Skip to content

Add Embed Card Component and Update Cookies#3963

Merged
patrickpatrickpatrick merged 4 commits intomainfrom
design-system-day-yt
Aug 21, 2024
Merged

Add Embed Card Component and Update Cookies#3963
patrickpatrickpatrick merged 4 commits intomainfrom
design-system-day-yt

Conversation

@patrickpatrickpatrick
Copy link
Contributor

@patrickpatrickpatrick patrickpatrickpatrick commented Jul 29, 2024

NB: Content will come in a later PR. Felt that the work in PR should be separated as it was getting quite large.

What

  • Adds new Embed Card Component
  • Updates Cookie functionality
  • Adds relevant tests
  • New page as an example of functionality for review

Why

We want to add the ability to embed YouTube videos to the Design System website. This requires new preference cookies needing to be set because embeddable iframes from external sites can/do set cookies themselves.

Addresses #3931

@netlify
Copy link

netlify bot commented Jul 29, 2024

You can preview this change here:

Name Link
🔨 Latest commit 781b769
🔍 Latest deploy log https://app.netlify.com/sites/govuk-design-system-preview/deploys/66c5e18f1e8f0300087d5c64
😎 Deploy Preview https://deploy-preview-3963--govuk-design-system-preview.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

@patrickpatrickpatrick patrickpatrickpatrick changed the title design system day yt Add Embed Card Component Jul 31, 2024
@patrickpatrickpatrick patrickpatrickpatrick changed the title Add Embed Card Component Add Embed Card Component and Update Cookies Jul 31, 2024
@patrickpatrickpatrick patrickpatrickpatrick force-pushed the design-system-day-yt branch 2 times, most recently from d69467a to 3676f37 Compare July 31, 2024 10:31
@patrickpatrickpatrick patrickpatrickpatrick marked this pull request as ready for review July 31, 2024 10:39
@patrickpatrickpatrick patrickpatrickpatrick linked an issue Jul 31, 2024 that may be closed by this pull request
6 tasks
@patrickpatrickpatrick patrickpatrickpatrick marked this pull request as draft August 1, 2024 11:07
@patrickpatrickpatrick patrickpatrickpatrick force-pushed the design-system-day-yt branch 6 times, most recently from 797f9a8 to 32a9744 Compare August 5, 2024 14:06
@patrickpatrickpatrick patrickpatrickpatrick marked this pull request as ready for review August 5, 2024 15:05
@patrickpatrickpatrick
Copy link
Contributor Author

When it's approved, the page will be set to DRAFT.

@patrickpatrickpatrick patrickpatrickpatrick requested a review from a team August 7, 2024 10:46
Copy link
Contributor

@owenatgov owenatgov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple of comments. Overall looking good!


{% from "_cookie-banner.njk" import cookieBanner %}

<p class="govuk-!-font-size-24">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could use govuk-body-l here. Functionally they're the same but for neatness we should probably be using native styles rather than overrides where we can.

Suggested change
<p class="govuk-!-font-size-24">
<p class="govuk-body-l">

width: 100%;
height: 100%;
background:
url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3OSIgaGVpZ2h0PSI1NSIgdmlld0JveD0iMCAwIDc5IDU1IiBmaWxsPSJub25lIj4KPHBhdGggZD0iTTM5Ljc1MDMgMEg0MC4xODYxQzQ0LjIxMDQgMC4wMTQ2ODEgNjQuNjAxNiAwLjE2MTQ5MiA3MC4wOTk2IDEuNjM5MzhDNzEuNzYxNyAyLjA5MDQyIDczLjI3NjMgMi45Njk1OSA3NC40OTIgNC4xODkwMkM3NS43MDc2IDUuNDA4NDYgNzYuNTgxOCA2LjkyNTQ1IDc3LjAyNzIgOC41ODg0Qzc3LjUyMTcgMTAuNDQ4IDc3Ljg2OTMgMTIuOTA5NSA3OC4xMDQzIDE1LjQ0OTNMNzguMTUzMyAxNS45NTgzTDc4LjI2MSAxNy4yMzA2TDc4LjMwMDEgMTcuNzM5NkM3OC42MTg0IDIyLjIxMjQgNzguNjU3NSAyNi40MDE0IDc4LjY2MjQgMjcuMzE2NVYyNy42ODM1Qzc4LjY1NzUgMjguNjMyOSA3OC42MTM1IDMzLjEwNTcgNzguMjYxIDM3Ljc2NDVMNzguMjIxOCAzOC4yNzgzTDc4LjE3NzcgMzguNzg3M0M3Ny45MzI5IDQxLjU4NjQgNzcuNTcwNiA0NC4zNjYgNzcuMDI3MiA0Ni40MTE2Qzc2LjU4MzIgNDguMDc1MiA3NS43MDk0IDQ5LjU5MjkgNzQuNDkzNiA1MC44MTI2QzczLjI3NzcgNTIuMDMyMiA3MS43NjI0IDUyLjkxMDkgNzAuMDk5NiA1My4zNjA2QzY0LjQyMDQgNTQuODg3NCA0Mi44MzQ3IDU0Ljk5NTEgMzkuODQzNCA1NUgzOS4xNDgxQzM3LjYzNTMgNTUgMzEuMzc4NSA1NC45NzA2IDI0LjgxOCA1NC43NDU1TDIzLjk4NTggNTQuNzE2MkwyMy41NTk4IDU0LjY5NjZMMjIuNzIyNiA1NC42NjIzTDIxLjg4NTQgNTQuNjI4MUMxNi40NTExIDU0LjM4ODMgMTEuMjc2MiA1NC4wMDE3IDguODkxOSA1My4zNTU3QzcuMjI5NzIgNTIuOTA2NSA1LjcxNDgyIDUyLjAyODUgNC40OTg5OSA1MC44MDk3QzMuMjgzMTUgNDkuNTkxIDIuNDA5MDcgNDguMDc0MyAxLjk2NDMgNDYuNDExNkMxLjQyMDg2IDQ0LjM3MDkgMS4wNTg1NyA0MS41ODY0IDAuODEzNzc2IDM4Ljc4NzNMMC43NzQ2MDkgMzguMjczNEwwLjczNTQ0MyAzNy43NjQ1QzAuNDkzODIyIDM0LjQ0ODUgMC4zNTk5MzIgMzEuMTI1NiAwLjMzMzk4NCAyNy44MDFMMC4zMzM5ODQgMjcuMTk5QzAuMzQzNzc2IDI2LjE0NjkgMC4zODI5NDMgMjIuNTEwOSAwLjY0NzMxOCAxOC40OTgxTDAuNjgxNTg5IDE3Ljk5NEwwLjY5NjI3NiAxNy43Mzk2TDAuNzM1NDQzIDE3LjIzMDZMMC44NDMxNTEgMTUuOTU4M0wwLjg5MjEwOSAxNS40NDkzQzEuMTI3MTEgMTIuOTA5NSAxLjQ3NDcxIDEwLjQ0MzEgMS45NjkxOSA4LjU4ODRDMi40MTMyMSA2LjkyNDc4IDMuMjg2OTcgNS40MDcwNyA0LjUwMjg1IDQuMTg3NDNDNS43MTg3NCAyLjk2Nzc5IDcuMjM0MDIgMi4wODkwNyA4Ljg5NjggMS42MzkzOEMxMS4yODExIDEuMDAzMiAxNi40NTYgMC42MTE3MDkgMjEuODkwMyAwLjM2NzAyNUwyMi43MjI2IDAuMzMyNzdMMjMuNTY0NyAwLjMwMzQwOUwyMy45ODU4IDAuMjg4NzI3TDI0LjgyMjkgMC4yNTQ0NzJDMjkuNDgyMyAwLjEwNDYwMSAzNC4xNDM3IDAuMDIxMzk5NCAzOC44MDU0IDAuMDA0ODkzOUgzOS43NTAzVjBaTTMxLjY2NzMgMTUuNzA4N1YzOS4yODY0TDUyLjAxOTMgMjcuNTAyNEwzMS42NjczIDE1LjcwODdaIiBmaWxsPSIjRUEzMzIzIi8+CjxwYXRoIGQ9Ik0zMS42NjggMTUuNzA4N1YzOS4yODY1TDUyLjAxOTkgMjcuNTAyNUwzMS42NjggMTUuNzA4N1oiIGZpbGw9IndoaXRlIi8+Cjwvc3ZnPg==")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is this coming from?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, this is just me converting the YouTube logo to a base64 string. Can add it as an actual image if that's preferable.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a benefit to either appraoch? The only downside I can see here is that it amkes the file slightly less legible. If we can add a comment explaining what it is and why that's good enough for me.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thing to think about: inlined in the CSS, it adds Kb of downloads to each page, even those that don't show any video. If referenced as an external URL, browsers will only download it on pages showing videos 😊

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll switch to using an asset :)

<p class="govuk-body">You’ve accepted analytics cookies. You can <a class="govuk-link" href="/cookies/">change your cookie settings</a> at any time.</p>
{% endset %}
{%- set category -%}
{%- if not params.category -%}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How come we're checking for params negatively? IE: Can we change the if around so we're just checking for params.[param]?

Adds new category of cookies to cookie functions and the cookie page.
Change default values of preference cookies to `null`. This means that
we can now track if the user has been asked at all what their cookie
preference is for different categories.
Change `_cookie-banner.njk` to a macro that take parameters including
what category of cookie the banner is setting and the HTML that should
be displayed for different states of the cookie banner.

Allow `cookie-banner.mjs` to have a different cookie category than
'analytics' to be set (by using data varibles on the target module).

Move the `GDS_CONSENT_COOKIE_VERSION` to `_generic.njk` so that this
only gets set once at the top each page instead of multiple times by
different cookie banner instances.

Add new tests for multiple categories of cookie banners on the same
page. Update existing tests.
Create the Design System Day 1 page, which will consist of embeds of
talks of the speakers.
Update `application.mjs` to support multiple cookie banners on a page.

Create new Embed Card component. If require cookie not set (or script
fails to execute) placeholder image that links to YouTube video will be
created. If cookie is set then placeholder will be replaced with a YT
embed.

Add `lazyEmbedObserver` in `application.mjs`. Embed Card component will
only be initialized when the placeholder is in the viewport. This means
for a page with lots of embeds, the page the performance hit will be
limited if the user doesn't scroll the entire page.

Add tests for new Embed Card component.
Copy link
Contributor

@owenatgov owenatgov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😎

@patrickpatrickpatrick patrickpatrickpatrick merged commit a88c287 into main Aug 21, 2024
@patrickpatrickpatrick patrickpatrickpatrick deleted the design-system-day-yt branch August 21, 2024 13:06
Copy link
Member

@romaricpascal romaricpascal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies for the late review, it's a strong base to add embeds but I've found a couple of places we might improve things. These can be adressed in separate PRs now we've merged 😊

})

await page.setCookie({ ...cookieParam, value })
await goTo(page, '/community/design-system-day-2024-day-1/')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion Could we use a draft test page instead of a live content page everywhere we're running tests? This will reduce the risk of a content update screwing the tests if one day we archive or move the page for DS Day day 1.


const $embedCards = document.querySelectorAll('[data-module="app-embed-card"]')

const lazyEmbedObserver = new IntersectionObserver(function (
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question Looks like there's a slim gap of lack of support for IntersectionObserver in Safari where this code will error. Thanfully this is the last thing being initialised, so other components won't be affected, but if an error occurs due to lack of IntersectionObserver, will people still be able to navigate to the video via the link already in the page?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion For tidiness, it would be good to protect the component's initialisation with an if (IntersectionObserver in window) or something similar 😊

{{- caller() if caller else params.content | safe -}}
<a class="app-embed-card__placeholder" href="https://www.youtube.com/watch?v={{ params.ytId }}">
<div class="app-embed-card__placeholder-thumb-container">
<img class="app-image--no-border app-embed-card__placeholder-thumb-image" alt="placeholder for {{ params.title }} youtube embed" src="https://img.youtube.com/vi/{{ params.ytId }}/hqdefault.jpg">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick Worth checking with @selfthinker, but I don't think the alternative text brings any information to a person using assistive technology and will just lengthen the name of the link to "placeholder for <VIDEO_TITLE> youtube embed <VIDEO_TITLE>".

If we set the alt text to {{ params.title}} this will:

  • provide a fallback in case the placeholder image doesn't load for whatever reason
  • reduce the markup, as the next span will be redundant for labelling the link and we can get rid of it

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question A couple of questions about the URL we use for that placeholder:

  • is it from an official API from YouTube or discovered from how their embed works? how likely is it to change in the future?
  • it effectively embeds content from another domain into our site, are we sure it doesn't set cookies prior to users having given their consent (and won't do in the future)?

All in all, it might be safer to have the placeholder images in our repo (we're the ones making the videos anyway so we have the images, in any case).

Comment on lines +85 to +86
lazyEmbedObserver.unobserve(lazyEmbed)
lazyEmbedObserver.observe(lazyEmbed)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question I'm not following what this is doing exactly, what's stopping observing and observing again doing?

}

const observer = new MutationObserver(callback)
observer.observe(campaignCookieBanner, {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question Do we need to unobserve the mutations at some point? Thinking the CookieBanner may have two mutations happening: the click for 'Accept/Refuse', then the click to dismiss the banner?

}
}

.app-campaign-cookie-banner .govuk-grid-column-two-thirds {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick This makes the semantic of govuk-grid-column-two-thirds surprising. Is there a way we could use either:

Comment on lines +46 to +50
const ytId = ytHref.match(
/(youtu\.be\/|youtube\.com\/(watch\?(.*&)?v=|(embed|v)\/))([^?&"'>]+)/
)[5]

const iframe = this.createIframe(ytId, title)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion Given the Nunjucks component knows the ID, passing it through data-attribute would avoid us maintaining a RegExp to extract it from a URL we've built ourselves.

@@ -0,0 +1,17 @@
.app-embed-card__placeholder-thumb-container {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue If the image does not load, the thumbnail container becomes very short. Best to give it a set aspect ratio (we'll still need the padding hack to do it).

Screenshot 2024-08-22 at 11 51 52

The aspect ratio would also be beneficial to the iframe while it's loading, to avoid layout shifts.

<div class="govuk-grid-column-two-thirds-from-desktop">
{{- caller() if caller else params.content | safe -}}
<a class="app-embed-card__placeholder" href="https://www.youtube.com/watch?v={{ params.ytId }}">
<div class="app-embed-card__placeholder-thumb-container">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question Could the <a> serve as thumb container if it was display: block and lighten the HTML a little?

@@ -0,0 +1,22 @@
{% macro embedCard(params) %}
<div class="govuk-grid-row" data-module="app-embed-card">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion Given the role of the JavaScript is to swap the link for an iframe, having it set on the <a> element would help narrow down which bits of the markup it would affect.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Investigate youtube video embedding for the DS website

3 participants