Skip to content

Commit

Permalink
Merge pull request #90 from GoogleChromeLabs/video/observer
Browse files Browse the repository at this point in the history
News Videos - Intersection Observer
  • Loading branch information
flashdesignory authored Oct 30, 2024
2 parents 2425c13 + f1c2be1 commit 2393dcc
Show file tree
Hide file tree
Showing 30 changed files with 303 additions and 68 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { useRef, useEffect } from "react";

export function useIntersectionObserver( { callback }) {
const elementRef = useRef(undefined);
const intersectionObserver = useRef(undefined);

useEffect(
function() {
const element = elementRef.current;
intersectionObserver.current = new IntersectionObserver(callback);
intersectionObserver.current.observe(element);

return function () {
if (intersectionObserver.current)
intersectionObserver.current.unobserve(element);

};
}, [elementRef]
);

function disconnect() {
if (intersectionObserver.current)
intersectionObserver.current.disconnect();
}

return { elementRef, disconnect };
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,41 @@
import { useRef } from "react";

import ArticleTag from "@/components/molecules/article/article-tag";
import ArticleText from "@/components/molecules/article/article-text";

import { useIntersectionObserver } from "@/hooks/use-intersection-observer";

import videoStyles from "./article-video.module.css";
import styles from "news-site-css/dist/article.module.css";

export default function ArticleVideo ({ data, meta }) {
if (!data)
return null;

const autoplayRef = useRef(false);

const { elementRef, disconnect } = useIntersectionObserver({
callback: handleOnIntersection
});

function handleOnIntersection(entries) {
for (let entry of entries) {
if (!entry.isIntersecting)
return;

disconnect();
autoplayRef.current = true;
}
}

const videoSource = process.env.TARGET && process.env.TARGET === "static" ? `./${data.src}` : `/${data.src}`;
const aspectRatio = data.width / data.height;

return (
<>
<div className={videoStyles.container} style={{ aspectRatio }}>
<div className={videoStyles.container} style={{ aspectRatio }} ref={elementRef}>
<div className={videoStyles.content}>
<video src={videoSource} muted autoPlay controls playsinline webkit-playsinline/>
<video id={data.id} src={videoSource} muted controls playsInline autoPlay={autoplayRef} />
</div>
<ArticleTag tag={meta?.tag} />
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { useRef, useEffect } from "react";

export function useIntersectionObserver( { callback }) {
const elementRef = useRef(undefined);
const intersectionObserver = useRef(undefined);

useEffect(
function() {
const element = elementRef.current;
intersectionObserver.current = new IntersectionObserver(callback);
intersectionObserver.current.observe(element);

return function () {
if (intersectionObserver.current)
intersectionObserver.current.unobserve(element);

};
}, [elementRef]
);

function disconnect() {
if (intersectionObserver.current)
intersectionObserver.current.disconnect();
}

return { elementRef, disconnect };
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,41 @@
import { useRef } from "react";

import ArticleTag from "@/components/molecules/article/article-tag";
import ArticleText from "@/components/molecules/article/article-text";

import { useIntersectionObserver } from "@/hooks/use-intersection-observer";

import videoStyles from "./article-video.module.css";
import styles from "news-site-css/dist/article.module.css";

export default function ArticleVideo ({ data, meta }) {
if (!data)
return null;

const autoplayRef = useRef(false);

const { elementRef, disconnect } = useIntersectionObserver({
callback: handleOnIntersection
});

function handleOnIntersection(entries) {
for (let entry of entries) {
if (!entry.isIntersecting)
return;

disconnect();
autoplayRef.current = true;
}
}

const videoSource = process.env.TARGET && process.env.TARGET === "static" ? `./${data.src}` : `/${data.src}`;
const aspectRatio = data.width / data.height;

return (
<>
<div className={videoStyles.container} style={{ aspectRatio }}>
<div className={videoStyles.container} style={{ aspectRatio }} ref={elementRef}>
<div className={videoStyles.content}>
<video src={videoSource} muted autoPlay controls playsinline webkit-playsinline/>
<video id={data.id} src={videoSource} muted controls playsInline autoPlay={autoplayRef} />
</div>
<ArticleTag tag={meta?.tag} />
</div>
Expand Down
2 changes: 1 addition & 1 deletion apps/news-site/news-site-next/dist/404.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="./_next/static/css/ec187bc9a45ccd09.css" as="style"/><link rel="stylesheet" href="./_next/static/css/ec187bc9a45ccd09.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="./_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"></script><script src="./workload-testing-utils.min.js" type="module" async="" defer="" data-nscript="beforeInteractive"></script><script src="./workload-test.js" type="module" async="" defer="" data-nscript="beforeInteractive"></script><script src="./_next/static/chunks/webpack-dabe763974b7e688.js" defer=""></script><script src="./_next/static/chunks/framework-2ccfc1b811a4e007.js" defer=""></script><script src="./_next/static/chunks/main-d70fd7e950e8d98d.js" defer=""></script><script src="./_next/static/chunks/pages/_app-49cdd33e11c5c280.js" defer=""></script><script src="./_next/static/chunks/pages/_error-b750ae521d56f53f.js" defer=""></script><script src="./_next/static/GVijF8IiW-oscErTe7byT/_buildManifest.js" defer=""></script><script src="./_next/static/GVijF8IiW-oscErTe7byT/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><div id="settings-container"></div><div id="notifications-container"></div><div id="sitemap-container"></div><div id="login-container"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{"statusCode":404}},"page":"/_error","query":{},"buildId":"GVijF8IiW-oscErTe7byT","assetPrefix":".","nextExport":true,"isFallback":false,"gip":true,"scriptLoader":[]}</script></body></html>
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="./_next/static/css/ec187bc9a45ccd09.css" as="style"/><link rel="stylesheet" href="./_next/static/css/ec187bc9a45ccd09.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="./_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"></script><script src="./workload-testing-utils.min.js" type="module" async="" defer="" data-nscript="beforeInteractive"></script><script src="./workload-test.js" type="module" async="" defer="" data-nscript="beforeInteractive"></script><script src="./_next/static/chunks/webpack-dabe763974b7e688.js" defer=""></script><script src="./_next/static/chunks/framework-2ccfc1b811a4e007.js" defer=""></script><script src="./_next/static/chunks/main-d70fd7e950e8d98d.js" defer=""></script><script src="./_next/static/chunks/pages/_app-49cdd33e11c5c280.js" defer=""></script><script src="./_next/static/chunks/pages/_error-b750ae521d56f53f.js" defer=""></script><script src="./_next/static/wrEsXCWOzM4QfYOpj55CR/_buildManifest.js" defer=""></script><script src="./_next/static/wrEsXCWOzM4QfYOpj55CR/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><div id="settings-container"></div><div id="notifications-container"></div><div id="sitemap-container"></div><div id="login-container"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{"statusCode":404}},"page":"/_error","query":{},"buildId":"wrEsXCWOzM4QfYOpj55CR","assetPrefix":".","nextExport":true,"isFallback":false,"gip":true,"scriptLoader":[]}</script></body></html>

This file was deleted.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion apps/news-site/news-site-next/dist/index.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="./_next/static/css/ec187bc9a45ccd09.css" as="style"/><link rel="stylesheet" href="./_next/static/css/ec187bc9a45ccd09.css" data-n-g=""/><link rel="preload" href="./_next/static/css/33ac65976d350a23.css" as="style"/><link rel="stylesheet" href="./_next/static/css/33ac65976d350a23.css" data-n-p=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="./_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"></script><script src="./workload-testing-utils.min.js" type="module" async="" defer="" data-nscript="beforeInteractive"></script><script src="./workload-test.js" type="module" async="" defer="" data-nscript="beforeInteractive"></script><script src="./_next/static/chunks/webpack-dabe763974b7e688.js" defer=""></script><script src="./_next/static/chunks/framework-2ccfc1b811a4e007.js" defer=""></script><script src="./_next/static/chunks/main-d70fd7e950e8d98d.js" defer=""></script><script src="./_next/static/chunks/pages/_app-49cdd33e11c5c280.js" defer=""></script><script src="./_next/static/chunks/463e5e2b-76fd1f216b2a8cb0.js" defer=""></script><script src="./_next/static/chunks/978-f094c48b437e4ca3.js" defer=""></script><script src="./_next/static/chunks/pages/index-79d3d7a93274c482.js" defer=""></script><script src="./_next/static/GVijF8IiW-oscErTe7byT/_buildManifest.js" defer=""></script><script src="./_next/static/GVijF8IiW-oscErTe7byT/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><div id="settings-container"></div><div id="notifications-container"></div><div id="sitemap-container"></div><div id="login-container"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/","query":{},"buildId":"GVijF8IiW-oscErTe7byT","assetPrefix":".","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="./_next/static/css/ec187bc9a45ccd09.css" as="style"/><link rel="stylesheet" href="./_next/static/css/ec187bc9a45ccd09.css" data-n-g=""/><link rel="preload" href="./_next/static/css/33ac65976d350a23.css" as="style"/><link rel="stylesheet" href="./_next/static/css/33ac65976d350a23.css" data-n-p=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="./_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"></script><script src="./workload-testing-utils.min.js" type="module" async="" defer="" data-nscript="beforeInteractive"></script><script src="./workload-test.js" type="module" async="" defer="" data-nscript="beforeInteractive"></script><script src="./_next/static/chunks/webpack-dabe763974b7e688.js" defer=""></script><script src="./_next/static/chunks/framework-2ccfc1b811a4e007.js" defer=""></script><script src="./_next/static/chunks/main-d70fd7e950e8d98d.js" defer=""></script><script src="./_next/static/chunks/pages/_app-49cdd33e11c5c280.js" defer=""></script><script src="./_next/static/chunks/463e5e2b-76fd1f216b2a8cb0.js" defer=""></script><script src="./_next/static/chunks/978-f094c48b437e4ca3.js" defer=""></script><script src="./_next/static/chunks/pages/index-9ce97f331f88ffe3.js" defer=""></script><script src="./_next/static/wrEsXCWOzM4QfYOpj55CR/_buildManifest.js" defer=""></script><script src="./_next/static/wrEsXCWOzM4QfYOpj55CR/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><div id="settings-container"></div><div id="notifications-container"></div><div id="sitemap-container"></div><div id="login-container"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/","query":{},"buildId":"wrEsXCWOzM4QfYOpj55CR","assetPrefix":".","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { useRef, useEffect } from "react";

export function useIntersectionObserver( { callback }) {
const elementRef = useRef(undefined);
const intersectionObserver = useRef(undefined);

useEffect(
function() {
const element = elementRef.current;
intersectionObserver.current = new IntersectionObserver(callback);
intersectionObserver.current.observe(element);

return function () {
if (intersectionObserver.current)
intersectionObserver.current.unobserve(element);

};
}, [elementRef]
);

function disconnect() {
if (intersectionObserver.current)
intersectionObserver.current.disconnect();
}

return { elementRef, disconnect };
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,41 @@
import { useRef } from "react";

import ArticleTag from "@/components/molecules/article/article-tag";
import ArticleText from "@/components/molecules/article/article-text";

import { useIntersectionObserver } from "@/hooks/use-intersection-observer";

import videoStyles from "./article-video.module.css";
import styles from "news-site-css/dist/article.module.css";

export default function ArticleVideo ({ data, meta }) {
if (!data)
return null;

const autoplayRef = useRef(false);

const { elementRef, disconnect } = useIntersectionObserver({
callback: handleOnIntersection
});

function handleOnIntersection(entries) {
for (let entry of entries) {
if (!entry.isIntersecting)
return;

disconnect();
autoplayRef.current = true;
}
}

const videoSource = process.env.TARGET && process.env.TARGET === "static" ? `./${data.src}` : `/${data.src}`;
const aspectRatio = data.width / data.height;

return (
<>
<div className={videoStyles.container} style={{ aspectRatio }}>
<div className={videoStyles.container} style={{ aspectRatio }} ref={elementRef}>
<div className={videoStyles.content}>
<video src={videoSource} muted autoPlay controls playsinline webkit-playsinline/>
<video id={data.id} src={videoSource} muted controls playsInline autoPlay={autoplayRef} />
</div>
<ArticleTag tag={meta?.tag} />
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { ref, watch } from "vue";

export function useIntersectionObserver({ callback }) {
const elementRef = ref(undefined);
const intersectionObserver = ref(undefined);

watch(() => elementRef, () => {
if (!elementRef.value)
return;

const element = elementRef.value;
intersectionObserver.value = new IntersectionObserver(callback);
intersectionObserver.value.observe(element);

// eslint-disable-next-line consistent-return
return function () {
if (intersectionObserver.value)
intersectionObserver.value.unobserve(element);

};
}, { deep: true, immediate: true });

function disconnect() {
if (intersectionObserver.value)
intersectionObserver.value.disconnect();
}

return { elementRef, disconnect };
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
<script setup>
import { ref } from "vue";
import { useIntersectionObserver } from "#imports";
import styles from "news-site-css/dist/article.module.css";
import videoStyles from "../styles/article-video.module.css";
Expand All @@ -8,20 +10,36 @@ const { data, meta } = defineProps({
});
const aspectRatio = data.width / data.height;
const autoplayRef = ref(false);
const { elementRef, disconnect } = useIntersectionObserver({
callback: handleOnIntersection
});
function handleOnIntersection(entries) {
for (const entry of entries) {
if (!entry.isIntersecting)
return;
disconnect();
autoplayRef.value = true;
}
}
</script>
<template v-if="data">
<div
ref="elementRef"
:class="videoStyles.container"
:style="{ aspectRatio }"
>
<div :class="videoStyles.content">
<video
:src="data.src"
autoplay="autoplayRef"
muted
autoPlay
controls
playsinline
webkit-playsinline
playsInline
/>
</div>
<ArticleTag :tag="meta?.tag" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { ref, watch } from "vue";

export function useIntersectionObserver({ callback }) {
const elementRef = ref(undefined);
const intersectionObserver = ref(undefined);

watch(() => elementRef, () => {
if (!elementRef.value)
return;

const element = elementRef.value;
intersectionObserver.value = new IntersectionObserver(callback);
intersectionObserver.value.observe(element);

// eslint-disable-next-line consistent-return
return function () {
if (intersectionObserver.value)
intersectionObserver.value.unobserve(element);

};
}, { deep: true, immediate: true });

function disconnect() {
if (intersectionObserver.value)
intersectionObserver.value.disconnect();
}

return { elementRef, disconnect };
}
8 changes: 4 additions & 4 deletions apps/news-site/news-site-nuxt/dist/200.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
<title>The Daily Broadcast</title>
<meta name="description" content="A news site developed with Nuxt.">
<link rel="stylesheet" href="./_nuxt/entry.B4_de5XM.css">
<link rel="modulepreload" as="script" crossorigin href="./_nuxt/entry.tsOamT1S.js">
<link rel="modulepreload" as="script" crossorigin href="./_nuxt/entry.M-ziMx4_.js">
<link rel="prefetch" as="style" href="./_nuxt/error-404.ChDo4lHh.css">
<link rel="prefetch" as="script" crossorigin href="./_nuxt/error-404.CvFnQo5S.js">
<link rel="prefetch" as="script" crossorigin href="./_nuxt/error-404.Bl-h56Xq.js">
<link rel="prefetch" as="style" href="./_nuxt/error-500.CgCLIzMa.css">
<link rel="prefetch" as="script" crossorigin href="./_nuxt/error-500.Cks30mBZ.js">
<script type="module" src="./_nuxt/entry.tsOamT1S.js" crossorigin></script>
<link rel="prefetch" as="script" crossorigin href="./_nuxt/error-500.YpCZCrSC.js">
<script type="module" src="./_nuxt/entry.M-ziMx4_.js" crossorigin></script>
<script id="unhead:payload" type="application/json">{"title":"The Daily Broadcast"}</script></head><body><div id="__nuxt"></div><script type="application/json" id="__NUXT_DATA__" data-ssr="false">[{"_errors":1,"serverRendered":2,"data":3,"state":4,"once":5},{},false,{},{},["Set"]]</script>
<script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/",buildAssetsDir:"/_nuxt/",cdnURL:"./"}}</script></body></html>
Loading

0 comments on commit 2393dcc

Please sign in to comment.