mirror of
https://github.com/gethinode/hinode.git
synced 2025-10-10 19:43:11 +00:00
Compare commits
18 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
9fba521bc5 | ||
![]() |
60a34aac97 | ||
![]() |
15daf8c090 | ||
![]() |
7e4459ca8d | ||
![]() |
5ef2aad372 | ||
![]() |
4c6f4a9da9 | ||
![]() |
fd7f3692dd | ||
![]() |
f48b462c51 | ||
![]() |
287bc7700c | ||
![]() |
ee5e2745e2 | ||
![]() |
31fb07e180 | ||
![]() |
aaf8513688 | ||
![]() |
acd2812218 | ||
![]() |
665357e538 | ||
![]() |
f678352b78 | ||
![]() |
17b39caef7 | ||
![]() |
38ab9f2e43 | ||
![]() |
aa4da56910 |
3
assets/js/video.js
Normal file
3
assets/js/video.js
Normal file
@@ -0,0 +1,3 @@
|
||||
document.querySelectorAll('[data-video-padding]').forEach(element => {
|
||||
element.style.paddingBottom = element.getAttribute('data-video-padding')
|
||||
})
|
@@ -5,11 +5,21 @@
|
||||
background-color: var(--#{$prefix}secondary-bg);
|
||||
}
|
||||
|
||||
.card-img-wrap {
|
||||
.card .card-img-wrap {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.card .card-img-wrap:has(.card-img-top) {
|
||||
border-top-left-radius: var(--#{$prefix}card-inner-border-radius);
|
||||
border-top-right-radius: var(--#{$prefix}card-inner-border-radius);
|
||||
}
|
||||
|
||||
.card .card-img-wrap:has(.card-img-bottom) {
|
||||
border-bottom-right-radius: var(--#{$prefix}card-inner-border-radius);
|
||||
border-bottom-left-radius: var(--#{$prefix}card-inner-border-radius);
|
||||
}
|
||||
|
||||
.card-zoom {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
@@ -1,11 +1,11 @@
|
||||
.youtube-embedded {
|
||||
.video-embedded {
|
||||
position: relative;
|
||||
padding-bottom: 56.25%;
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.youtube-embedded > iframe {
|
||||
.video-embedded > iframe {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
@@ -27,6 +27,18 @@
|
||||
host = "imgix"
|
||||
# toml-docs-end images
|
||||
|
||||
# toml-docs-start videos
|
||||
[videos]
|
||||
[videos.cloudinary]
|
||||
host = "cloudinary"
|
||||
account = "demo"
|
||||
[videos.vimeo]
|
||||
host = "vimeo"
|
||||
[videos.youtube]
|
||||
host = "youtube"
|
||||
# toml-docs-end videos
|
||||
|
||||
|
||||
# toml-docs-start debugging
|
||||
[debugging]
|
||||
showJS = false
|
||||
|
@@ -14,7 +14,7 @@ for = '/**'
|
||||
connect-src 'self'
|
||||
https://*.google-analytics.com https://*.analytics.google.com https://*.googletagmanager.com; \
|
||||
font-src 'self' https://fonts.gstatic.com; \
|
||||
frame-src 'self' https://www.youtube-nocookie.com https://www.youtube.com; \
|
||||
frame-src 'self' https://player.cloudinary.com https://player.vimeo.com https://www.youtube-nocookie.com https://www.youtube.com; \
|
||||
img-src 'self' data: https://*.imgix.net https://*.imagekit.io https://*.cloudinary.com https://i.vimeocdn.com https://i.ytimg.com https://*.google-analytics.com https://*.googletagmanager.com https://tile.openstreetmap.org; \
|
||||
manifest-src 'self'; \
|
||||
media-src 'self' \
|
||||
@@ -29,7 +29,6 @@ for = '/**'
|
||||
camera=(), \
|
||||
magnetometer=(), \
|
||||
gyroscope=(), \
|
||||
fullscreen=(), \
|
||||
payment=() \
|
||||
"""
|
||||
cache-control = """\
|
||||
|
95
data/structures/video.yml
Normal file
95
data/structures/video.yml
Normal file
@@ -0,0 +1,95 @@
|
||||
comment: >-
|
||||
Embeds a responsive video player for supported video providers. The video is
|
||||
embedded in a responsive frame.
|
||||
arguments:
|
||||
page:
|
||||
type:
|
||||
- '*hugolib.pageState'
|
||||
- '*hugolib.pageForShortcode'
|
||||
optional: false
|
||||
group: partial
|
||||
release: v0.26.5
|
||||
comment: Context of the current page.
|
||||
position:
|
||||
type:
|
||||
- 'text.Position'
|
||||
optional: true
|
||||
group: partial
|
||||
release: v0.26.5
|
||||
comment: Filename and position from which the shortcode was called.
|
||||
host:
|
||||
type: string
|
||||
optional: true
|
||||
default: youtube
|
||||
release: v0.26.5
|
||||
comment: >-
|
||||
Host name of the video provider. It should match one of the registered
|
||||
providers in the site's parameters under `videos`.
|
||||
title:
|
||||
type: string
|
||||
optional: true
|
||||
comment: >-
|
||||
Title of the video.
|
||||
class:
|
||||
type: string
|
||||
optional: true
|
||||
position: 1
|
||||
comment: >-
|
||||
Class attribute of the video wrapper element.
|
||||
id:
|
||||
type: string
|
||||
optional: false
|
||||
position: 0
|
||||
comment: Public identifier of the video to be embedded.
|
||||
account:
|
||||
type: string
|
||||
optional: true
|
||||
comment: >-
|
||||
Account name of the video asset, required by some digital asset managers.
|
||||
You can also set the default account name in the site's parameters. For
|
||||
example, the following configuration sets the default account name for
|
||||
videos hosted by Cloudinary:
|
||||
```toml
|
||||
[videos.cloudinary]
|
||||
account = "demo"
|
||||
```
|
||||
release: v0.26.5
|
||||
autoplay:
|
||||
type: bool
|
||||
optional: true
|
||||
default: false
|
||||
comment: >-
|
||||
Flag indicating the video should start playing immediately when loaded, if
|
||||
supported by the browser. The audio will be muted.
|
||||
autotitle:
|
||||
type: bool
|
||||
optional: true
|
||||
default: false
|
||||
release: v0.25.2
|
||||
comment: >-
|
||||
Trigger to retrieve the title from the video metadata, if supported by the
|
||||
provider.
|
||||
ratio:
|
||||
type: select
|
||||
optional: true
|
||||
comment: >-
|
||||
Ratio of the video. If set, determines the padding of the embedded video
|
||||
frame. When not specified, the video dimensions used to calculate the
|
||||
padding are retrieved programmatically.
|
||||
options:
|
||||
values:
|
||||
- 1x1
|
||||
- 3x2
|
||||
- 4x3
|
||||
- 16x9
|
||||
- 21x9
|
||||
release: v0.26.5
|
||||
portrait:
|
||||
type: bool
|
||||
optional: true
|
||||
default: false
|
||||
comment: >-
|
||||
Flag to adjust the ratio from landscape to portrait. The image itself is
|
||||
not rotated, only the crop area is adjusted. Not applicable to vector
|
||||
graphics.
|
||||
release: v0.26.5
|
@@ -1,35 +0,0 @@
|
||||
comment: >-
|
||||
Embeds a responsive video player for YouTube videos. Only the ID of the video
|
||||
is required. In privacy-enhanced mode, YouTube will not store information
|
||||
about visitors on your website unless the user plays the embedded video.
|
||||
arguments:
|
||||
title:
|
||||
type: string
|
||||
optional: true
|
||||
comment: >-
|
||||
Title of the video.
|
||||
class:
|
||||
type: string
|
||||
optional: true
|
||||
position: 1
|
||||
comment: >-
|
||||
Class attribute of the video wrapper element.
|
||||
id:
|
||||
type: string
|
||||
optional: false
|
||||
position: 0
|
||||
comment: Identifier of the video to be embedded.
|
||||
autoplay:
|
||||
type: bool
|
||||
optional: true
|
||||
default: false
|
||||
comment: >-
|
||||
Flag indicating the video should start playing immediately when loaded, if
|
||||
supported by the browser. The audio will be muted.
|
||||
autotitle:
|
||||
type: bool
|
||||
optional: true
|
||||
default: false
|
||||
release: v0.25.2
|
||||
comment: >-
|
||||
Trigger to retrieve the title from the video metadata.
|
@@ -14,7 +14,7 @@ for = '/**'
|
||||
connect-src 'self'
|
||||
https://*.google-analytics.com https://*.analytics.google.com https://*.googletagmanager.com; \
|
||||
font-src 'self' https://fonts.gstatic.com; \
|
||||
frame-src 'self' https://www.youtube-nocookie.com https://www.youtube.com; \
|
||||
frame-src 'self' https://player.cloudinary.com https://player.vimeo.com https://www.youtube-nocookie.com https://www.youtube.com; \
|
||||
img-src 'self' data: https://*.imgix.net https://*.imagekit.io https://*.cloudinary.com https://i.vimeocdn.com https://i.ytimg.com https://*.google-analytics.com https://*.googletagmanager.com https://tile.openstreetmap.org; \
|
||||
manifest-src 'self'; \
|
||||
media-src 'self' \
|
||||
@@ -29,7 +29,6 @@ for = '/**'
|
||||
camera=(), \
|
||||
magnetometer=(), \
|
||||
gyroscope=(), \
|
||||
fullscreen=(), \
|
||||
payment=() \
|
||||
"""
|
||||
cache-control = """\
|
||||
|
@@ -474,6 +474,26 @@ As an example, the following shortcode displays a tooltip for a colored hyperlin
|
||||
{{< /example >}}
|
||||
<!-- markdownlint-enable MD037 -->
|
||||
|
||||
## Video
|
||||
|
||||
As an example, the following shortcode displays an Elephants video hosted by Cloudinary.
|
||||
|
||||
<!-- markdownlint-disable MD037 -->
|
||||
{{< example lang="hugo" >}}
|
||||
{{</* video host="cloudinary" account="demo" id="elephants" autoplay=true */>}}
|
||||
{{< /example >}}
|
||||
<!-- markdownlint-enable MD037 -->
|
||||
|
||||
## Vimeo
|
||||
|
||||
As an example, the following shortcode displays a Vimeo video.
|
||||
|
||||
<!-- markdownlint-disable MD037 -->
|
||||
{{< example lang="hugo" >}}
|
||||
{{</* vimeo id="55073825" autoplay=true autotitle=true */>}}
|
||||
{{< /example >}}
|
||||
<!-- markdownlint-enable MD037 -->
|
||||
|
||||
## Youtube
|
||||
|
||||
As an example, the following shortcode displays a Hugo quickstart guide.
|
||||
|
@@ -237,6 +237,7 @@
|
||||
"fade",
|
||||
"fas",
|
||||
"figure-caption",
|
||||
"fixed-top",
|
||||
"flex-column",
|
||||
"flex-fill",
|
||||
"flex-grow-1",
|
||||
@@ -311,6 +312,7 @@
|
||||
"mt-4",
|
||||
"mt-5",
|
||||
"mt-auto",
|
||||
"mt-md-0",
|
||||
"multi-docs-collapse-15",
|
||||
"multi-file-collapse-1",
|
||||
"mx-auto",
|
||||
@@ -332,10 +334,10 @@
|
||||
"navbar-container",
|
||||
"navbar-contrast",
|
||||
"navbar-expand-md",
|
||||
"navbar-fixed-top",
|
||||
"navbar-mode-selector",
|
||||
"navbar-nav",
|
||||
"navbar-nav-scroll",
|
||||
"navbar-overlay",
|
||||
"navbar-title",
|
||||
"navbar-toggler",
|
||||
"next",
|
||||
@@ -471,11 +473,11 @@
|
||||
"top-bar",
|
||||
"translate-middle",
|
||||
"translate-middle-y",
|
||||
"video-embedded",
|
||||
"visually-hidden",
|
||||
"vr",
|
||||
"w-100",
|
||||
"w-50",
|
||||
"youtube-embedded"
|
||||
"w-50"
|
||||
],
|
||||
"ids": [
|
||||
"TableOfContents",
|
||||
@@ -607,6 +609,8 @@
|
||||
"toast-message-email-4",
|
||||
"toc-collapse",
|
||||
"tooltip",
|
||||
"video",
|
||||
"vimeo",
|
||||
"youtube"
|
||||
]
|
||||
}
|
||||
|
@@ -16,6 +16,7 @@
|
||||
"link",
|
||||
"meta",
|
||||
"nav",
|
||||
"noscript",
|
||||
"ol",
|
||||
"p",
|
||||
"path",
|
||||
@@ -38,6 +39,7 @@
|
||||
"bg-body",
|
||||
"bg-opacity-10",
|
||||
"bg-primary",
|
||||
"border-0",
|
||||
"bottom-0",
|
||||
"bottom-bar",
|
||||
"breadcrumb",
|
||||
@@ -45,10 +47,19 @@
|
||||
"btn",
|
||||
"btn-close",
|
||||
"btn-primary",
|
||||
"btn-social",
|
||||
"card",
|
||||
"card-body",
|
||||
"card-body-link",
|
||||
"card-text",
|
||||
"card-title",
|
||||
"card-zoom",
|
||||
"checkbox",
|
||||
"col",
|
||||
"col-12",
|
||||
"col-6",
|
||||
"col-lg-2",
|
||||
"col-lg-8",
|
||||
"col-md-2",
|
||||
"col-md-3",
|
||||
"col-md-4",
|
||||
@@ -61,7 +72,9 @@
|
||||
"container-xxl",
|
||||
"d-flex",
|
||||
"d-inline",
|
||||
"d-lg-block",
|
||||
"d-md-block",
|
||||
"d-md-none",
|
||||
"d-none",
|
||||
"display-1",
|
||||
"display-4",
|
||||
@@ -73,12 +86,17 @@
|
||||
"fa-book-open",
|
||||
"fa-ellipsis",
|
||||
"fa-face-frown",
|
||||
"fa-facebook",
|
||||
"fa-fw",
|
||||
"fa-github",
|
||||
"fa-link",
|
||||
"fa-linkedin",
|
||||
"fa-medium",
|
||||
"fa-moon",
|
||||
"fa-share-nodes",
|
||||
"fa-sun",
|
||||
"fa-whatsapp",
|
||||
"fa-x-twitter",
|
||||
"fab",
|
||||
"fas",
|
||||
"fixed-top",
|
||||
@@ -88,8 +106,13 @@
|
||||
"form-control",
|
||||
"fs-3",
|
||||
"fs-5",
|
||||
"fs-6",
|
||||
"fs-lg-5",
|
||||
"fw-30",
|
||||
"fw-bold",
|
||||
"g-4",
|
||||
"gap-1",
|
||||
"h-100",
|
||||
"hstack",
|
||||
"img-fluid",
|
||||
"img-wrap",
|
||||
@@ -99,10 +122,14 @@
|
||||
"justify-content-end",
|
||||
"justify-content-start",
|
||||
"label",
|
||||
"lead",
|
||||
"link-bg-footer",
|
||||
"link-secondary",
|
||||
"main-content",
|
||||
"main-nav-toggler",
|
||||
"mb-3",
|
||||
"mb-5",
|
||||
"mb-lg-5",
|
||||
"me-auto",
|
||||
"middle-bar",
|
||||
"min-vh-100",
|
||||
@@ -114,6 +141,7 @@
|
||||
"mx-auto",
|
||||
"mx-md-0",
|
||||
"my-auto",
|
||||
"my-md-0",
|
||||
"my-md-auto",
|
||||
"nav-item",
|
||||
"nav-link",
|
||||
@@ -136,6 +164,7 @@
|
||||
"p-3",
|
||||
"p-4",
|
||||
"pb-4",
|
||||
"pb-5",
|
||||
"pb-md-0",
|
||||
"position-fixed",
|
||||
"position-relative",
|
||||
@@ -150,40 +179,59 @@
|
||||
"row",
|
||||
"row-cols-1",
|
||||
"row-cols-2",
|
||||
"row-cols-lg-3",
|
||||
"row-cols-md-2",
|
||||
"row-cols-md-3",
|
||||
"row-cols-sm-2",
|
||||
"row-cols-sm-3",
|
||||
"search",
|
||||
"search-input",
|
||||
"search-suggestions",
|
||||
"shadow",
|
||||
"sidebar-overflow",
|
||||
"sticky-top",
|
||||
"stretched-link",
|
||||
"svg-inline--fa",
|
||||
"text-body-secondary",
|
||||
"text-center",
|
||||
"text-decoration-none",
|
||||
"text-end",
|
||||
"text-muted",
|
||||
"text-secondary",
|
||||
"text-sm-start",
|
||||
"text-start",
|
||||
"text-uppercase",
|
||||
"toast",
|
||||
"toast-body",
|
||||
"toast-container",
|
||||
"toast-header",
|
||||
"toc",
|
||||
"toc-sidebar",
|
||||
"toggler-icon",
|
||||
"top-bar"
|
||||
],
|
||||
"ids": [
|
||||
"blogs",
|
||||
"btn-webshare",
|
||||
"fa-face-frown",
|
||||
"fab-facebook",
|
||||
"fab-github",
|
||||
"fab-linkedin",
|
||||
"fab-medium",
|
||||
"fab-whatsapp",
|
||||
"fab-x-twitter",
|
||||
"fas-book-open",
|
||||
"fas-ellipsis",
|
||||
"fas-link",
|
||||
"fas-moon",
|
||||
"fas-share-nodes",
|
||||
"fas-sun",
|
||||
"navbar-0-collapse",
|
||||
"navbar-mode",
|
||||
"navbar-mode-checkbox",
|
||||
"toast-container",
|
||||
"toast-copied-code-message"
|
||||
"toast-copied-code-message",
|
||||
"toast-message-email-4"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@@ -222,7 +222,9 @@
|
||||
|
||||
<div class="navbar-collapse collapse" id="{{ $id }}-collapse">
|
||||
<!-- Insert search input -->
|
||||
{{- if and $search (not $searchModal) }}{{ partial "assets/search-input.html" }}{{ end -}}
|
||||
{{- if and $search (not $searchModal) }}
|
||||
{{ partial "assets/search-input.html" (dict "class" (printf "mt-4 mt-%s-0" $size)) }}
|
||||
{{ end -}}
|
||||
|
||||
<!-- Render top-menu items (maximum depth of 2) -->
|
||||
<ul class="navbar-nav {{ if $flex }}d-flex w-100{{ else }}ms-auto{{ end }}">
|
||||
|
146
layouts/partials/assets/video.html
Normal file
146
layouts/partials/assets/video.html
Normal file
@@ -0,0 +1,146 @@
|
||||
<!--
|
||||
Copyright © 2024 The Hinode Team / Mark Dumay. All rights reserved.
|
||||
Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file.
|
||||
Visit gethinode.com/license for more details.
|
||||
|
||||
This source code adapts the original embedded shortcode as maintained by the Hugo repository. It introduces the
|
||||
following modifications:
|
||||
- Isolated the styles to comply with the Content Security Policy
|
||||
- Added validation of shortcode arguments
|
||||
- Added support to retrieve the title from the video metadata
|
||||
- Adjusted autoplay configuration
|
||||
- Modified the layout
|
||||
|
||||
The original source code is available on:
|
||||
https://github.com/gohugoio/hugo/tpl/tplimpl/embedded/templates/shortcodes/youtube.html
|
||||
https://github.com/gohugoio/hugo/tpl/tplimpl/embedded/templates/shortcodes/vimeo.html
|
||||
Copyright 2022 The Hugo Authors. Licensed under the Apache License, Version 2.0.
|
||||
-->
|
||||
|
||||
{{ $error := false }}
|
||||
|
||||
<!-- Validate arguments -->
|
||||
{{ if partial "utilities/IsInvalidArgs.html" (dict "structure" "video" "args" . "group" "partial") }}
|
||||
{{- errorf "partial [assets/video.html] - Invalid arguments" -}}
|
||||
{{ $error = true }}
|
||||
{{ end }}
|
||||
|
||||
<!-- Initialize arguments -->
|
||||
{{- $page := .page -}}
|
||||
{{- $position := .position -}}
|
||||
{{- $host := .host -}}
|
||||
{{- $title := .title -}}
|
||||
{{- $class := .class -}}
|
||||
{{- $account := .account -}}
|
||||
{{- $id := .id -}}
|
||||
{{- $autoplay := .autoplay -}}
|
||||
{{- $autotitle := .autotitle -}}
|
||||
{{- $ratio := .ratio -}}
|
||||
{{- $pc := "" -}}
|
||||
{{- if eq $host "youtube" }}
|
||||
{{- $pc = $page.Site.Config.Privacy.YouTube -}}
|
||||
{{- else if eq $host "vimeo" }}
|
||||
{{- $pc = $page.Site.Config.Privacy.Vimeo -}}
|
||||
{{- end -}}
|
||||
|
||||
{{ if and (eq $host "youtube") ($pc.Disable) }}
|
||||
{{- errorf "partial [assets/video.html] - YouTube video disabled in site's privacy settings" -}}
|
||||
{{ $error = true }}
|
||||
{{ else if and (eq $host "vimeo") ($pc.Disable) }}
|
||||
{{- errorf "partial [assets/video.html] - Vimeo video disabled in site's privacy settings" -}}
|
||||
{{ $error = true }}
|
||||
{{ end }}
|
||||
|
||||
{{ if not $account }}
|
||||
{{ with index $page.Site.Params.videos $host }}
|
||||
{{ with index . "account" }}{{ $account = . }}{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
<!-- Main code -->
|
||||
{{ if not $error -}}
|
||||
{{ if eq $host "youtube" }}
|
||||
{{- $host := cond $pc.PrivacyEnhanced "www.youtube-nocookie.com" "www.youtube.com" -}}
|
||||
{{ $url := printf "https://%s/embed/%s?origin=%s" $host $id $page.Site.BaseURL }}
|
||||
{{ $api := printf "https://www.youtube.com/oembed?format=json&url=%s" (printf "https://www.youtube.com/watch?v=%s" $id) }}
|
||||
{{ $padding := "56.25%" }}
|
||||
|
||||
{{ with resources.GetRemote $api }}
|
||||
{{ with .Err }}
|
||||
{{ errorf "Unable to parse video metadata '%q': %s\n %s" $api $position . }}
|
||||
{{ else }}
|
||||
{{ $data := . | transform.Unmarshal }}
|
||||
{{ if $autotitle }}{{ with $data.title }}{{ $title = . }}{{ end }}{{ end }}
|
||||
{{ $padding = printf "%.2f%%" (mul (div $data.height $data.width) 100) }}
|
||||
{{ end }}
|
||||
{{ else }}
|
||||
{{ errorf "Unable to get video metadata '%q': %s" $api $position }}
|
||||
{{ end }}
|
||||
|
||||
<div class="video-embedded {{ $class }}" data-video-padding="{{ $padding }}">
|
||||
<iframe src="{{ $url }}{{ if $autoplay }}&autoplay=1&mute=1{{ end }}"
|
||||
allowfullscreen title="{{ $title }}" {{ if $autoplay }}allow="autoplay"{{ end }}>
|
||||
</iframe>
|
||||
</div>
|
||||
{{ else if eq $host "vimeo" }}
|
||||
{{ $url := printf "https://player.vimeo.com/video/%s" $id }}
|
||||
{{ $params := "" }}
|
||||
{{ if $autoplay }}{{ $params = print $params "&autoplay=1&muted=1" }}{{ end }}
|
||||
{{ if $pc.EnableDNT }}{{ $params = print $params "&dnt=1" }}{{ end }}
|
||||
{{ $params = strings.TrimPrefix "&" $params }}
|
||||
{{ with $params }}{{ $url = printf "%s?%s" $url . }}{{ end }}
|
||||
{{ $padding := "56.25%" }}
|
||||
|
||||
{{- $dnt := cond $pc.EnableDNT 1 0 -}}
|
||||
{{- $source := urls.JoinPath "https://vimeo.com" $id -}}
|
||||
{{- $query := querify "url" $url "dnt" $dnt -}}
|
||||
{{- $api := printf "https://vimeo.com/api/oembed.json?%s" $query -}}
|
||||
{{- with resources.GetRemote $api -}}
|
||||
{{ with .Err }}
|
||||
{{ errorf "Unable to parse video metadata '%q': %s\n %s" $api $position . }}
|
||||
{{ else }}
|
||||
{{ $data := . | transform.Unmarshal }}
|
||||
{{ if $autotitle }}{{ with $data.title }}{{ $title = . }}{{ end }}{{ end }}
|
||||
{{ $padding = printf "%.2f%%" (mul (div $data.height $data.width) 100) }}
|
||||
{{ end }}
|
||||
{{- end -}}
|
||||
|
||||
<div class="video-embedded {{ $class }}" data-video-padding="{{ $padding }}">
|
||||
<iframe src="{{ $url | safeHTMLAttr }}" title="{{ $title }}" webkitallowfullscreen mozallowfullscreen allowfullscreen>
|
||||
</iframe>
|
||||
</div>
|
||||
{{ else if eq $host "cloudinary" }}
|
||||
{{ if not $account }}
|
||||
{{ errorf "Missing account name for Cloudinary video '%s': %s" $id $position }}
|
||||
{{ end }}
|
||||
|
||||
{{ $url := printf "https://player.cloudinary.com/embed/?cloud_name=%s&public_id=%s" $account $id }}
|
||||
{{ $params := "&controls=true" }}
|
||||
{{ if $autoplay }}{{ $params = print $params "&autoplay=true&muted=true" }}{{ end }}
|
||||
{{ with $params }}{{ $url = print $url . }}{{ end }}
|
||||
{{ $padding := "56.25%" }}
|
||||
|
||||
{{ $thumbnail := urls.JoinPath (path.Dir $id) (printf "%s.jpg" (path.BaseName $id)) }}
|
||||
{{ $metadata := partial "assets/helpers/image-dimension.html" (dict
|
||||
"page" $page
|
||||
"url" (printf "https://res.cloudinary.com/%s/video/upload/%s" $account $thumbnail)
|
||||
"ratio" $ratio
|
||||
"imageset" false
|
||||
) }}
|
||||
{{ $height := index $metadata "height" }}
|
||||
{{ $width := index $metadata "width" }}
|
||||
{{ if and $height $width }}
|
||||
{{ $padding := printf "%.2f%%" (mul (div (float $height) $width) 100) }}
|
||||
{{ if not $title }}{{ $title = printf "Cloudinary video '%s'" (path.BaseName $id) }}{{ end }}
|
||||
|
||||
<div class="video-embedded {{ $class }}" data-video-padding="{{ $padding }}">
|
||||
<iframe src="{{ $url | safeHTMLAttr }}" title="{{ $title }}" webkitallowfullscreen mozallowfullscreen allowfullscreen>
|
||||
</iframe>
|
||||
</div>
|
||||
{{ else }}
|
||||
{{ errorf "Cannot retrieve metadata of Cloudinary video '%s' with account '%s': %s" $id $account $position }}
|
||||
{{ end }}
|
||||
{{ else }}
|
||||
{{ warnf "partial [assets/video.html] - Unsupported video provider: %s" $host }}
|
||||
{{ end }}
|
||||
{{ end -}}
|
50
layouts/shortcodes/video.html
Normal file
50
layouts/shortcodes/video.html
Normal file
@@ -0,0 +1,50 @@
|
||||
<!--
|
||||
Copyright © 2024 The Hinode Team / Mark Dumay. All rights reserved.
|
||||
Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file.
|
||||
Visit gethinode.com/license for more details.
|
||||
-->
|
||||
|
||||
{{ $error := false }}
|
||||
|
||||
<!-- Validate arguments -->
|
||||
{{ if partial "utilities/IsInvalidArgs.html" (dict "structure" "video" "args" .Params "group" "shortcode") }}
|
||||
{{ errorf "Invalid arguments: %s" .Position -}}
|
||||
{{ $error = true }}
|
||||
{{ end }}
|
||||
|
||||
<!-- Initialize arguments -->
|
||||
{{- $host := "youtube" -}}
|
||||
{{- $account := "" -}}
|
||||
{{- $id := "" -}}
|
||||
{{- $class := "" -}}
|
||||
{{- $title := "" }}
|
||||
{{- $autoplay := false }}
|
||||
{{- $autotitle := false }}
|
||||
|
||||
{{- if .IsNamedParams }}
|
||||
{{ with .Get "host" }}{{ $host = . }}{{ end }}
|
||||
{{ with .Get "account" }}{{ $account = . }}{{ end }}
|
||||
{{ with .Get "id" }}{{ $id = . }}{{ end }}
|
||||
{{ with .Get "class" }}{{ $class = . }}{{ end }}
|
||||
{{ with .Get "title" }}{{ $title = . }}{{ end }}
|
||||
{{ if isset .Params "autoplay" }}{{ $autoplay = partial "utilities/CastBool.html" (.Get "autoplay") }}{{ end -}}
|
||||
{{ if isset .Params "autotitle" }}{{ $autotitle = partial "utilities/CastBool.html" (.Get "autotitle") }}{{ end -}}
|
||||
{{ else }}
|
||||
{{- $id = .Get 0 -}}
|
||||
{{- $class = .Get 1 -}}
|
||||
{{ end }}
|
||||
|
||||
<!-- Main code -->
|
||||
{{ if not $error -}}
|
||||
{{ partial "assets/video.html" (dict
|
||||
"page" .Page
|
||||
"position" .Position
|
||||
"account" $account
|
||||
"host" $host
|
||||
"id" $id
|
||||
"class" $class
|
||||
"title" $title
|
||||
"autoplay" $autoplay
|
||||
"autotitle" $autotitle
|
||||
) }}
|
||||
{{ end -}}
|
46
layouts/shortcodes/vimeo.html
Normal file
46
layouts/shortcodes/vimeo.html
Normal file
@@ -0,0 +1,46 @@
|
||||
<!--
|
||||
Copyright © 2024 The Hinode Team / Mark Dumay. All rights reserved.
|
||||
Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file.
|
||||
Visit gethinode.com/license for more details.
|
||||
-->
|
||||
|
||||
{{ $error := false }}
|
||||
|
||||
<!-- Validate arguments -->
|
||||
{{ if partial "utilities/IsInvalidArgs.html" (dict "structure" "video" "args" .Params "group" "shortcode") }}
|
||||
{{ errorf "Invalid arguments: %s" .Position -}}
|
||||
{{ $error = true }}
|
||||
{{ end }}
|
||||
|
||||
<!-- Initialize arguments -->
|
||||
{{- $host := "vimeo" -}}
|
||||
{{- $id := "" -}}
|
||||
{{- $class := "" -}}
|
||||
{{- $title := "Vimeo Video" }}
|
||||
{{- $autoplay := false }}
|
||||
{{- $autotitle := false }}
|
||||
|
||||
{{- if .IsNamedParams }}
|
||||
{{ with .Get "id" }}{{ $id = . }}{{ end }}
|
||||
{{ with .Get "class" }}{{ $class = . }}{{ end }}
|
||||
{{ with .Get "title" }}{{ $title = . }}{{ end }}
|
||||
{{ if isset .Params "autoplay" }}{{ $autoplay = partial "utilities/CastBool.html" (.Get "autoplay") }}{{ end -}}
|
||||
{{ if isset .Params "autotitle" }}{{ $autotitle = partial "utilities/CastBool.html" (.Get "autotitle") }}{{ end -}}
|
||||
{{ else }}
|
||||
{{- $id = .Get 0 -}}
|
||||
{{- $class = .Get 1 -}}
|
||||
{{ end }}
|
||||
|
||||
<!-- Main code -->
|
||||
{{ if not $error -}}
|
||||
{{ partial "assets/video.html" (dict
|
||||
"page" .Page
|
||||
"position" .Position
|
||||
"host" $host
|
||||
"id" $id
|
||||
"class" $class
|
||||
"title" $title
|
||||
"autoplay" $autoplay
|
||||
"autotitle" $autotitle
|
||||
) }}
|
||||
{{ end -}}
|
@@ -2,69 +2,45 @@
|
||||
Copyright © 2024 The Hinode Team / Mark Dumay. All rights reserved.
|
||||
Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file.
|
||||
Visit gethinode.com/license for more details.
|
||||
|
||||
This source code adapts the original embedded shortcode as maintained by the Hugo repository. It introduces the
|
||||
following modifications:
|
||||
- Isolated the styles to comply with the Content Security Policy
|
||||
- Added validation of shortcode arguments
|
||||
- Added support to retrieve the title from the video metadata
|
||||
- Adjusted autoplay configuration
|
||||
- Modified the layout
|
||||
|
||||
The original source code is available on:
|
||||
https://github.com/gohugoio/hugo/tpl/tplimpl/embedded/templates/shortcodes/youtube.html
|
||||
Copyright 2022 The Hugo Authors. Licensed under the Apache License, Version 2.0.
|
||||
-->
|
||||
|
||||
{{- $pc := .Page.Site.Config.Privacy.YouTube -}}
|
||||
{{- if not $pc.Disable -}}
|
||||
{{ $error := false }}
|
||||
{{ $error := false }}
|
||||
|
||||
<!-- Validate arguments -->
|
||||
{{ if partial "utilities/IsInvalidArgs.html" (dict "structure" "youtube" "args" .Params) }}
|
||||
<!-- Validate arguments -->
|
||||
{{ if partial "utilities/IsInvalidArgs.html" (dict "structure" "video" "args" .Params "group" "shortcode") }}
|
||||
{{ errorf "Invalid arguments: %s" .Position -}}
|
||||
{{ $error = true }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
<!-- Initialize arguments -->
|
||||
{{- $id := "" -}}
|
||||
{{- $class := "" -}}
|
||||
{{- $title := "YouTube Video" }}
|
||||
{{- $autoplay := false }}
|
||||
{{- $autotitle := false }}
|
||||
{{- $host := cond $pc.PrivacyEnhanced "www.youtube-nocookie.com" "www.youtube.com" -}}
|
||||
<!-- Initialize arguments -->
|
||||
{{- $host := "youtube" -}}
|
||||
{{- $id := "" -}}
|
||||
{{- $class := "" -}}
|
||||
{{- $title := "YouTube Video" }}
|
||||
{{- $autoplay := false }}
|
||||
{{- $autotitle := false }}
|
||||
|
||||
{{- if .IsNamedParams }}
|
||||
{{- if .IsNamedParams }}
|
||||
{{ with .Get "id" }}{{ $id = . }}{{ end }}
|
||||
{{ with .Get "class" }}{{ $class = . }}{{ end }}
|
||||
{{ with .Get "title" }}{{ $title = . }}{{ end }}
|
||||
{{ if isset .Params "autoplay" }}{{ $autoplay = partial "utilities/CastBool.html" (.Get "autoplay") }}{{ end -}}
|
||||
{{ if isset .Params "autotitle" }}{{ $autotitle = partial "utilities/CastBool.html" (.Get "autotitle") }}{{ end -}}
|
||||
{{ else }}
|
||||
{{ else }}
|
||||
{{- $id = .Get 0 -}}
|
||||
{{- $class = .Get 1 -}}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{ $url := printf "https://%s/embed/%s?origin=%s" $host $id .Site.BaseURL }}
|
||||
{{ $api := printf "https://www.youtube.com/oembed?format=json&url=%s" (printf "https://www.youtube.com/watch?v=%s" $id) }}
|
||||
|
||||
{{ if $autotitle }}
|
||||
{{ with resources.GetRemote $api }}
|
||||
{{ with .Err }}
|
||||
{{ errorf "Unable to parse video metadata '%q': %s\n %s" $api .Position . }}
|
||||
{{ else }}
|
||||
{{ $data := . | transform.Unmarshal }}
|
||||
{{ with $data.title }}{{ $title = . }}{{ end }}
|
||||
{{ end }}
|
||||
{{ else }}
|
||||
{{ errorf "Unable to get video metadata '%q': %s" $api .Position }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
<!-- Main code -->
|
||||
<div class="youtube-embedded {{ $class }}">
|
||||
<iframe src="{{ $url }}{{ if $autoplay }}&autoplay=1&mute=1{{ end }}"
|
||||
allowfullscreen title="{{ $title }}" {{ if $autoplay }}allow="autoplay"{{ end }}>
|
||||
</iframe>
|
||||
</div>
|
||||
<!-- Main code -->
|
||||
{{ if not $error -}}
|
||||
{{ partial "assets/video.html" (dict
|
||||
"page" .Page
|
||||
"position" .Position
|
||||
"host" $host
|
||||
"id" $id
|
||||
"class" $class
|
||||
"title" $title
|
||||
"autoplay" $autoplay
|
||||
"autotitle" $autotitle
|
||||
) }}
|
||||
{{ end -}}
|
@@ -31,7 +31,7 @@
|
||||
connect-src 'self'
|
||||
https://*.google-analytics.com https://*.analytics.google.com https://*.googletagmanager.com; \
|
||||
font-src 'self' https://*.netlify.app https://fonts.gstatic.com; \
|
||||
frame-src 'self' https://www.youtube-nocookie.com https://www.youtube.com \
|
||||
frame-src 'self' https://player.cloudinary.com https://player.vimeo.com https://www.youtube-nocookie.com https://www.youtube.com \
|
||||
app.netlify.com; \
|
||||
img-src 'self' data: https://*.imgix.net https://*.imagekit.io https://*.cloudinary.com https://*.netlify.app https://i.vimeocdn.com https://i.ytimg.com https://*.google-analytics.com https://*.googletagmanager.com https://tile.openstreetmap.org; \
|
||||
manifest-src 'self'; \
|
||||
@@ -47,7 +47,6 @@
|
||||
camera=(), \
|
||||
magnetometer=(), \
|
||||
gyroscope=(), \
|
||||
fullscreen=(), \
|
||||
payment=() \
|
||||
"""
|
||||
cache-control = """\
|
||||
|
12
package-lock.json
generated
12
package-lock.json
generated
@@ -1,19 +1,19 @@
|
||||
{
|
||||
"name": "@gethinode/hinode",
|
||||
"version": "0.26.4",
|
||||
"version": "0.26.5",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@gethinode/hinode",
|
||||
"version": "0.26.4",
|
||||
"version": "0.26.5",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@fullhuman/postcss-purgecss": "^6.0.0",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"cssnano": "^7.0.5",
|
||||
"cssnano-preset-advanced": "^7.0.5",
|
||||
"hugo-bin": "0.129.2",
|
||||
"hugo-bin": "0.130.0",
|
||||
"purgecss-whitelister": "^2.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -3313,9 +3313,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/hugo-bin": {
|
||||
"version": "0.129.2",
|
||||
"resolved": "https://registry.npmjs.org/hugo-bin/-/hugo-bin-0.129.2.tgz",
|
||||
"integrity": "sha512-OpfKbO8nkopEt8MBYPWQOgcL6IcotiskI+U1YRprAtw+ySUJHIDHfxMIcWeNmo66N/Reqm4RbDxFMDgKPUXGeQ==",
|
||||
"version": "0.130.0",
|
||||
"resolved": "https://registry.npmjs.org/hugo-bin/-/hugo-bin-0.130.0.tgz",
|
||||
"integrity": "sha512-Y6hqmIeGiRzUf3RgOLEsb+/FHCJ5Jn8EFL+AOzU7sRq/jt17iRVcs5ZoiN4EWzNL/5qvX5xV7712wA9FKnSPag==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@gethinode/hinode",
|
||||
"version": "0.26.4",
|
||||
"version": "0.26.5",
|
||||
"description": "Hinode is a clean documentation and blog theme for Hugo, an open-source static site generator",
|
||||
"keywords": [
|
||||
"hugo",
|
||||
@@ -71,7 +71,7 @@
|
||||
"autoprefixer": "^10.4.20",
|
||||
"cssnano": "^7.0.5",
|
||||
"cssnano-preset-advanced": "^7.0.5",
|
||||
"hugo-bin": "0.129.2",
|
||||
"hugo-bin": "0.130.0",
|
||||
"purgecss-whitelister": "^2.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
Reference in New Issue
Block a user