From e4a1a4935df085ec5aafe473f6aba6a4b8e41a78 Mon Sep 17 00:00:00 2001 From: julieg18 Date: Wed, 2 Feb 2022 10:47:04 -0600 Subject: [PATCH 01/14] Make markdown youtube embeds gdpr compliant * add custom youtube transformer to gatsby-remark-embedder * add needed js and css code in doc/blog components --- .../custom-yt-embedder.js | 59 +++++++++++++++++++ gatsby-config.js | 8 ++- .../Documentation/Markdown/Main/index.tsx | 3 + .../Markdown/Main/styles.module.css | 47 +++++++++++++++ .../src/utils/front/setUpCustomYtEmbeds.ts | 16 +++++ .../Blog/Post/Markdown/styles.module.css | 49 +++++++++++++++ src/components/Blog/Post/index.tsx | 7 ++- 7 files changed, 187 insertions(+), 2 deletions(-) create mode 100644 config/gatsby-remark-embedder/custom-yt-embedder.js create mode 100644 plugins/gatsby-theme-iterative-docs/src/utils/front/setUpCustomYtEmbeds.ts diff --git a/config/gatsby-remark-embedder/custom-yt-embedder.js b/config/gatsby-remark-embedder/custom-yt-embedder.js new file mode 100644 index 0000000000..4bfd78ad85 --- /dev/null +++ b/config/gatsby-remark-embedder/custom-yt-embedder.js @@ -0,0 +1,59 @@ +const shouldTransform = url => { + const { host, pathname, searchParams } = new URL(url) + + return ( + host === 'youtu.be' || + (['youtube.com', 'www.youtube.com'].includes(host) && + pathname.includes('/watch') && + Boolean(searchParams.get('v'))) + ) +} + +const getTimeValueInSeconds = timeValue => { + if (Number(timeValue).toString() === timeValue) { + return timeValue + } + + const { + 2: hours = '0', + 4: minutes = '0', + 6: seconds = '0' + } = timeValue.match(/((\d*)h)?((\d*)m)?((\d*)s)?/) + + return String((Number(hours) * 60 + Number(minutes)) * 60 + Number(seconds)) +} + +const getYouTubeIFrameSrc = urlString => { + const url = new URL(urlString) + const id = + url.host === 'youtu.be' ? url.pathname.slice(1) : url.searchParams.get('v') + + const embedUrl = new URL( + `https://www.youtube-nocookie.com/embed/${id}?rel=0&controls=0&showinfo=0;` + ) + + url.searchParams.forEach((value, name) => { + if (name === 'v') { + return + } + + if (name === 't') { + embedUrl.searchParams.append('start', getTimeValueInSeconds(value)) + } else { + embedUrl.searchParams.append(name, value) + } + }) + return embedUrl.toString() +} + +// all code above taken from gatsby-remark-embedder (https://github.com/MichaelDeBoey/gatsby-remark-embedder) + +const name = 'YouTubeCustom' + +const getHTML = url => { + const iframeSrc = getYouTubeIFrameSrc(url) + + return `
By clicking play, you agree to YouTube's Privacy Policy and Terms of Service
` +} + +module.exports = { getHTML, name, shouldTransform } diff --git a/gatsby-config.js b/gatsby-config.js index d3adb03408..854ace5791 100644 --- a/gatsby-config.js +++ b/gatsby-config.js @@ -7,6 +7,7 @@ require('./config/prismjs/dvc') require('./config/prismjs/usage') require('./config/prismjs/dvctable') +const customYoutubeTransformer = require('./config/gatsby-remark-embedder/custom-yt-embedder') const apiMiddleware = require('./src/server/middleware/api') const redirectsMiddleware = require('./src/server/middleware/redirects') const makeFeedHtml = require('./plugins/utils/makeFeedHtml') @@ -70,7 +71,12 @@ const plugins = [ resolve: 'gatsby-transformer-remark', options: { plugins: [ - 'gatsby-remark-embedder', + { + resolve: 'gatsby-remark-embedder', + options: { + customTransformers: [customYoutubeTransformer] + } + }, 'gatsby-remark-dvc-linker', { resolve: 'gatsby-remark-args-linker', diff --git a/plugins/gatsby-theme-iterative-docs/src/components/Documentation/Markdown/Main/index.tsx b/plugins/gatsby-theme-iterative-docs/src/components/Documentation/Markdown/Main/index.tsx index 5979791159..a9e07788d4 100644 --- a/plugins/gatsby-theme-iterative-docs/src/components/Documentation/Markdown/Main/index.tsx +++ b/plugins/gatsby-theme-iterative-docs/src/components/Documentation/Markdown/Main/index.tsx @@ -5,6 +5,7 @@ import { navigate } from '@reach/router' import Link from '../../../Link' import Tutorials from '../../TutorialsLinks' import { getPathWithSource } from '../../../../utils/shared/sidebar' +import setUpCustomYtEmbeds from '../../../..//utils/front/setUpCustomYtEmbeds' import 'github-markdown-css/github-markdown-light.css' import * as sharedStyles from '../../styles.module.css' @@ -64,6 +65,8 @@ const Main: React.FC = ({ }, []) useEffect(() => { + setUpCustomYtEmbeds() + document.addEventListener('touchstart', onTouchStart, false) document.addEventListener('touchend', onTouchEnd, false) diff --git a/plugins/gatsby-theme-iterative-docs/src/components/Documentation/Markdown/Main/styles.module.css b/plugins/gatsby-theme-iterative-docs/src/components/Documentation/Markdown/Main/styles.module.css index 274aad58a4..61f70345e4 100644 --- a/plugins/gatsby-theme-iterative-docs/src/components/Documentation/Markdown/Main/styles.module.css +++ b/plugins/gatsby-theme-iterative-docs/src/components/Documentation/Markdown/Main/styles.module.css @@ -273,6 +273,53 @@ margin-left: 20px; margin-right: 10px; } + + .yt-embed-wrapper { + position: relative; + display: flex; + + &:hover &__tooltip { + opacity: 1; + } + + &__overlay { + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 100%; + display: flex; + align-items: flex-end; + + &:hover { + cursor: pointer; + } + + &.hidden { + display: none; + } + } + + &__tooltip { + padding: 10px; + box-sizing: border-box; + color: #fff; + opacity: 0; + width: 100%; + font-size: 16px; + background-color: rgb(23 23 23 / 59%); + text-shadow: 0 1px 0 rgb(33 45 69 / 25%); + transition: opacity 0.2s ease-in-out; + + a { + color: #fff; + + &::after { + display: none; + } + } + } + } } .content { diff --git a/plugins/gatsby-theme-iterative-docs/src/utils/front/setUpCustomYtEmbeds.ts b/plugins/gatsby-theme-iterative-docs/src/utils/front/setUpCustomYtEmbeds.ts new file mode 100644 index 0000000000..f75ba9fbda --- /dev/null +++ b/plugins/gatsby-theme-iterative-docs/src/utils/front/setUpCustomYtEmbeds.ts @@ -0,0 +1,16 @@ +const setUpCustomYtEmbeds = () => { + const ytEmbeds = document.querySelectorAll('.yt-embed-wrapper') + ytEmbeds.forEach(embed => { + const iframe = embed.querySelector('iframe') + const overlay = embed.querySelector('.yt-embed-wrapper__overlay') + + overlay?.addEventListener('click', () => { + if (iframe && iframe.src) { + iframe.src = iframe?.src + `&autoplay=1` + } + overlay.classList.add('hidden') + }) + }) +} + +export default setUpCustomYtEmbeds diff --git a/src/components/Blog/Post/Markdown/styles.module.css b/src/components/Blog/Post/Markdown/styles.module.css index 9ff7a5a54a..efcc4ce208 100644 --- a/src/components/Blog/Post/Markdown/styles.module.css +++ b/src/components/Blog/Post/Markdown/styles.module.css @@ -564,4 +564,53 @@ border-bottom: none; } } + + :global { + .yt-embed-wrapper { + position: relative; + display: flex; + + &:hover &__tooltip { + opacity: 1; + } + + &__overlay { + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 100%; + display: flex; + align-items: flex-end; + + &:hover { + cursor: pointer; + } + + &.hidden { + display: none; + } + } + + &__tooltip { + padding: 10px; + box-sizing: border-box; + color: #fff; + opacity: 0; + width: 100%; + font-size: 16px; + background-color: rgb(23 23 23 / 59%); + text-shadow: 0 1px 0 rgb(33 45 69 / 25%); + transition: opacity 0.2s ease-in-out; + + a { + color: #fff; + + &::after { + display: none; + } + } + } + } + } } diff --git a/src/components/Blog/Post/index.tsx b/src/components/Blog/Post/index.tsx index f16b8dbbb6..5bbcbbb3ed 100644 --- a/src/components/Blog/Post/index.tsx +++ b/src/components/Blog/Post/index.tsx @@ -1,6 +1,6 @@ import cn from 'classnames' -import React, { useMemo, useRef } from 'react' +import React, { useMemo, useRef, useEffect } from 'react' import { useWindowScroll, useWindowSize } from 'react-use' import { IBlogPostData } from '../../../templates/blog-post' @@ -8,6 +8,7 @@ import { IBlogPostData } from '../../../templates/blog-post' import { useCommentsCount } from 'gatsby-theme-iterative-docs/src/utils/front/api' import { pluralizeComments } from 'gatsby-theme-iterative-docs/src/utils/front/i18n' import tagToSlug from 'gatsby-theme-iterative-docs/src/utils/shared/tagToSlug' +import setUpCustomYtEmbeds from 'gatsby-theme-iterative-docs/src/utils/front/setUpCustomYtEmbeds' import Markdown from './Markdown' import FeedMeta from '../FeedMeta' @@ -38,6 +39,10 @@ const Post: React.FC = ({ const { width, height } = useWindowSize() const { y } = useWindowScroll() + useEffect(() => { + setUpCustomYtEmbeds() + }, []) + const isFixed = useMemo(() => { if (!wrapperRef.current) { return false From a10c1d158cc8687771a80734c224176aa2756b1d Mon Sep 17 00:00:00 2001 From: julieg18 Date: Wed, 2 Feb 2022 10:47:50 -0600 Subject: [PATCH 02/14] Make Video youtube embeds gdpr compliant * add on hover message to overlay --- src/components/Home/UseCases/Video/index.tsx | 41 +++++++++++++------ .../Home/UseCases/Video/styles.module.css | 27 ++++++++++++ 2 files changed, 55 insertions(+), 13 deletions(-) diff --git a/src/components/Home/UseCases/Video/index.tsx b/src/components/Home/UseCases/Video/index.tsx index 0191c7d56f..f268532f29 100644 --- a/src/components/Home/UseCases/Video/index.tsx +++ b/src/components/Home/UseCases/Video/index.tsx @@ -3,6 +3,8 @@ import React, { useState, useCallback } from 'react' import TwoRowsButton from '../../../TwoRowsButton' import { logEvent } from 'gatsby-theme-iterative-docs/src/utils/front/plausible' +import Link from 'gatsby-theme-iterative-docs/src/components/Link' + import * as styles from './styles.module.css' const Video: React.FC<{ id: string }> = ({ id }) => { @@ -18,19 +20,32 @@ const Video: React.FC<{ id: string }> = ({ id }) => {
{!isWatching && (
- - } - onClick={watchVideo} - /> +
+ + } + onClick={watchVideo} + /> +
+ By clicking play, you agree to YouTube's{' '} + + Privacy Policy + {' '} + and{' '} + + Terms of Service + +
+
)}
By clicking play, you agree to YouTube's Privacy Policy and Terms of Service
` + return `
By clicking play, you agree to YouTube's Privacy Policy and Terms of Service
` } module.exports = { getHTML, name, shouldTransform } From c1fa1a474e21712ed885f80b91b45f4e72b3813d Mon Sep 17 00:00:00 2001 From: julieg18 Date: Thu, 3 Feb 2022 15:11:08 -0600 Subject: [PATCH 08/14] Fix ts error --- .../src/utils/front/useCustomYtEmbeds.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/gatsby-theme-iterative-docs/src/utils/front/useCustomYtEmbeds.ts b/plugins/gatsby-theme-iterative-docs/src/utils/front/useCustomYtEmbeds.ts index e1d28f3315..3c49f1ce1e 100644 --- a/plugins/gatsby-theme-iterative-docs/src/utils/front/useCustomYtEmbeds.ts +++ b/plugins/gatsby-theme-iterative-docs/src/utils/front/useCustomYtEmbeds.ts @@ -8,7 +8,7 @@ const setUpCustomYtEmbeds = () => { const tooltip = embed.querySelector('.yt-embed-wrapper__tooltip') overlay?.addEventListener('click', event => { - if (event.target === tooltip || tooltip?.contains(event.target)) { + if (event.target === tooltip || tooltip?.contains(event.target as Node)) { return } if (iframe && iframe.src) { From 644fca69c01451481b7b549ce709dd158ff218ea Mon Sep 17 00:00:00 2001 From: julieg18 Date: Thu, 3 Feb 2022 15:38:07 -0600 Subject: [PATCH 09/14] fix cursor on tooltip --- .../components/Documentation/Markdown/Main/styles.module.css | 4 ++++ src/components/Blog/Post/Markdown/styles.module.css | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/plugins/gatsby-theme-iterative-docs/src/components/Documentation/Markdown/Main/styles.module.css b/plugins/gatsby-theme-iterative-docs/src/components/Documentation/Markdown/Main/styles.module.css index 61f70345e4..2fead92259 100644 --- a/plugins/gatsby-theme-iterative-docs/src/components/Documentation/Markdown/Main/styles.module.css +++ b/plugins/gatsby-theme-iterative-docs/src/components/Documentation/Markdown/Main/styles.module.css @@ -311,6 +311,10 @@ text-shadow: 0 1px 0 rgb(33 45 69 / 25%); transition: opacity 0.2s ease-in-out; + &:hover { + cursor: auto; + } + a { color: #fff; diff --git a/src/components/Blog/Post/Markdown/styles.module.css b/src/components/Blog/Post/Markdown/styles.module.css index efcc4ce208..c5571d877d 100644 --- a/src/components/Blog/Post/Markdown/styles.module.css +++ b/src/components/Blog/Post/Markdown/styles.module.css @@ -603,6 +603,10 @@ text-shadow: 0 1px 0 rgb(33 45 69 / 25%); transition: opacity 0.2s ease-in-out; + &:hover { + cursor: auto; + } + a { color: #fff; From c88e09e9c89ec18b42a7350128ea86b82492e6b5 Mon Sep 17 00:00:00 2001 From: julieg18 Date: Thu, 3 Feb 2022 15:43:18 -0600 Subject: [PATCH 10/14] Add remove click listeners --- .../src/utils/front/useCustomYtEmbeds.ts | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/plugins/gatsby-theme-iterative-docs/src/utils/front/useCustomYtEmbeds.ts b/plugins/gatsby-theme-iterative-docs/src/utils/front/useCustomYtEmbeds.ts index 3c49f1ce1e..042832039e 100644 --- a/plugins/gatsby-theme-iterative-docs/src/utils/front/useCustomYtEmbeds.ts +++ b/plugins/gatsby-theme-iterative-docs/src/utils/front/useCustomYtEmbeds.ts @@ -2,26 +2,44 @@ import { useEffect } from 'react' const setUpCustomYtEmbeds = () => { const ytEmbeds = document.querySelectorAll('.yt-embed-wrapper') + const removeClickListeners: Array<() => void> = [] + ytEmbeds.forEach(embed => { const iframe = embed.querySelector('iframe') const overlay = embed.querySelector('.yt-embed-wrapper__overlay') const tooltip = embed.querySelector('.yt-embed-wrapper__tooltip') - overlay?.addEventListener('click', event => { + const handleOverlayClick = (event: MouseEvent) => { if (event.target === tooltip || tooltip?.contains(event.target as Node)) { return } if (iframe && iframe.src) { iframe.src = iframe?.src + `&autoplay=1` } - overlay.classList.add('hidden') - }) + overlay?.classList.add('hidden') + } + + const removeListener = () => { + overlay?.removeEventListener('click', handleOverlayClick as EventListener) + } + + overlay?.addEventListener('click', handleOverlayClick as EventListener) + + removeClickListeners.push(removeListener) }) + + return () => { + removeClickListeners.forEach(rmListener => rmListener()) + } } const useCustomYtEmbeds = () => { useEffect(() => { - setUpCustomYtEmbeds() + const removeEventListeners = setUpCustomYtEmbeds() + + return () => { + removeEventListeners() + } }, []) } From eabc30d96e9c94d8f3c5f6846839fba9dc6e47f6 Mon Sep 17 00:00:00 2001 From: julieg18 Date: Fri, 4 Feb 2022 07:34:24 -0600 Subject: [PATCH 11/14] Set up local storage --- .../src/utils/front/useCustomYtEmbeds.ts | 33 ++++++++++++++----- src/components/Home/UseCases/Video/index.tsx | 32 +++++++++++------- 2 files changed, 45 insertions(+), 20 deletions(-) diff --git a/plugins/gatsby-theme-iterative-docs/src/utils/front/useCustomYtEmbeds.ts b/plugins/gatsby-theme-iterative-docs/src/utils/front/useCustomYtEmbeds.ts index 042832039e..dc5e74b822 100644 --- a/plugins/gatsby-theme-iterative-docs/src/utils/front/useCustomYtEmbeds.ts +++ b/plugins/gatsby-theme-iterative-docs/src/utils/front/useCustomYtEmbeds.ts @@ -1,10 +1,16 @@ import { useEffect } from 'react' -const setUpCustomYtEmbeds = () => { - const ytEmbeds = document.querySelectorAll('.yt-embed-wrapper') +const hideAllEmbedOverlays = (embeds: NodeListOf) => { + embeds.forEach(embed => { + const overlay = embed.querySelector('.yt-embed-wrapper__overlay') + overlay?.classList.add('hidden') + }) +} + +const setUpEmbedClickListeners = (embeds: NodeListOf) => { const removeClickListeners: Array<() => void> = [] - ytEmbeds.forEach(embed => { + embeds.forEach(embed => { const iframe = embed.querySelector('iframe') const overlay = embed.querySelector('.yt-embed-wrapper__overlay') const tooltip = embed.querySelector('.yt-embed-wrapper__tooltip') @@ -13,18 +19,17 @@ const setUpCustomYtEmbeds = () => { if (event.target === tooltip || tooltip?.contains(event.target as Node)) { return } + if (iframe && iframe.src) { iframe.src = iframe?.src + `&autoplay=1` } - overlay?.classList.add('hidden') + hideAllEmbedOverlays(embeds) + localStorage.setItem('yt-embed-consent', 'true') } - const removeListener = () => { overlay?.removeEventListener('click', handleOverlayClick as EventListener) } - overlay?.addEventListener('click', handleOverlayClick as EventListener) - removeClickListeners.push(removeListener) }) @@ -35,10 +40,20 @@ const setUpCustomYtEmbeds = () => { const useCustomYtEmbeds = () => { useEffect(() => { - const removeEventListeners = setUpCustomYtEmbeds() + const hasUserGivenConsent = Boolean( + localStorage.getItem('yt-embed-consent') + ) + const embeds = document.querySelectorAll('.yt-embed-wrapper') + + if (hasUserGivenConsent) { + hideAllEmbedOverlays(embeds) + return + } + + const cleanUpEventListeners = setUpEmbedClickListeners(embeds) return () => { - removeEventListeners() + cleanUpEventListeners() } }, []) } diff --git a/src/components/Home/UseCases/Video/index.tsx b/src/components/Home/UseCases/Video/index.tsx index f268532f29..e749cc6879 100644 --- a/src/components/Home/UseCases/Video/index.tsx +++ b/src/components/Home/UseCases/Video/index.tsx @@ -1,4 +1,4 @@ -import React, { useState, useCallback } from 'react' +import React, { useState, useCallback, useEffect } from 'react' import TwoRowsButton from '../../../TwoRowsButton' import { logEvent } from 'gatsby-theme-iterative-docs/src/utils/front/plausible' @@ -9,10 +9,18 @@ import * as styles from './styles.module.css' const Video: React.FC<{ id: string }> = ({ id }) => { const [isWatching, setWatching] = useState(false) + const [hasUserGivenConsent, setHasUserGivenConsent] = useState(false) + + useEffect(() => { + const givenConsent = Boolean(localStorage.getItem('yt-embed-consent')) + + setHasUserGivenConsent(givenConsent) + }, []) const watchVideo = useCallback(() => { logEvent('Button', { Item: 'video' }) setWatching(true) + localStorage.setItem('yt-embed-consent', 'true') }, []) return ( @@ -35,16 +43,18 @@ const Video: React.FC<{ id: string }> = ({ id }) => { } onClick={watchVideo} /> -
- By clicking play, you agree to YouTube's{' '} - - Privacy Policy - {' '} - and{' '} - - Terms of Service - -
+ {!hasUserGivenConsent && ( +
+ By clicking play, you agree to YouTube's{' '} + + Privacy Policy + {' '} + and{' '} + + Terms of Service + +
+ )} )} From 5e25a5d53a2ab1696fc76b5c4dda5265c4cce709 Mon Sep 17 00:00:00 2001 From: julieg18 Date: Fri, 4 Feb 2022 08:11:16 -0600 Subject: [PATCH 12/14] Refactor custom-yt-embedder --- .../gatsby-remark-embedder/custom-yt-embedder.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/config/gatsby-remark-embedder/custom-yt-embedder.js b/config/gatsby-remark-embedder/custom-yt-embedder.js index 8d3e5f0fd3..30b00f0a0b 100644 --- a/config/gatsby-remark-embedder/custom-yt-embedder.js +++ b/config/gatsby-remark-embedder/custom-yt-embedder.js @@ -2,10 +2,9 @@ const shouldTransform = url => { const { host, pathname, searchParams } = new URL(url) return ( - host === 'youtu.be' || - (['youtube.com', 'www.youtube.com'].includes(host) && - pathname.includes('/watch') && - Boolean(searchParams.get('v'))) + ['youtu.be', 'youtube.com', 'www.youtube.com'].includes(host) && + pathname.includes('/watch') && + Boolean(searchParams.get('v')) ) } @@ -15,10 +14,10 @@ const getTimeValueInSeconds = timeValue => { } const { - 2: hours = '0', - 4: minutes = '0', - 6: seconds = '0' - } = timeValue.match(/((\d*)h)?((\d*)m)?((\d*)s)?/) + 1: hours = '0', + 2: minutes = '0', + 3: seconds = '0' + } = timeValue.match(/(?:(\d*)h)?(?:(\d*)m)?(?:(\d*)s)?/) return String((Number(hours) * 60 + Number(minutes)) * 60 + Number(seconds)) } From 3d03fcf1748d628b5bc351ce26b3a546be5aa6b1 Mon Sep 17 00:00:00 2001 From: julieg18 Date: Fri, 4 Feb 2022 10:16:30 -0600 Subject: [PATCH 13/14] Fix bug --- config/gatsby-remark-embedder/custom-yt-embedder.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/config/gatsby-remark-embedder/custom-yt-embedder.js b/config/gatsby-remark-embedder/custom-yt-embedder.js index 30b00f0a0b..7acf6a2d10 100644 --- a/config/gatsby-remark-embedder/custom-yt-embedder.js +++ b/config/gatsby-remark-embedder/custom-yt-embedder.js @@ -2,9 +2,10 @@ const shouldTransform = url => { const { host, pathname, searchParams } = new URL(url) return ( - ['youtu.be', 'youtube.com', 'www.youtube.com'].includes(host) && - pathname.includes('/watch') && - Boolean(searchParams.get('v')) + host === 'youtu.be' || + (['youtube.com', 'www.youtube.com'].includes(host) && + pathname.includes('/watch') && + Boolean(searchParams.get('v'))) ) } From 6b2af716aa9105e10675a37d21f31deb4dbd5732 Mon Sep 17 00:00:00 2001 From: julieg18 Date: Fri, 4 Feb 2022 16:02:54 -0600 Subject: [PATCH 14/14] Keep embed links style consistent --- .../Documentation/Markdown/Main/styles.module.css | 3 +++ src/components/Blog/Post/Markdown/styles.module.css | 11 +++++++++++ src/components/Home/UseCases/Video/styles.module.css | 2 ++ 3 files changed, 16 insertions(+) diff --git a/plugins/gatsby-theme-iterative-docs/src/components/Documentation/Markdown/Main/styles.module.css b/plugins/gatsby-theme-iterative-docs/src/components/Documentation/Markdown/Main/styles.module.css index 2fead92259..6269e61494 100644 --- a/plugins/gatsby-theme-iterative-docs/src/components/Documentation/Markdown/Main/styles.module.css +++ b/plugins/gatsby-theme-iterative-docs/src/components/Documentation/Markdown/Main/styles.module.css @@ -316,7 +316,10 @@ } a { + @mixin focus; + color: #fff; + text-decoration: underline; &::after { display: none; diff --git a/src/components/Blog/Post/Markdown/styles.module.css b/src/components/Blog/Post/Markdown/styles.module.css index c5571d877d..8ca158573f 100644 --- a/src/components/Blog/Post/Markdown/styles.module.css +++ b/src/components/Blog/Post/Markdown/styles.module.css @@ -608,7 +608,18 @@ } a { + @mixin focus; + color: #fff; + text-decoration: underline; + + &:hover { + opacity: 1; + } + + &:focus { + position: static; + } &::after { display: none; diff --git a/src/components/Home/UseCases/Video/styles.module.css b/src/components/Home/UseCases/Video/styles.module.css index 8bc9fe473e..935312293e 100644 --- a/src/components/Home/UseCases/Video/styles.module.css +++ b/src/components/Home/UseCases/Video/styles.module.css @@ -75,6 +75,8 @@ } a { + @mixin focus; + color: #fff; } }