From 5d50e024685d88466da3498136facdf74536714f Mon Sep 17 00:00:00 2001 From: Jamie Henson Date: Tue, 5 Mar 2024 14:58:28 +0000 Subject: [PATCH 01/18] fix: make StaticImage assetPrefix & pathPrefix aware --- src/components/StaticImage.test.tsx | 44 +++++++++++++++++++++++++++++ src/components/StaticImage.tsx | 20 +++++++++---- 2 files changed, 59 insertions(+), 5 deletions(-) create mode 100644 src/components/StaticImage.test.tsx diff --git a/src/components/StaticImage.test.tsx b/src/components/StaticImage.test.tsx new file mode 100644 index 0000000000..8b85c2bcd9 --- /dev/null +++ b/src/components/StaticImage.test.tsx @@ -0,0 +1,44 @@ +import React from 'react'; +import { useStaticQuery } from 'gatsby'; +import { render } from '@testing-library/react'; +import { StaticImage } from 'src/components/StaticImage'; + +describe('', () => { + describe('with assetPrefix', () => { + beforeEach(() => { + useStaticQuery.mockReturnValue({ + site: { + assetPrefix: 'http://example.com', + }, + }); + }); + + it('prepends the asset prefix to the img src', () => { + expect(__PATH_PREFIX__).toBe('/docs'); + + const { getByTestId } = render(); + const img = getByTestId('static-image'); + + expect(img).toHaveAttribute('src', 'http://example.com/docs/images/example.png'); + }); + }); + + describe('without assetPrefix', () => { + beforeEach(() => { + useStaticQuery.mockReturnValue({ + site: { + assetPrefix: undefined, + }, + }); + }); + + it('does nothing to the img src', () => { + expect(__PATH_PREFIX__).toBe('/docs'); + + const { getByTestId } = render(); + const img = getByTestId('static-image'); + + expect(img).toHaveAttribute('src', '/docs/images/example.png'); + }); + }); +}); diff --git a/src/components/StaticImage.tsx b/src/components/StaticImage.tsx index 0f55cfc6a2..344e899c23 100644 --- a/src/components/StaticImage.tsx +++ b/src/components/StaticImage.tsx @@ -1,7 +1,17 @@ -import React, { ComponentProps } from 'react'; +import React from 'react'; +import { graphql, useStaticQuery, withPrefix } from 'gatsby'; +import { ComponentProps } from 'react'; -type StaticImageProps = ComponentProps<'img'> & { - src: string; -}; +export const StaticImage = ({ src, ...attribs }: ComponentProps<'img'>) => { + const result = useStaticQuery(graphql` + query AssetPrefixQuery { + site { + assetPrefix + } + } + `); + const assetPrefix = result?.site.assetPrefix ?? ''; + const srcUrl = `${assetPrefix}${withPrefix(src)}`; -export const StaticImage = ({ src, ...attribs }: StaticImageProps) => ; + return ; +}; From de398a077a7d0207fe129eb1fbd46a0cc3080f48 Mon Sep 17 00:00:00 2001 From: Jamie Henson Date: Tue, 5 Mar 2024 15:23:12 +0000 Subject: [PATCH 02/18] chore: remove superfluous JS gatsby config --- gatsby-config.js | 9 --------- gatsby-node.ts | 6 ++++++ 2 files changed, 6 insertions(+), 9 deletions(-) delete mode 100644 gatsby-config.js diff --git a/gatsby-config.js b/gatsby-config.js deleted file mode 100644 index b93cfb37fd..0000000000 --- a/gatsby-config.js +++ /dev/null @@ -1,9 +0,0 @@ -// Source: https://www.gatsbyjs.com/docs/how-to/local-development/environment-variables/ -require('dotenv').config({ - path: `.env.${process.env.NODE_ENV}`, -}); - -// Source: https://gist.github.com/JohnAlbin/2fc05966624dffb20f4b06b4305280f9 -require('ts-node').register(); - -module.exports = require('./gatsby-config.ts'); diff --git a/gatsby-node.ts b/gatsby-node.ts index b13b091a4e..51e075ff36 100644 --- a/gatsby-node.ts +++ b/gatsby-node.ts @@ -1,3 +1,9 @@ +import dotenv from 'dotenv'; + +dotenv.config({ + path: `.env.${process.env.NODE_ENV}`, +}); + export { createPages } from './data/createPages'; export { onCreateNode, createSchemaCustomization } from './data/onCreateNode'; export { onCreateWebpackConfig } from './gatsby-overwrite-config'; From 0c520d16afea35c00ebb66be59268c5f3970acb4 Mon Sep 17 00:00:00 2001 From: Jamie Henson Date: Tue, 5 Mar 2024 15:23:33 +0000 Subject: [PATCH 03/18] chore: upgrade Gatsby deps to latest minors --- package.json | 2 +- yarn.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 52819370b6..7bd7d7019d 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "dompurify": "^2.3.4", "front-matter": "^4.0.2", "fs-extra": "^10.0.1", - "gatsby": "^5.10.0", + "gatsby": "^5.13.3", "gatsby-plugin-client-side-redirect": "^1.1.0", "gatsby-plugin-image": "^3.3.0", "gatsby-plugin-manifest": "^5.3.0", diff --git a/yarn.lock b/yarn.lock index 0a69e83b2e..75cceff8b0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8241,7 +8241,7 @@ gatsby-worker@^2.13.1: fs-extra "^11.1.1" signal-exit "^3.0.7" -gatsby@^5.10.0: +gatsby@^5.13.3: version "5.13.3" resolved "https://registry.yarnpkg.com/gatsby/-/gatsby-5.13.3.tgz#7f7dd3403944994f92dc15f6827bf4479b761e39" integrity sha512-SSnGpjswK20BQORcvTbtK8eI+W4QUG+u8rdVswB4suva6BfvTakW2wiktj7E2MdO4NjRvlgJjF5dUUncU5nldA== From cd22e6c98fca146a229baef1c652d9ed930abd22 Mon Sep 17 00:00:00 2001 From: Kenneth Kalmer Date: Wed, 6 Mar 2024 12:42:41 +0000 Subject: [PATCH 04/18] cleanup: remove webpack customizations for HEROKU_APP_NAME We no longer use this environment variable so we don't need these customisations --- gatsby-overwrite-config.ts | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/gatsby-overwrite-config.ts b/gatsby-overwrite-config.ts index 552799ef8c..a22eef3807 100644 --- a/gatsby-overwrite-config.ts +++ b/gatsby-overwrite-config.ts @@ -1,27 +1,10 @@ import { GatsbyNode } from 'gatsby'; import path from 'path'; -// src: https://github.com/chadly/gatsby-plugin-env-variables/blob/master/src/gatsby-node.js -// We need this replicated because of installation conflicts with gatsby-plugin-env-variables -const allowList = ['HEROKU_APP_NAME']; - -export const onCreateWebpackConfig: GatsbyNode['onCreateWebpackConfig'] = ({ actions, plugins, getConfig }) => { +export const onCreateWebpackConfig: GatsbyNode['onCreateWebpackConfig'] = ({ actions, getConfig }) => { const prevConfig = getConfig(); - let pluginsToAdd: unknown[] = []; - if (allowList) { - const envVars = Object.keys(process.env).reduce((acc, key) => { - if (allowList.indexOf(key) >= 0) { - acc[`process.env.${key}`] = JSON.stringify(process.env[key]); - } - return acc; - }, {}); - if (Object.keys(envVars).length) { - pluginsToAdd = [plugins.define(envVars)]; - } - } actions.replaceWebpackConfig({ ...prevConfig, - plugins: [...prevConfig.plugins, ...pluginsToAdd], resolve: { ...prevConfig.resolve, fallback: { From efb743862549734ccfa530cedd0f6b6754e0575a Mon Sep 17 00:00:00 2001 From: Kenneth Kalmer Date: Wed, 6 Mar 2024 13:51:13 +0000 Subject: [PATCH 05/18] chore: rework TopMainNavAblyLogo to import images (and use Link) --- .../TopMainNavAblyLogo.tsx | 19 +++++++++--------- .../images}/ably-docs-logo-mobile.png | Bin .../images}/ably-docs-logo.svg | 0 3 files changed, 10 insertions(+), 9 deletions(-) rename {static/images/icons => src/components/Header/TopMainNavIllustration/images}/ably-docs-logo-mobile.png (100%) rename {static/images/icons => src/components/Header/TopMainNavIllustration/images}/ably-docs-logo.svg (100%) diff --git a/src/components/Header/TopMainNavIllustration/TopMainNavAblyLogo.tsx b/src/components/Header/TopMainNavIllustration/TopMainNavAblyLogo.tsx index 87456503a3..bdcfe28045 100644 --- a/src/components/Header/TopMainNavIllustration/TopMainNavAblyLogo.tsx +++ b/src/components/Header/TopMainNavIllustration/TopMainNavAblyLogo.tsx @@ -1,14 +1,15 @@ import React from 'react'; import cn from 'classnames'; -import { StaticImage } from 'src/components/StaticImage'; +import Link from 'src/components/Link'; import { width } from './TopMainNavAblyLogo.module.css'; -export const TopMainNavAblyLogo = ({ href = '/' }: { href?: string }) => { - return ( - - - - - ); -}; +import logo from './images/ably-docs-logo.svg'; +import mobileLogo from './images/ably-docs-logo-mobile.png'; + +export const TopMainNavAblyLogo = ({ href = '/' }: { href?: string }) => ( + + + + +); diff --git a/static/images/icons/ably-docs-logo-mobile.png b/src/components/Header/TopMainNavIllustration/images/ably-docs-logo-mobile.png similarity index 100% rename from static/images/icons/ably-docs-logo-mobile.png rename to src/components/Header/TopMainNavIllustration/images/ably-docs-logo-mobile.png diff --git a/static/images/icons/ably-docs-logo.svg b/src/components/Header/TopMainNavIllustration/images/ably-docs-logo.svg similarity index 100% rename from static/images/icons/ably-docs-logo.svg rename to src/components/Header/TopMainNavIllustration/images/ably-docs-logo.svg From 2ef0ef7b1e2cc520402b4e7ac89bad428e09ab18 Mon Sep 17 00:00:00 2001 From: Kenneth Kalmer Date: Wed, 6 Mar 2024 13:59:43 +0000 Subject: [PATCH 06/18] chore: rework FooterLogo to import images (and use Link) --- .../Footer/FooterTopNav/FooterLogo.tsx | 9 +++++---- .../Footer/FooterTopNav/images/ably-logo.png | Bin 0 -> 3422 bytes 2 files changed, 5 insertions(+), 4 deletions(-) create mode 100644 src/components/Footer/FooterTopNav/images/ably-logo.png diff --git a/src/components/Footer/FooterTopNav/FooterLogo.tsx b/src/components/Footer/FooterTopNav/FooterLogo.tsx index c70b73eb59..0bc61463ac 100644 --- a/src/components/Footer/FooterTopNav/FooterLogo.tsx +++ b/src/components/Footer/FooterTopNav/FooterLogo.tsx @@ -1,8 +1,9 @@ import React from 'react'; -import { StaticImage } from '../../StaticImage'; +import Link from 'src/components/Link'; +import logo from './images/ably-logo.png'; export const FooterLogo = () => ( - - - + + Ably logo + ); diff --git a/src/components/Footer/FooterTopNav/images/ably-logo.png b/src/components/Footer/FooterTopNav/images/ably-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..5786ce564aab2c939763e21caa53bf751520f3fe GIT binary patch literal 3422 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 ASO5S3 literal 0 HcmV?d00001 From b7d49f395c7e3222301e418ef0a9b40e77e8e9cb Mon Sep 17 00:00:00 2001 From: Kenneth Kalmer Date: Wed, 6 Mar 2024 14:15:28 +0000 Subject: [PATCH 07/18] chore: rework SDKs page to import images --- src/components/SDKsPage/Card/index.tsx | 3 +- src/components/SDKsPage/data.ts | 68 ++++++++++++------ .../components/SDKsPage/images}/android.svg | 0 .../components/SDKsPage/images}/clojure.svg | 0 .../components/SDKsPage/images}/cordova.svg | 0 .../components/SDKsPage/images}/csharp.svg | 0 .../components/SDKsPage/images}/flutter.svg | 0 .../components/SDKsPage/images}/go.svg | 0 .../components/SDKsPage/images}/java.svg | 0 .../components/SDKsPage/images}/js.svg | 0 .../components/SDKsPage/images}/kotlin.svg | 0 .../components/SDKsPage/images}/laravel.svg | 0 .../SDKsPage/images}/nativescript.svg | 0 .../components/SDKsPage/images}/nodejs.svg | 0 .../SDKsPage/images}/objectivec.svg | 0 .../components/SDKsPage/images}/php.svg | 0 .../components/SDKsPage/images}/python.svg | 0 .../components/SDKsPage/images}/react.svg | 0 .../components/SDKsPage/images}/ruby.svg | 0 .../components/SDKsPage/images}/scala.svg | 0 .../components/SDKsPage/images}/sdk-hero.png | Bin .../components/SDKsPage/images}/swift.svg | 0 .../components/SDKsPage/images}/unity.svg | 0 .../components/SDKsPage/images}/xamarin.svg | 0 src/components/SDKsPage/index.tsx | 5 +- 25 files changed, 49 insertions(+), 27 deletions(-) rename {static/images/sdks => src/components/SDKsPage/images}/android.svg (100%) rename {static/images/sdks => src/components/SDKsPage/images}/clojure.svg (100%) rename {static/images/sdks => src/components/SDKsPage/images}/cordova.svg (100%) rename {static/images/sdks => src/components/SDKsPage/images}/csharp.svg (100%) rename {static/images/sdks => src/components/SDKsPage/images}/flutter.svg (100%) rename {static/images/sdks => src/components/SDKsPage/images}/go.svg (100%) rename {static/images/sdks => src/components/SDKsPage/images}/java.svg (100%) rename {static/images/sdks => src/components/SDKsPage/images}/js.svg (100%) rename {static/images/sdks => src/components/SDKsPage/images}/kotlin.svg (100%) rename {static/images/sdks => src/components/SDKsPage/images}/laravel.svg (100%) rename {static/images/sdks => src/components/SDKsPage/images}/nativescript.svg (100%) rename {static/images/sdks => src/components/SDKsPage/images}/nodejs.svg (100%) rename {static/images/sdks => src/components/SDKsPage/images}/objectivec.svg (100%) rename {static/images/sdks => src/components/SDKsPage/images}/php.svg (100%) rename {static/images/sdks => src/components/SDKsPage/images}/python.svg (100%) rename {static/images/sdks => src/components/SDKsPage/images}/react.svg (100%) rename {static/images/sdks => src/components/SDKsPage/images}/ruby.svg (100%) rename {static/images/sdks => src/components/SDKsPage/images}/scala.svg (100%) rename {static/images/sdks => src/components/SDKsPage/images}/sdk-hero.png (100%) rename {static/images/sdks => src/components/SDKsPage/images}/swift.svg (100%) rename {static/images/sdks => src/components/SDKsPage/images}/unity.svg (100%) rename {static/images/sdks => src/components/SDKsPage/images}/xamarin.svg (100%) diff --git a/src/components/SDKsPage/Card/index.tsx b/src/components/SDKsPage/Card/index.tsx index 64703f35f5..3df1158cad 100644 --- a/src/components/SDKsPage/Card/index.tsx +++ b/src/components/SDKsPage/Card/index.tsx @@ -1,6 +1,5 @@ import Icon from '@ably/ui/core/Icon'; import Link from 'src/components/Link'; -import { StaticImage } from 'src/components/StaticImage'; import { btn_sdks } from '../sdks.module.css'; type ImagesSDK = { @@ -21,7 +20,7 @@ const Card = ({ githubRepoURL, setupLink, title, image, text }: CardProps) => {

{title}

- +

{text}

diff --git a/src/components/SDKsPage/data.ts b/src/components/SDKsPage/data.ts index c09638321f..2147e2d79e 100644 --- a/src/components/SDKsPage/data.ts +++ b/src/components/SDKsPage/data.ts @@ -1,3 +1,25 @@ +import js from './images/js.svg'; +import java from './images/java.svg'; +import python from './images/python.svg'; +import react from './images/react.svg'; +import csharp from './images/csharp.svg'; +import go from './images/go.svg'; +import nodejs from './images/nodejs.svg'; +import ruby from './images/ruby.svg'; +import swift from './images/swift.svg'; +import objectivec from './images/objectivec.svg'; +import flutter from './images/flutter.svg'; +import php from './images/php.svg'; +import laravel from './images/laravel.svg'; +import android from './images/android.svg'; +import kotlin from './images/kotlin.svg'; +import unity from './images/unity.svg'; +import xamarin from './images/xamarin.svg'; +import nativescript from './images/nativescript.svg'; +import cordova from './images/cordova.svg'; +import clojure from './images/clojure.svg'; +import scala from './images/scala.svg'; + export const data = { hero: { title: 'Available SDKs', @@ -10,147 +32,147 @@ export const data = { { title: 'JavaScript', text: 'Ably SDK for JavaScript.', - image: { src: '/images/sdks/js.svg', isWide: false }, + image: { src: js, isWide: false }, githubRepoURL: 'https://github.com/ably/ably-js', setupLink: '/getting-started/setup?lang=javascript', }, { title: 'Java', text: 'Ably SDK for Java.', - image: { src: '/images/sdks/java.svg', isWide: false }, + image: { src: java, isWide: false }, githubRepoURL: 'https://github.com/ably/ably-java', setupLink: '/getting-started/setup?lang=java', }, { title: 'Python', text: 'Ably SDK for Python.', - image: { src: '/images/sdks/python.svg', isWide: false }, + image: { src: python, isWide: false }, githubRepoURL: 'https://github.com/ably/ably-python', setupLink: '/getting-started/setup?lang=python', }, { title: 'React', text: 'Ably React Hooks package.', - image: { src: '/images/sdks/react.svg', isWide: false }, + image: { src: react, isWide: false }, githubRepoURL: 'https://github.com/ably/ably-js', setupLink: '/getting-started/react', }, { title: 'C#.NET', text: 'Ably SDK for C#.NET.', - image: { src: '/images/sdks/csharp.svg', isWide: false }, + image: { src: csharp, isWide: false }, githubRepoURL: 'https://github.com/ably/ably-dotnet', setupLink: '/getting-started/setup?lang=csharp', }, { title: 'Go', text: 'Ably SDK for Go.', - image: { src: '/images/sdks/go.svg', isWide: false }, + image: { src: go, isWide: false }, githubRepoURL: 'https://github.com/ably/ably-go', setupLink: '/getting-started/setup?lang=go', }, { title: 'Node.js', text: 'Ably SDK for Node.js.', - image: { src: '/images/sdks/nodejs.svg', isWide: false }, + image: { src: nodejs, isWide: false }, githubRepoURL: 'https://github.com/ably/ably-js', setupLink: '/getting-started/setup?lang=nodejs', }, { title: 'Ruby', text: 'Ably SDK for Ruby.', - image: { src: '/images/sdks/ruby.svg', isWide: false }, + image: { src: ruby, isWide: false }, githubRepoURL: 'https://github.com/ably/ably-ruby', setupLink: '/getting-started/setup?lang=ruby', }, { title: 'Swift', text: 'Ably SDK for Swift.', - image: { src: '/images/sdks/swift.svg', isWide: false }, + image: { src: swift, isWide: false }, githubRepoURL: 'https://github.com/ably/ably-cocoa', setupLink: '/getting-started/setup?lang=swift', }, { title: 'Objective-C', text: 'Ably SDK for Objective-C.', - image: { src: '/images/sdks/objectivec.svg', isWide: false }, + image: { src: objectivec, isWide: false }, githubRepoURL: 'https://github.com/ably/ably-cocoa', setupLink: '/getting-started/setup?lang=objc', }, { title: 'Flutter', text: 'Ably SDK for Flutter.', - image: { src: '/images/sdks/flutter.svg', isWide: false }, + image: { src: flutter, isWide: false }, githubRepoURL: 'https://github.com/ably/ably-flutter', setupLink: '/getting-started/setup?lang=flutter', }, { title: 'PHP', text: 'Ably SDK for PHP.', - image: { src: '/images/sdks/php.svg', isWide: false }, + image: { src: php, isWide: false }, githubRepoURL: 'https://github.com/ably/ably-php', setupLink: '/getting-started/setup?lang=php', }, { title: 'PHP Laravel', text: 'Ably SDK for PHP Laravel.', - image: { src: '/images/sdks/laravel.svg', isWide: false }, + image: { src: laravel, isWide: false }, githubRepoURL: 'https://github.com/ably/ably-php#laravel-realtime-broadcasting', setupLink: 'https://github.com/ably/ably-php#laravel-realtime-broadcasting', }, { title: 'Android', text: 'Ably SDK for Android.', - image: { src: '/images/sdks/android.svg', isWide: false }, + image: { src: android, isWide: false }, githubRepoURL: 'https://github.com/ably/ably-java', setupLink: '/getting-started/setup?lang=java', }, { title: 'Kotlin', text: 'Ably SDK for Kotlin.', - image: { src: '/images/sdks/kotlin.svg', isWide: false }, + image: { src: kotlin, isWide: false }, githubRepoURL: 'https://github.com/ably/ably-java', setupLink: '/getting-started/setup?lang=java', }, { title: 'Unity', text: 'Ably SDK for Unity.', - image: { src: '/images/sdks/unity.svg', isWide: false }, + image: { src: unity, isWide: false }, githubRepoURL: 'https://github.com/ably/ably-dotnet', setupLink: 'https://github.com/ably/ably-dotnet/blob/main/unity/README.md', }, { title: 'Xamarin', text: 'Ably SDK for Xamarin.', - image: { src: '/images/sdks/xamarin.svg', isWide: false }, + image: { src: xamarin, isWide: false }, githubRepoURL: 'https://github.com/ably/ably-dotnet', setupLink: '/getting-started/setup?lang=csharp', }, { title: 'NativeScript', text: 'Ably SDK for NativeScript.', - image: { src: '/images/sdks/nativescript.svg', isWide: false }, + image: { src: nativescript, isWide: false }, githubRepoURL: 'https://github.com/ably/ably-js-nativescript', setupLink: 'https://github.com/ably/ably-js-nativescript#how-to-use-this-library', }, { title: 'Cordova', text: 'Ably SDK for Cordova.', - image: { src: '/images/sdks/cordova.svg', isWide: false }, + image: { src: cordova, isWide: false }, githubRepoURL: 'https://github.com/ably/ably-js', setupLink: '/getting-started/setup?lang=javascript', }, { title: 'Clojure', text: 'Ably SDK for Clojure.', - image: { src: '/images/sdks/clojure.svg', isWide: false }, + image: { src: clojure, isWide: false }, githubRepoURL: 'https://github.com/ably/ably-java', setupLink: '/getting-started/setup?lang=java', }, { title: 'Scala', text: 'Ably SDK for Scala.', - image: { src: '/images/sdks/scala.svg', isWide: false }, + image: { src: scala, isWide: false }, githubRepoURL: 'https://github.com/ably/ably-java', setupLink: '/getting-started/setup?lang=java', }, @@ -162,14 +184,14 @@ export const data = { { title: 'JavaScript', text: 'Ably Spaces SDK for JavaScript.', - image: { src: '/images/sdks/js.svg', isWide: false }, + image: { src: js, isWide: false }, githubRepoURL: 'https://github.com/ably/spaces', setupLink: '/spaces/setup', }, { title: 'React', text: 'Ably Spaces React Hooks package.', - image: { src: '/images/sdks/react.svg', isWide: false }, + image: { src: react, isWide: false }, githubRepoURL: 'https://github.com/ably/spaces', setupLink: '/spaces/react', }, diff --git a/static/images/sdks/android.svg b/src/components/SDKsPage/images/android.svg similarity index 100% rename from static/images/sdks/android.svg rename to src/components/SDKsPage/images/android.svg diff --git a/static/images/sdks/clojure.svg b/src/components/SDKsPage/images/clojure.svg similarity index 100% rename from static/images/sdks/clojure.svg rename to src/components/SDKsPage/images/clojure.svg diff --git a/static/images/sdks/cordova.svg b/src/components/SDKsPage/images/cordova.svg similarity index 100% rename from static/images/sdks/cordova.svg rename to src/components/SDKsPage/images/cordova.svg diff --git a/static/images/sdks/csharp.svg b/src/components/SDKsPage/images/csharp.svg similarity index 100% rename from static/images/sdks/csharp.svg rename to src/components/SDKsPage/images/csharp.svg diff --git a/static/images/sdks/flutter.svg b/src/components/SDKsPage/images/flutter.svg similarity index 100% rename from static/images/sdks/flutter.svg rename to src/components/SDKsPage/images/flutter.svg diff --git a/static/images/sdks/go.svg b/src/components/SDKsPage/images/go.svg similarity index 100% rename from static/images/sdks/go.svg rename to src/components/SDKsPage/images/go.svg diff --git a/static/images/sdks/java.svg b/src/components/SDKsPage/images/java.svg similarity index 100% rename from static/images/sdks/java.svg rename to src/components/SDKsPage/images/java.svg diff --git a/static/images/sdks/js.svg b/src/components/SDKsPage/images/js.svg similarity index 100% rename from static/images/sdks/js.svg rename to src/components/SDKsPage/images/js.svg diff --git a/static/images/sdks/kotlin.svg b/src/components/SDKsPage/images/kotlin.svg similarity index 100% rename from static/images/sdks/kotlin.svg rename to src/components/SDKsPage/images/kotlin.svg diff --git a/static/images/sdks/laravel.svg b/src/components/SDKsPage/images/laravel.svg similarity index 100% rename from static/images/sdks/laravel.svg rename to src/components/SDKsPage/images/laravel.svg diff --git a/static/images/sdks/nativescript.svg b/src/components/SDKsPage/images/nativescript.svg similarity index 100% rename from static/images/sdks/nativescript.svg rename to src/components/SDKsPage/images/nativescript.svg diff --git a/static/images/sdks/nodejs.svg b/src/components/SDKsPage/images/nodejs.svg similarity index 100% rename from static/images/sdks/nodejs.svg rename to src/components/SDKsPage/images/nodejs.svg diff --git a/static/images/sdks/objectivec.svg b/src/components/SDKsPage/images/objectivec.svg similarity index 100% rename from static/images/sdks/objectivec.svg rename to src/components/SDKsPage/images/objectivec.svg diff --git a/static/images/sdks/php.svg b/src/components/SDKsPage/images/php.svg similarity index 100% rename from static/images/sdks/php.svg rename to src/components/SDKsPage/images/php.svg diff --git a/static/images/sdks/python.svg b/src/components/SDKsPage/images/python.svg similarity index 100% rename from static/images/sdks/python.svg rename to src/components/SDKsPage/images/python.svg diff --git a/static/images/sdks/react.svg b/src/components/SDKsPage/images/react.svg similarity index 100% rename from static/images/sdks/react.svg rename to src/components/SDKsPage/images/react.svg diff --git a/static/images/sdks/ruby.svg b/src/components/SDKsPage/images/ruby.svg similarity index 100% rename from static/images/sdks/ruby.svg rename to src/components/SDKsPage/images/ruby.svg diff --git a/static/images/sdks/scala.svg b/src/components/SDKsPage/images/scala.svg similarity index 100% rename from static/images/sdks/scala.svg rename to src/components/SDKsPage/images/scala.svg diff --git a/static/images/sdks/sdk-hero.png b/src/components/SDKsPage/images/sdk-hero.png similarity index 100% rename from static/images/sdks/sdk-hero.png rename to src/components/SDKsPage/images/sdk-hero.png diff --git a/static/images/sdks/swift.svg b/src/components/SDKsPage/images/swift.svg similarity index 100% rename from static/images/sdks/swift.svg rename to src/components/SDKsPage/images/swift.svg diff --git a/static/images/sdks/unity.svg b/src/components/SDKsPage/images/unity.svg similarity index 100% rename from static/images/sdks/unity.svg rename to src/components/SDKsPage/images/unity.svg diff --git a/static/images/sdks/xamarin.svg b/src/components/SDKsPage/images/xamarin.svg similarity index 100% rename from static/images/sdks/xamarin.svg rename to src/components/SDKsPage/images/xamarin.svg diff --git a/src/components/SDKsPage/index.tsx b/src/components/SDKsPage/index.tsx index b095359ba0..f6c46f1171 100644 --- a/src/components/SDKsPage/index.tsx +++ b/src/components/SDKsPage/index.tsx @@ -1,8 +1,9 @@ -import { StaticImage } from '../StaticImage'; import MainSection, { Tab } from './MainSection'; import { data } from './data'; import { container } from './sdks.module.css'; +import hero from './images/sdk-hero.png'; + const Content = ({ tab }: { tab: string }) => { return ( <> @@ -12,7 +13,7 @@ const Content = ({ tab }: { tab: string }) => {

{data.hero.title}

{data.hero.subtitle}

- + From 2fd247f81800607dfd188a4ceeb4c505a0970075 Mon Sep 17 00:00:00 2001 From: Kenneth Kalmer Date: Thu, 7 Mar 2024 09:34:55 +0000 Subject: [PATCH 08/18] chore: rework HamburderMenu to import images --- .../HamburgerMenu/HamburgerButton/HamburgerIcon.tsx | 13 ++++++------- .../BackButton.tsx | 4 ++-- .../HamburgerSidebarDropdownButton.tsx | 5 +++-- .../HamburgerSidebarSubmenu.tsx | 10 +++++----- {static => src}/images/icons/bold-chevron-left.svg | 0 {static => src}/images/icons/chevron-down.svg | 0 .../images/icons/hamburger-is-closed.svg | 0 {static => src}/images/icons/hamburger-is-open.svg | 0 8 files changed, 16 insertions(+), 16 deletions(-) rename {static => src}/images/icons/bold-chevron-left.svg (100%) rename {static => src}/images/icons/chevron-down.svg (100%) rename {static => src}/images/icons/hamburger-is-closed.svg (100%) rename {static => src}/images/icons/hamburger-is-open.svg (100%) diff --git a/src/components/Header/HamburgerMenu/HamburgerButton/HamburgerIcon.tsx b/src/components/Header/HamburgerMenu/HamburgerButton/HamburgerIcon.tsx index 09733a07dc..5c98365db5 100644 --- a/src/components/Header/HamburgerMenu/HamburgerButton/HamburgerIcon.tsx +++ b/src/components/Header/HamburgerMenu/HamburgerButton/HamburgerIcon.tsx @@ -1,11 +1,10 @@ import React from 'react'; -import { StaticImage } from 'src/components/StaticImage'; + +import hamburgerOpen from 'src/images/icons/hamburger-is-open.svg'; +import hamburgerClosed from 'src/images/icons/hamburger-is-closed.svg'; const MENU_DESCRIPTION = 'Site navigation menu'; -export const HamburgerIcon = ({ isOpen }: { isOpen: boolean }) => - isOpen ? ( - - ) : ( - - ); +export const HamburgerIcon = ({ isOpen }: { isOpen: boolean }) => ( + {MENU_DESCRIPTION} +); diff --git a/src/components/Header/HamburgerMenu/HamburgerDropdown/HamburgerSidebarRenderer/HamburgerSidebarDropdownPopulatedItem/BackButton.tsx b/src/components/Header/HamburgerMenu/HamburgerDropdown/HamburgerSidebarRenderer/HamburgerSidebarDropdownPopulatedItem/BackButton.tsx index 618552930e..72f14b8991 100644 --- a/src/components/Header/HamburgerMenu/HamburgerDropdown/HamburgerSidebarRenderer/HamburgerSidebarDropdownPopulatedItem/BackButton.tsx +++ b/src/components/Header/HamburgerMenu/HamburgerDropdown/HamburgerSidebarRenderer/HamburgerSidebarDropdownPopulatedItem/BackButton.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { StaticImage } from 'src/components/StaticImage'; +import boldChevronLeft from 'src/images/icons/bold-chevron-left.svg'; export const BackButton = ({ toggle }: { toggle: () => void }) => (
void }) => ( onKeyDown={(event) => event.key === 'Enter' && toggle()} > - + Back
diff --git a/src/components/Header/HamburgerMenu/HamburgerDropdown/HamburgerSidebarRenderer/HamburgerSidebarDropdownPopulatedItem/HamburgerSidebarDropdownButton.tsx b/src/components/Header/HamburgerMenu/HamburgerDropdown/HamburgerSidebarRenderer/HamburgerSidebarDropdownPopulatedItem/HamburgerSidebarDropdownButton.tsx index 98a6106b8c..9b43de127d 100644 --- a/src/components/Header/HamburgerMenu/HamburgerDropdown/HamburgerSidebarRenderer/HamburgerSidebarDropdownPopulatedItem/HamburgerSidebarDropdownButton.tsx +++ b/src/components/Header/HamburgerMenu/HamburgerDropdown/HamburgerSidebarRenderer/HamburgerSidebarDropdownPopulatedItem/HamburgerSidebarDropdownButton.tsx @@ -1,11 +1,12 @@ import React from 'react'; -import { StaticImage } from 'src/components/StaticImage'; import { DropdownData } from '../../../../Dropdown'; import { HamburgerHasFooterContext } from '../../../hamburger-has-footer-context'; import { DispatchExpandedMenu } from '../hamburger-expanded-menu-context'; import { HamburgerSidebarItemContainer } from '../HamburgerSidebarItemContainer'; import { HamburgerSidebarDropdownMenu } from './HamburgerSidebarDropdownMenu'; +import chevronDown from 'src/images/icons/chevron-down.svg'; + export const HamburgerSidebarDropdownButton = ({ handleMenuExpansion, label, @@ -32,7 +33,7 @@ export const HamburgerSidebarDropdownButton = ({ tabIndex={0} > {label} - + ) : ( diff --git a/src/components/Header/HamburgerMenu/HamburgerDropdown/HamburgerSidebarRenderer/HamburgerSidebarSubmenu.tsx b/src/components/Header/HamburgerMenu/HamburgerDropdown/HamburgerSidebarRenderer/HamburgerSidebarSubmenu.tsx index de0033c4fc..c4d8b58f48 100644 --- a/src/components/Header/HamburgerMenu/HamburgerDropdown/HamburgerSidebarRenderer/HamburgerSidebarSubmenu.tsx +++ b/src/components/Header/HamburgerMenu/HamburgerDropdown/HamburgerSidebarRenderer/HamburgerSidebarSubmenu.tsx @@ -1,13 +1,15 @@ import React, { useEffect, useRef } from 'react'; import { SidebarData } from 'src/components'; -import { StaticImage } from 'src/components/StaticImage'; import { MAX_NESTING_LEVEL } from './constants'; import { DispatchExpandedMenu } from './hamburger-expanded-menu-context'; import { HamburgerSidebarItemContainer } from '.'; import { dataToHamburgerSidebarItem } from '.'; +import boldChevronLeft from 'src/images/icons/bold-chevron-left.svg'; +import chevronDown from 'src/images/icons/chevron-down.svg'; + const getClosedRotation = (rotation: number, isClosed: boolean) => (rotation + (isClosed ? 180 : 0)) % 360; export const HamburgerSidebarSubmenu = ({ @@ -57,12 +59,10 @@ export const HamburgerSidebarSubmenu = ({ tabIndex={0} > - {shouldDisplayRootLevelHeaderIndicator && ( - - )} + {shouldDisplayRootLevelHeaderIndicator && } {label} - {!isRootLevelHeader && } + {!isRootLevelHeader && } {!closed && content ? ( diff --git a/static/images/icons/bold-chevron-left.svg b/src/images/icons/bold-chevron-left.svg similarity index 100% rename from static/images/icons/bold-chevron-left.svg rename to src/images/icons/bold-chevron-left.svg diff --git a/static/images/icons/chevron-down.svg b/src/images/icons/chevron-down.svg similarity index 100% rename from static/images/icons/chevron-down.svg rename to src/images/icons/chevron-down.svg diff --git a/static/images/icons/hamburger-is-closed.svg b/src/images/icons/hamburger-is-closed.svg similarity index 100% rename from static/images/icons/hamburger-is-closed.svg rename to src/images/icons/hamburger-is-closed.svg diff --git a/static/images/icons/hamburger-is-open.svg b/src/images/icons/hamburger-is-open.svg similarity index 100% rename from static/images/icons/hamburger-is-open.svg rename to src/images/icons/hamburger-is-open.svg From aef62c80d7d6f7c70f0d0dd29a735b14f946c1cc Mon Sep 17 00:00:00 2001 From: Kenneth Kalmer Date: Thu, 7 Mar 2024 11:25:12 +0000 Subject: [PATCH 09/18] cleanup: remove unused icons from folder --- static/images/icon-alert.png | Bin 4769 -> 0 bytes static/images/icons/ably-docs-logo.png | Bin 2343 -> 0 bytes static/images/icons/ably-logo.svg | 23 ----------------------- static/images/icons/arrow-right.svg | 3 --- static/images/icons/external-link.svg | 3 --- static/images/icons/search-icon.svg | 8 -------- 6 files changed, 37 deletions(-) delete mode 100644 static/images/icon-alert.png delete mode 100644 static/images/icons/ably-docs-logo.png delete mode 100644 static/images/icons/ably-logo.svg delete mode 100644 static/images/icons/arrow-right.svg delete mode 100644 static/images/icons/external-link.svg delete mode 100644 static/images/icons/search-icon.svg diff --git a/static/images/icon-alert.png b/static/images/icon-alert.png deleted file mode 100644 index 983454b9548017c392f75535faeb2bb7cf210b1a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4769 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 diff --git a/static/images/icons/ably-docs-logo.png b/static/images/icons/ably-docs-logo.png deleted file mode 100644 index c020ea0875eb76e191e104f064f34100edb909e3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2343 zcmV+?3E1|DP)4TO6c~hJK(}J+ybkNyb;;D7AU8;E(B8nlL2?7<2JH=W1m_06 z!F+>q?;}O&@rjfuxrv)rAMlV?e0)^wAD1gM0Wo8|^4LQ7?w|MCj3fCjB5~ z;Qqk;R?=s?nxq7(vUX=@KbIbHx}Whl{o#+7hVmc!OyevkfX`%%FGd93LI4~5qLs3&>lBGy>uC20RA$; zCD<+nfKgu#`7K4ix%AnNK7VMf$p5VaZuY4pj%$>f(2TuHzwpR`FO_~ikzXdDy{2q? zFHMrYDIlWo5%JrgwXyKCNuNHn5cN4@<-)b!=Pd`m2 zqtU^vSp9Qw3U~mr*d-Y6pA>yP(3*Jk_qB+H_(eP^KeQwI$;Z8;CxBnLC&zbZ|DE*V z>H{rA{ud>G6aZZRI(dyiL2rF7#D>6iSP4B+nRJ=#?I zHA&U8ZFHs%3($FCbqw%0*T(y2Re$EU129|Tt;dOl-YNv`gSnx!I8J7=kCcvaOy#8PZ|&GkS{iJ*aJ1uPJr?ik5q12Y0(_Sk zaQAuyNi?|c1hl#IiB}x3UJF3m$sBO~&?0M(-Hg4)wW^<0?LGp2mHI*psS3#2=TGrY z1w2c#h5DDiI~vP@DX^fUdz(5jOuq#i*SYUvk{Ew8DeyGFxb_}`lie%zBW2kisAEb7 za36O6kgSw{_aT#hF`_T_l7G>ZCD(UH2lIRM_=e$8EPYCAffgATnGSJwsh-83J>>@j zD+DdF?ZJf;o3gKMv%>v^`iHa;w6;VLeGAwuC|AD6vodwD1#&4L^)&!R4Bc*Gl)q#7 zyNCs%z8_@kz!SkMHKhTbP@tbEAi#a3p*@v;U8L%#X}R=i*WT0tfgtnOnn|)dy6-@v ztpQq!b>+`;RO{{>E*;;|WNzBR&=!-YY^yK!aF1?W8fz+jq&9+ywB z+ybbwBxuOQQspG-no)fsXlLqY3igBy;6CpD0ZHK-Q5zob%Iwuv|BdCMssY*%{6_9% zsQ?T^3&GDFgHH-sS065`wy-`nv;xG8xqDT@Nm;eLX0oh_(cuJ6RoiiEWLMc9Eqw!1 z3Iwab6$_AlqEBirpzZX**CA*EtqyqzT3;5Fl6ADX+6=8+kX0GFUgoq-K&y?QJx<;i zkdzao%yzHi;yI8P8CCHuwT4VB1>Z8u8(YL?X-DcAb^NV>_9@w~N#hm_q)g4az)#u6 zrTp2pR_ldShqhUO#DQu9X#Hb1LyOEhX4#&PBPK!X0?cYdXe}V+eX`8i`WZk@RxL8~ zM)zcP8#uV#;MD>CpiaM&0oKZJ;JvQt(Cq%3GZ>lI!gVSyi?B;11;=XbAe3X+_?bI z+8gQ1rRvAKGwI`#1i-f<=aP@~5VWx72@rz39X`1rE3&^+8Z;d~Nc924c?^p(pezqq zjoKuqJSghWzU6^Wdf&E!7qxCUo_a~nFB8-$N@rVGAVn)v4&(wnX#m=2MFs>vg@MqzO%q?1PyXV&?*hBG4EcR`X+fJUYxN80H><{PjM`` zwb`QT*%sDV4;yLV#4^(Ex@dzpamdUU`4>nrL(03sWL2z z=CY4eYYeuXRZNuJ;|I&VlS2=HEL#EVZioCrL8mkj_G@v-P=UKt-+BTvspfJaWquOy zoP~*!1|r!%vF{DY_HH70DIQ`OsG4>ax=3dCZVRxRlr9JGC^xSs!aNhUS)Lg9v-h(s zI7C@ve0{K5k>fediYm(s`~a84B1sbYLzJ|@OQo_ ztJT1_UE`i7V1tBo8V9r%+!tmxP{z&mf((1MF1Vtmi<7EnQ){!LeI~B=8s}4%+%xXF z02{=lu+luHOm{@J1`26xeW6USy9s9dYei*3=SKt=KveZ3To^L3EhS)??0ehQ=M}_3 zEz&i`-<0i+G`v-PYrypv#66_k|Di_i=bn&7l^wTDa<8|~0&Gw~3M*3%?O)ygJy?ti zaIuSEfkpOhJodfanoLl?a+4l|HdL`?vE;i5*CA!<+#C?gwn2kJ`X35 - - - - - - - - - - - - - - - - - - - - - - diff --git a/static/images/icons/arrow-right.svg b/static/images/icons/arrow-right.svg deleted file mode 100644 index a8f3565b05..0000000000 --- a/static/images/icons/arrow-right.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/static/images/icons/external-link.svg b/static/images/icons/external-link.svg deleted file mode 100644 index 1826ba420f..0000000000 --- a/static/images/icons/external-link.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/static/images/icons/search-icon.svg b/static/images/icons/search-icon.svg deleted file mode 100644 index cb3cd45c97..0000000000 --- a/static/images/icons/search-icon.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - \ No newline at end of file From bb722218b6cba3b8a2154241d6fa419cd9d332ed Mon Sep 17 00:00:00 2001 From: Kenneth Kalmer Date: Fri, 8 Mar 2024 01:36:32 +0000 Subject: [PATCH 10/18] feat: new Image component for rendering images from GraphQL This allows us to take results from GraphQL queries and render them as images, especially useful for pages where the content is defined in YAML and references images in `src/images`. --- src/components/Image.tsx | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/components/Image.tsx diff --git a/src/components/Image.tsx b/src/components/Image.tsx new file mode 100644 index 0000000000..78f581cfba --- /dev/null +++ b/src/components/Image.tsx @@ -0,0 +1,34 @@ +import { GatsbyImage, GatsbyImageData, getImage } from 'gatsby-plugin-image'; +import { ComponentProps } from 'react'; + +export type ImageProp = { + childImageSharp: GatsbyImageData; + extension: string; + publicURL: string; +}; + +export type ImageComponentProps = ComponentProps<'img'> & { + image: ImageProp; +}; + +export const Image = ({ image, src, ...attribs }: ImageProps) => { + if (!image) { + return; + } + + if (src) { + console.warn(`You're using in an unsupported way by passing src="${src}"`); + return ; + } + + const { childImageSharp, extension, publicURL } = image ?? {}; + + if (!childImageSharp && extension === 'svg') { + return ; + } + + const { alt } = attribs ?? ''; + delete attribs.alt; + + return ; +}; From 1cc1985926326193e6f2c2b30cddf25ecea5aeb6 Mon Sep 17 00:00:00 2001 From: Kenneth Kalmer Date: Wed, 6 Mar 2024 15:54:19 +0000 Subject: [PATCH 11/18] refactor: fix image rendering for homepage --- data/yaml/page-content/homepage.yaml | 2 +- .../Homepage/BodySection/BodySection.tsx | 18 ++++++++++++++++-- .../Homepage/BodySection/Card/FeatureCard.tsx | 4 ++-- .../Homepage/BodySection/Card/SdkCard.tsx | 4 ++-- src/components/Homepage/HomepageContent.tsx | 5 +++-- {static => src}/images/homepage/pub-sub.svg | 0 {static => src}/images/homepage/sdks@2x.png | Bin {static => src}/images/homepage/spaces.svg | 0 src/pages/index.tsx | 16 ++++++++++++++-- static/images/homepage/sdks.png | Bin 84655 -> 0 bytes 10 files changed, 38 insertions(+), 11 deletions(-) rename {static => src}/images/homepage/pub-sub.svg (100%) rename {static => src}/images/homepage/sdks@2x.png (100%) rename {static => src}/images/homepage/spaces.svg (100%) delete mode 100644 static/images/homepage/sdks.png diff --git a/data/yaml/page-content/homepage.yaml b/data/yaml/page-content/homepage.yaml index 10af0ac81b..64a8a1525b 100644 --- a/data/yaml/page-content/homepage.yaml +++ b/data/yaml/page-content/homepage.yaml @@ -33,7 +33,7 @@ sections: cards: - title: SDKs content: Ably SDKs provide a consistent and idiomatic API across a variety of supported platforms. - image: 'sdks' + image: 'sdks@2x.png' type: sdk callToAction: text: View all SDKs diff --git a/src/components/Homepage/BodySection/BodySection.tsx b/src/components/Homepage/BodySection/BodySection.tsx index 6aa152bd77..0e37c6154e 100644 --- a/src/components/Homepage/BodySection/BodySection.tsx +++ b/src/components/Homepage/BodySection/BodySection.tsx @@ -1,5 +1,6 @@ import React from 'react'; import cn from 'classnames'; +import { ImageProps } from 'src/components/Image'; import { SectionProps } from '../HomepageContent'; import { BodySectionDescription } from './BodySectionDescription'; import { HeroCard } from './Card/HeroCard'; @@ -32,13 +33,25 @@ const gridGapVariants = { 4: 'gap-24', }; -export const BodySection = ({ section }: { section: SectionProps }) => { +const getImage = (images = [], name): { images: ImageProps[]; name: string } => { + const result = images.find((image) => image.base === name); + + if (name && result === undefined) { + console.warn(`Could not find image '${name}' in list`, images); + } + + return result; +}; + +export const BodySection = ({ section, images }: { section: SectionProps; images: ImageProps[] }) => { const cards = section.cards ?? []; const cardsExist = cards.length > 0; const columns = section.columns; const singleColumn = columns == 1; const bottomMargin = sectionBottomMarginVariants[section.bottomMargin]; + console.log(images); + return (
{section.title &&

{section.title}

} @@ -51,7 +64,8 @@ export const BodySection = ({ section }: { section: SectionProps }) => { > {cards.map((card, index) => { const Card = cardTypes[card.type]; - return ; + const image = getImage(images, card.image); + return ; })} )} diff --git a/src/components/Homepage/BodySection/Card/FeatureCard.tsx b/src/components/Homepage/BodySection/Card/FeatureCard.tsx index ba63995aaf..8c05068cb3 100644 --- a/src/components/Homepage/BodySection/Card/FeatureCard.tsx +++ b/src/components/Homepage/BodySection/Card/FeatureCard.tsx @@ -1,10 +1,10 @@ import { CardProps } from '../../HomepageContent'; import { Links } from '../../../ProductPage/BodySection/Card/Links'; -import { StaticImage } from '../../../StaticImage'; +import { Image } from '../../../Image'; export const FeatureCard = ({ title, content, image, links }: CardProps) => (
- +

{title}

diff --git a/src/components/Homepage/BodySection/Card/SdkCard.tsx b/src/components/Homepage/BodySection/Card/SdkCard.tsx index a36cfe34c7..53ca79d26b 100644 --- a/src/components/Homepage/BodySection/Card/SdkCard.tsx +++ b/src/components/Homepage/BodySection/Card/SdkCard.tsx @@ -1,7 +1,7 @@ import Icon from '@ably/ui/core/Icon'; import { CardProps } from '../../HomepageContent'; import Link from '../../../Link'; -import { StaticImage } from '../../../StaticImage'; +import { Image } from '../../../Image'; export const SdkCard = ({ title, content, image, callToAction }: CardProps) => (
@@ -19,6 +19,6 @@ export const SdkCard = ({ title, content, image, callToAction }: CardProps) => ( ) : null}
- +
); diff --git a/src/components/Homepage/HomepageContent.tsx b/src/components/Homepage/HomepageContent.tsx index 53ffc55824..881214e716 100644 --- a/src/components/Homepage/HomepageContent.tsx +++ b/src/components/Homepage/HomepageContent.tsx @@ -1,5 +1,6 @@ import { BodySection } from './BodySection/BodySection'; import { LinkProps, CallToActionProps } from '../ProductPage/ProductPageContent'; +import { ImageProps } from 'src/components/Image'; export type CardProps = { title: string; @@ -21,10 +22,10 @@ export type SectionProps = { cards: CardProps[]; }; -export const HomepageContent = ({ sections }: { sections: SectionProps[] }) => ( +export const HomepageContent = ({ sections, images }: { sections: SectionProps[]; images: ImageProps[] }) => (
{sections.map((section, index) => ( - + ))}
); diff --git a/static/images/homepage/pub-sub.svg b/src/images/homepage/pub-sub.svg similarity index 100% rename from static/images/homepage/pub-sub.svg rename to src/images/homepage/pub-sub.svg diff --git a/static/images/homepage/sdks@2x.png b/src/images/homepage/sdks@2x.png similarity index 100% rename from static/images/homepage/sdks@2x.png rename to src/images/homepage/sdks@2x.png diff --git a/static/images/homepage/spaces.svg b/src/images/homepage/spaces.svg similarity index 100% rename from static/images/homepage/spaces.svg rename to src/images/homepage/spaces.svg diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 156c94f606..4a9384a527 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -2,6 +2,7 @@ import { graphql, withPrefix } from 'gatsby'; import { Helmet } from 'react-helmet'; import Layout from 'src/components/Layout'; +import { ImageProps } from 'src/components/Image'; import { useSiteMetadata } from 'src/hooks/use-site-metadata'; import { HomepageContent, SectionProps } from 'src/components/Homepage/HomepageContent'; @@ -20,10 +21,11 @@ export const ABLY_MAIN_WEBSITE = process.env.GATSBY_ABLY_MAIN_WEBSITE ?? 'http:/ const IndexPage = ({ data: { pageContentYaml: { sections, meta }, + allFile: { images }, }, location: { search }, }: { - data: { pageContentYaml: { sections: SectionProps[]; meta: MetaData } }; + data: { pageContentYaml: { sections: SectionProps[]; meta: MetaData }; allFile: { images: ImageProps[] } }; location: Location; }) => { const openGraphTitle = sections[0]?.title ?? 'Ably Realtime Docs'; @@ -51,7 +53,7 @@ const IndexPage = ({ - + @@ -96,6 +98,16 @@ export const query = graphql` twitter } } + allFile(filter: { relativeDirectory: { eq: "homepage" } }) { + images: nodes { + extension + base + publicURL + childImageSharp { + gatsbyImageData + } + } + } } `; diff --git a/static/images/homepage/sdks.png b/static/images/homepage/sdks.png deleted file mode 100644 index 6d0f2bd6a380a79ceab5ae81cf86742ee56b9e1f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 84655 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 ijj}cQ%apksCjJkjMOI5x;HGo{0000@d From a256046f0810462f53fcc21cbbef932e4d4a469a Mon Sep 17 00:00:00 2001 From: Kenneth Kalmer Date: Thu, 7 Mar 2024 11:14:33 +0000 Subject: [PATCH 12/18] refactor: fix image rendering for product landing pages --- data/yaml/page-content/channels.yaml | 34 +++++++++---------- data/yaml/page-content/livesync.yaml | 4 +-- data/yaml/page-content/spaces.yaml | 8 ++--- .../ProductPage/BodySection/BodySection.tsx | 15 ++++++-- .../BodySection/Card/ExampleCard.tsx | 4 +-- .../BodySection/Card/FeatureCard.tsx | 4 +-- .../BodySection/Card/QuickstartCard.tsx | 4 +-- .../BodySection/Card/TutorialCard.tsx | 4 +-- .../ProductPage/ProductPageContent.tsx | 5 +-- .../products/channels/activity-feed.svg | 0 .../images/products/channels/all-examples.svg | 0 .../products/channels/api-references.svg | 0 .../images/products/channels/channels.svg | 0 .../products/channels/chat-priviliges.svg | 0 .../products/channels/data-visualisation.svg | 0 .../products/channels/emoji-reactions.svg | 0 .../products/channels/icon-tutorial-demo.svg | 0 .../images/products/channels/integrations.svg | 0 .../channels/message-storage-history.svg | 0 .../products/channels/metadata-stats.svg | 0 .../products/channels/presence-occupancy.svg | 0 .../products/channels/push-notifications.svg | 0 .../products/channels/quickstart-guides.svg | 0 .../products/livesync/database-connector.svg | 0 .../images/products/livesync/models-sdk.svg | 0 .../images/products/spaces/avatar-stack.svg | 0 .../products/spaces/component-locking.svg | 0 .../images/products/spaces/live-cursors.svg | 0 .../products/spaces/member-location.svg | 0 src/pages/products/channels.tsx | 19 +++++++++-- src/pages/products/livesync.tsx | 17 ++++++++-- src/pages/products/spaces.tsx | 19 +++++++++-- 32 files changed, 94 insertions(+), 43 deletions(-) rename {static => src}/images/products/channels/activity-feed.svg (100%) rename {static => src}/images/products/channels/all-examples.svg (100%) rename {static => src}/images/products/channels/api-references.svg (100%) rename {static => src}/images/products/channels/channels.svg (100%) rename {static => src}/images/products/channels/chat-priviliges.svg (100%) rename {static => src}/images/products/channels/data-visualisation.svg (100%) rename {static => src}/images/products/channels/emoji-reactions.svg (100%) rename {static => src}/images/products/channels/icon-tutorial-demo.svg (100%) rename {static => src}/images/products/channels/integrations.svg (100%) rename {static => src}/images/products/channels/message-storage-history.svg (100%) rename {static => src}/images/products/channels/metadata-stats.svg (100%) rename {static => src}/images/products/channels/presence-occupancy.svg (100%) rename {static => src}/images/products/channels/push-notifications.svg (100%) rename {static => src}/images/products/channels/quickstart-guides.svg (100%) rename {static => src}/images/products/livesync/database-connector.svg (100%) rename {static => src}/images/products/livesync/models-sdk.svg (100%) rename {static => src}/images/products/spaces/avatar-stack.svg (100%) rename {static => src}/images/products/spaces/component-locking.svg (100%) rename {static => src}/images/products/spaces/live-cursors.svg (100%) rename {static => src}/images/products/spaces/member-location.svg (100%) diff --git a/data/yaml/page-content/channels.yaml b/data/yaml/page-content/channels.yaml index ee701db15e..96d83fdeaa 100644 --- a/data/yaml/page-content/channels.yaml +++ b/data/yaml/page-content/channels.yaml @@ -22,42 +22,42 @@ sections: - title: Channels type: feature content: The core building blocks of pub/sub. Publishers send messages to a channel and subscribers of that channel receive them. - image: 'channels/channels.svg' + image: 'channels.svg' links: - text: 'Read docs' href: '/channels' - title: Presence and occupancy type: feature content: View information and metrics about clients that are attached to a channel, such as which other clients are currently “present” on the channel, or how many subscribers a channel has. - image: 'channels/presence-occupancy.svg' + image: 'presence-occupancy.svg' links: - text: 'Read docs' href: '/presence-occupancy' - title: History type: feature content: Retrieve messages that were previously sent on a channel to provide context to those who join a channel. - image: 'channels/message-storage-history.svg' + image: 'message-storage-history.svg' links: - text: 'Read docs' href: '/storage-history/history' - title: Integrations type: feature content: Integrate with an external service to send all, or a subset of messages to your database, queue, Kafka topic, serverless function, or any custom HTTP endpoint. - image: 'channels/integrations.svg' + image: 'integrations.svg' links: - text: 'Read docs' href: '/general/integrations' - title: Metadata type: feature content: Provides insight into activity related to things such as connections, channels and API requests. Use this to indicate when the last subscriber has left a channel or check if there are any subscribers on a channel before publishing to it, for example. - image: 'channels/metadata-stats.svg' + image: 'metadata-stats.svg' links: - text: 'Read docs' href: '/metadata-stats/metadata' - title: Push notifications type: feature content: Used to deliver native push notifications directly to iOS and Android devices, even when a device isn’t online or connected to Ably. - image: 'channels/push-notifications.svg' + image: 'push-notifications.svg' links: - text: 'Read docs' href: '/general/push' @@ -69,14 +69,14 @@ sections: - title: Quickstart guide type: quickstart content: Learn the basics of integrating Ably into your applications by running through the quickstart guide. - image: 'channels/quickstart-guides.svg' + image: 'quickstart-guides.svg' links: - text: 'Read quickstart guide' href: '/getting-started/quickstart' - title: API references type: quickstart content: View the API references for Ably SDKs. - image: 'channels/api-references.svg' + image: 'api-references.svg' links: - text: 'View API references' href: '/api' @@ -87,23 +87,23 @@ sections: cards: - title: Chat admin privileges type: example - image: channels/chat-priviliges.svg + image: chat-priviliges.svg link: 'https://ably.com/examples/chat-admin-privileges' - title: Emoji reactions type: example - image: 'channels/emoji-reactions.svg' + image: 'emoji-reactions.svg' link: 'https://ably.com/examples/emoji-reactions' - title: Data Visalisation type: example - image: 'channels/data-visualisation.svg' + image: 'data-visualisation.svg' link: 'https://ably.com/examples/live-charts' - title: Activity Feed type: example - image: 'channels/activity-feed.svg' + image: 'activity-feed.svg' link: 'https://ably.com/examples/activity-feed' - title: View all examples type: example - image: 'channels/all-examples.svg' + image: 'all-examples.svg' link: 'https://ably.com/examples' - title: Tutorials description: Choose from a selection of tutorials for step-by-step instructions on how to implement features. @@ -116,25 +116,25 @@ sections: cards: - title: Create a pub/sub messaging app type: tutorial - image: 'channels/icon-tutorial-demo.svg' + image: 'icon-tutorial-demo.svg' links: - text: 'View tutorial' href: 'https://ably.com/tutorials/publish-subscribe' - title: Implementing token authentication type: tutorial - image: 'channels/icon-tutorial-demo.svg' + image: 'icon-tutorial-demo.svg' links: - text: 'View tutorial' href: 'https://ably.com/tutorials/token-authentication' - title: Persist messages into Amazon S3 type: tutorial - image: 'channels/icon-tutorial-demo.svg' + image: 'icon-tutorial-demo.svg' links: - text: 'View tutorial' href: 'https://ably.com/tutorials/aws-persistence' - title: Track connected clients with presence type: tutorial - image: 'channels/icon-tutorial-demo.svg' + image: 'icon-tutorial-demo.svg' links: - text: 'View tutorial' href: 'https://ably.com/tutorials/presence' diff --git a/data/yaml/page-content/livesync.yaml b/data/yaml/page-content/livesync.yaml index 0a72439ab4..bbfa9470b4 100644 --- a/data/yaml/page-content/livesync.yaml +++ b/data/yaml/page-content/livesync.yaml @@ -26,14 +26,14 @@ sections: - title: Database Connector type: feature content: A backend service for broadcasting changes from your database in realtime. - image: 'livesync/database-connector.svg' + image: 'database-connector.svg' links: - text: 'Read docs' href: '/livesync/connector' - title: Models SDK type: feature content: A frontend library that simplifies subscribing to changes in data models. - image: 'livesync/models-sdk.svg' + image: 'models-sdk.svg' links: - text: 'Read docs' href: '/livesync/models' diff --git a/data/yaml/page-content/spaces.yaml b/data/yaml/page-content/spaces.yaml index 0ffc928f81..6f5eedc086 100644 --- a/data/yaml/page-content/spaces.yaml +++ b/data/yaml/page-content/spaces.yaml @@ -25,7 +25,7 @@ sections: - title: Avatar stack type: feature content: Display whether members are online, or have recently disconnected. - image: 'spaces/avatar-stack.svg' + image: 'avatar-stack.svg' links: - text: 'Read docs' href: '/spaces/avatar' @@ -34,7 +34,7 @@ sections: - title: Live cursors type: feature content: Show each member's cursor position as they move across a page in realtime. - image: 'spaces/live-cursors.svg' + image: 'live-cursors.svg' links: - text: 'Read docs' href: '/spaces/cursors' @@ -43,7 +43,7 @@ sections: - title: Member location type: feature content: Track where members are by highlighting the UI components they have selected. - image: 'spaces/member-location.svg' + image: 'member-location.svg' links: - text: 'Read docs' href: '/spaces/locations' @@ -52,7 +52,7 @@ sections: - title: Component locking type: feature content: Lock stateful UI components so that only a single member can edit them at once. - image: 'spaces/component-locking.svg' + image: 'component-locking.svg' links: - text: 'Read docs' href: '/spaces/locking' diff --git a/src/components/ProductPage/BodySection/BodySection.tsx b/src/components/ProductPage/BodySection/BodySection.tsx index 61ff672866..8b051fa31f 100644 --- a/src/components/ProductPage/BodySection/BodySection.tsx +++ b/src/components/ProductPage/BodySection/BodySection.tsx @@ -22,7 +22,17 @@ const betaPillStyle = { paddingTop: '0.313rem', }; -export const BodySection = ({ section }: { section: SectionProps }) => { +const getImage = (images = [], name): { images: ImageProps[]; name: string } => { + const result = images.find((image) => image.base === name); + + if (name && result === undefined) { + console.warn(`Could not find image '${name}' in list`, images); + } + + return result; +}; + +export const BodySection = ({ section, images }: { section: SectionProps; images: ImageProps[] }) => { const cards = section.cards ?? []; const cardsExist = cards.length > 0; const columns = section.columns; @@ -54,7 +64,8 @@ export const BodySection = ({ section }: { section: SectionProps }) => { > {cards.map((card, index) => { const Card = cardTypes[card.type as keyof typeof cardTypes]; - return ; + const image = getImage(images, card.image); + return ; })} )} diff --git a/src/components/ProductPage/BodySection/Card/ExampleCard.tsx b/src/components/ProductPage/BodySection/Card/ExampleCard.tsx index 0286562c9b..fbaff91558 100644 --- a/src/components/ProductPage/BodySection/Card/ExampleCard.tsx +++ b/src/components/ProductPage/BodySection/Card/ExampleCard.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { CardProps } from '../../ProductPageContent'; -import { StaticImage } from '../../../StaticImage'; +import { Image } from '../../../Image'; import Link from '../../../Link'; export const ExampleCard = ({ title, image, link, external }: CardProps) => ( @@ -9,7 +9,7 @@ export const ExampleCard = ({ title, image, link, external }: CardProps) => ( external={external} className="items-center border border-extra-light-grey rounded-lg bg-extra-light-grey flex flex-col h-full hover:border-mid-grey hover:text-cool-black group" > - +

{title}

diff --git a/src/components/ProductPage/BodySection/Card/FeatureCard.tsx b/src/components/ProductPage/BodySection/Card/FeatureCard.tsx index fae27daab3..9dcb9eb9e6 100644 --- a/src/components/ProductPage/BodySection/Card/FeatureCard.tsx +++ b/src/components/ProductPage/BodySection/Card/FeatureCard.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { CardProps } from '../../ProductPageContent'; import { Links } from './Links'; -import { StaticImage } from '../../../StaticImage'; +import { Image } from '../../../Image'; export const FeatureCard = ({ title, content, image, links }: CardProps) => (
@@ -16,6 +16,6 @@ export const FeatureCard = ({ title, content, image, links }: CardProps) => (
- + ); diff --git a/src/components/ProductPage/BodySection/Card/QuickstartCard.tsx b/src/components/ProductPage/BodySection/Card/QuickstartCard.tsx index 8a0f088a22..1511b4496e 100644 --- a/src/components/ProductPage/BodySection/Card/QuickstartCard.tsx +++ b/src/components/ProductPage/BodySection/Card/QuickstartCard.tsx @@ -1,12 +1,12 @@ import React from 'react'; import { CardProps } from '../../ProductPageContent'; -import { StaticImage } from '../../../StaticImage'; +import { Image } from '../../../Image'; import { Links } from './Links'; export const QuickstartCard = ({ title, content, image, links }: CardProps) => (
- + {`${title}`}

{title}

diff --git a/src/components/ProductPage/BodySection/Card/TutorialCard.tsx b/src/components/ProductPage/BodySection/Card/TutorialCard.tsx index 0a283521d3..4fcc8ed7ca 100644 --- a/src/components/ProductPage/BodySection/Card/TutorialCard.tsx +++ b/src/components/ProductPage/BodySection/Card/TutorialCard.tsx @@ -1,12 +1,12 @@ import React from 'react'; import { CardProps } from '../../ProductPageContent'; -import { StaticImage } from '../../../StaticImage'; +import { Image } from '../../../Image'; import { Links } from './Links'; export const TutorialCard = ({ title, image, links }: CardProps) => (
- + {title}

{title}

diff --git a/src/components/ProductPage/ProductPageContent.tsx b/src/components/ProductPage/ProductPageContent.tsx index 981286b59b..a04bc14ba6 100644 --- a/src/components/ProductPage/ProductPageContent.tsx +++ b/src/components/ProductPage/ProductPageContent.tsx @@ -1,5 +1,6 @@ import React from 'react'; import { BodySection } from './BodySection/BodySection'; +import { ImageProps } from 'src/components/Image'; export type LinkProps = { text: string; @@ -35,10 +36,10 @@ export type SectionProps = { cards: CardProps[]; }; -export const ProductPageContent = ({ sections }: { sections: SectionProps[] }) => ( +export const ProductPageContent = ({ sections, images }: { sections: SectionProps[]; images: ImageProps[] }) => (
{sections.map((section, index) => ( - + ))}
); diff --git a/static/images/products/channels/activity-feed.svg b/src/images/products/channels/activity-feed.svg similarity index 100% rename from static/images/products/channels/activity-feed.svg rename to src/images/products/channels/activity-feed.svg diff --git a/static/images/products/channels/all-examples.svg b/src/images/products/channels/all-examples.svg similarity index 100% rename from static/images/products/channels/all-examples.svg rename to src/images/products/channels/all-examples.svg diff --git a/static/images/products/channels/api-references.svg b/src/images/products/channels/api-references.svg similarity index 100% rename from static/images/products/channels/api-references.svg rename to src/images/products/channels/api-references.svg diff --git a/static/images/products/channels/channels.svg b/src/images/products/channels/channels.svg similarity index 100% rename from static/images/products/channels/channels.svg rename to src/images/products/channels/channels.svg diff --git a/static/images/products/channels/chat-priviliges.svg b/src/images/products/channels/chat-priviliges.svg similarity index 100% rename from static/images/products/channels/chat-priviliges.svg rename to src/images/products/channels/chat-priviliges.svg diff --git a/static/images/products/channels/data-visualisation.svg b/src/images/products/channels/data-visualisation.svg similarity index 100% rename from static/images/products/channels/data-visualisation.svg rename to src/images/products/channels/data-visualisation.svg diff --git a/static/images/products/channels/emoji-reactions.svg b/src/images/products/channels/emoji-reactions.svg similarity index 100% rename from static/images/products/channels/emoji-reactions.svg rename to src/images/products/channels/emoji-reactions.svg diff --git a/static/images/products/channels/icon-tutorial-demo.svg b/src/images/products/channels/icon-tutorial-demo.svg similarity index 100% rename from static/images/products/channels/icon-tutorial-demo.svg rename to src/images/products/channels/icon-tutorial-demo.svg diff --git a/static/images/products/channels/integrations.svg b/src/images/products/channels/integrations.svg similarity index 100% rename from static/images/products/channels/integrations.svg rename to src/images/products/channels/integrations.svg diff --git a/static/images/products/channels/message-storage-history.svg b/src/images/products/channels/message-storage-history.svg similarity index 100% rename from static/images/products/channels/message-storage-history.svg rename to src/images/products/channels/message-storage-history.svg diff --git a/static/images/products/channels/metadata-stats.svg b/src/images/products/channels/metadata-stats.svg similarity index 100% rename from static/images/products/channels/metadata-stats.svg rename to src/images/products/channels/metadata-stats.svg diff --git a/static/images/products/channels/presence-occupancy.svg b/src/images/products/channels/presence-occupancy.svg similarity index 100% rename from static/images/products/channels/presence-occupancy.svg rename to src/images/products/channels/presence-occupancy.svg diff --git a/static/images/products/channels/push-notifications.svg b/src/images/products/channels/push-notifications.svg similarity index 100% rename from static/images/products/channels/push-notifications.svg rename to src/images/products/channels/push-notifications.svg diff --git a/static/images/products/channels/quickstart-guides.svg b/src/images/products/channels/quickstart-guides.svg similarity index 100% rename from static/images/products/channels/quickstart-guides.svg rename to src/images/products/channels/quickstart-guides.svg diff --git a/static/images/products/livesync/database-connector.svg b/src/images/products/livesync/database-connector.svg similarity index 100% rename from static/images/products/livesync/database-connector.svg rename to src/images/products/livesync/database-connector.svg diff --git a/static/images/products/livesync/models-sdk.svg b/src/images/products/livesync/models-sdk.svg similarity index 100% rename from static/images/products/livesync/models-sdk.svg rename to src/images/products/livesync/models-sdk.svg diff --git a/static/images/products/spaces/avatar-stack.svg b/src/images/products/spaces/avatar-stack.svg similarity index 100% rename from static/images/products/spaces/avatar-stack.svg rename to src/images/products/spaces/avatar-stack.svg diff --git a/static/images/products/spaces/component-locking.svg b/src/images/products/spaces/component-locking.svg similarity index 100% rename from static/images/products/spaces/component-locking.svg rename to src/images/products/spaces/component-locking.svg diff --git a/static/images/products/spaces/live-cursors.svg b/src/images/products/spaces/live-cursors.svg similarity index 100% rename from static/images/products/spaces/live-cursors.svg rename to src/images/products/spaces/live-cursors.svg diff --git a/static/images/products/spaces/member-location.svg b/src/images/products/spaces/member-location.svg similarity index 100% rename from static/images/products/spaces/member-location.svg rename to src/images/products/spaces/member-location.svg diff --git a/src/pages/products/channels.tsx b/src/pages/products/channels.tsx index 60d336a0d0..36445a8eff 100644 --- a/src/pages/products/channels.tsx +++ b/src/pages/products/channels.tsx @@ -2,6 +2,7 @@ import { graphql, withPrefix } from 'gatsby'; import { Helmet } from 'react-helmet'; import Layout from 'src/components/Layout'; +import { ImageProps } from 'src/components/Image'; import { useSiteMetadata } from 'src/hooks/use-site-metadata'; import { ProductPageContent, SectionProps } from 'src/components/ProductPage/ProductPageContent'; @@ -17,9 +18,10 @@ type MetaData = { const IndexPage = ({ data: { pageContentYaml: { sections, meta }, + allFile: { images }, }, }: { - data: { pageContentYaml: { sections: SectionProps[]; meta: MetaData } }; + data: { pageContentYaml: { sections: SectionProps[]; meta: MetaData }; allFile: { images: ImageProps[] } }; }) => { const openGraphTitle = sections[0]?.title ?? 'Ably Realtime Docs'; const { siteUrl } = useSiteMetadata(); @@ -45,7 +47,7 @@ const IndexPage = ({ - + @@ -53,7 +55,7 @@ const IndexPage = ({ }; export const query = graphql` - query HomePageQuery { + query { pageContentYaml(name: { eq: "Channels" }) { sections { title @@ -86,6 +88,17 @@ export const query = graphql` twitter } } + allFile(filter: { relativeDirectory: { eq: "products/channels" } }) { + images: nodes { + name + extension + base + publicURL + childImageSharp { + gatsbyImageData + } + } + } } `; diff --git a/src/pages/products/livesync.tsx b/src/pages/products/livesync.tsx index 877c0a774d..2cb40da1d9 100644 --- a/src/pages/products/livesync.tsx +++ b/src/pages/products/livesync.tsx @@ -2,6 +2,7 @@ import { Helmet } from 'react-helmet'; import { graphql, withPrefix } from 'gatsby'; import Layout from 'src/components/Layout'; +import { ImageProps } from 'src/components/Image'; import { useSiteMetadata } from 'src/hooks/use-site-metadata'; import { LeftSideBar } from 'src/components/StaticQuerySidebar'; import { ProductPageContent, SectionProps } from 'src/components/ProductPage/ProductPageContent'; @@ -16,9 +17,10 @@ type MetaData = { const IndexPage = ({ data: { pageContentYaml: { sections, meta }, + allFile: { images }, }, }: { - data: { pageContentYaml: { sections: SectionProps[]; meta: MetaData } }; + data: { pageContentYaml: { sections: SectionProps[]; meta: MetaData }; allFile: { images: ImageProps[] } }; }) => { const openGraphTitle = sections[0]?.title ?? 'Ably Realtime Docs'; const { siteUrl } = useSiteMetadata(); @@ -44,7 +46,7 @@ const IndexPage = ({ - + ); @@ -86,6 +88,17 @@ export const query = graphql` twitter } } + allFile(filter: { relativeDirectory: { eq: "products/livesync" } }) { + images: nodes { + name + extension + base + publicURL + childImageSharp { + gatsbyImageData + } + } + } } `; diff --git a/src/pages/products/spaces.tsx b/src/pages/products/spaces.tsx index a41c0ddf7e..2ceeec0fd3 100644 --- a/src/pages/products/spaces.tsx +++ b/src/pages/products/spaces.tsx @@ -2,6 +2,7 @@ import { graphql, withPrefix } from 'gatsby'; import { Helmet } from 'react-helmet'; import Layout from 'src/components/Layout'; +import { ImageProps } from 'src/components/Image'; import { useSiteMetadata } from 'src/hooks/use-site-metadata'; import { ProductPageContent, SectionProps } from 'src/components/ProductPage/ProductPageContent'; @@ -17,9 +18,10 @@ type MetaData = { const IndexPage = ({ data: { pageContentYaml: { sections, meta }, + allFile: { images }, }, }: { - data: { pageContentYaml: { sections: SectionProps[]; meta: MetaData } }; + data: { pageContentYaml: { sections: SectionProps[]; meta: MetaData }; allFile: { images: ImageProps[] } }; }) => { const openGraphTitle = sections[0]?.title ?? 'Ably Realtime Docs'; const { siteUrl } = useSiteMetadata(); @@ -45,7 +47,7 @@ const IndexPage = ({ - + @@ -53,7 +55,7 @@ const IndexPage = ({ }; export const query = graphql` - query HomePageQuery { + query { pageContentYaml(name: { eq: "Spaces" }) { sections { title @@ -87,6 +89,17 @@ export const query = graphql` twitter } } + allFile(filter: { relativeDirectory: { eq: "products/spaces" } }) { + images: nodes { + name + extension + base + publicURL + childImageSharp { + gatsbyImageData + } + } + } } `; From d239fe544d00d21711107be95d70f77a37f05c13 Mon Sep 17 00:00:00 2001 From: Kenneth Kalmer Date: Fri, 8 Mar 2024 01:03:15 +0000 Subject: [PATCH 13/18] chore: use fastHash for images file source --- gatsby-config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/gatsby-config.ts b/gatsby-config.ts index 344ed3396a..289443cad9 100644 --- a/gatsby-config.ts +++ b/gatsby-config.ts @@ -48,6 +48,7 @@ export const plugins = [ options: { name: 'images', path: './src/images', + fastHash: true, }, __key: 'images', }, From 6bfe388feaa600a070a824d7f40084a62ad4898f Mon Sep 17 00:00:00 2001 From: Kenneth Kalmer Date: Fri, 8 Mar 2024 01:04:27 +0000 Subject: [PATCH 14/18] feat: new content images context for rendering images in Textile Images in textile files should now be placed in `src/images/content` and sourced from `@content`. The benefits us from getting the images properly processed by Gatsby. --- .../blocks/external-references/Img.tsx | 32 +++++++++++- src/contexts/content-images-context.tsx | 49 +++++++++++++++++++ src/templates/document.tsx | 17 ++++++- 3 files changed, 95 insertions(+), 3 deletions(-) create mode 100644 src/contexts/content-images-context.tsx diff --git a/src/components/blocks/external-references/Img.tsx b/src/components/blocks/external-references/Img.tsx index e0c0505a9b..acbb2576c2 100644 --- a/src/components/blocks/external-references/Img.tsx +++ b/src/components/blocks/external-references/Img.tsx @@ -1,23 +1,51 @@ import React, { ReactElement } from 'react'; import Zoom from 'react-medium-image-zoom'; import { StaticImage } from 'src/components/StaticImage'; +import { GatsbyImage, getImage } from 'gatsby-plugin-image'; import { HtmlComponentProps } from '../../html-component-props'; import SelfClosingHtmlBlock from '../Html/SelfClosingHtmlBlock'; +import { useContentImages } from 'src/contexts/content-images-context'; import 'react-medium-image-zoom/dist/styles.css'; import { classDialog } from './Img.module.css'; +const Wrapper = ({ children }) => ( + + {children} + +); + const Img = ({ attribs }: Pick, 'attribs'>): ReactElement => { const rawSrc = attribs?.src; + const { findImage } = useContentImages(); + + if (rawSrc.startsWith('@')) { + const image = findImage(rawSrc); + const { childImageSharp, publicURL } = image ?? {}; + + if (!childImageSharp && publicURL) { + return ( + + + + ); + } + + return ( + + + + ); + } return ( - + {rawSrc && /^\/images.*/.test(rawSrc) ? ( ) : ( SelfClosingHtmlBlock('img')({ attribs }) )} - + ); }; diff --git a/src/contexts/content-images-context.tsx b/src/contexts/content-images-context.tsx new file mode 100644 index 0000000000..bf905351f0 --- /dev/null +++ b/src/contexts/content-images-context.tsx @@ -0,0 +1,49 @@ +import { FC, ReactNode, createContext, useContext } from 'react'; +import { graphql } from 'gatsby'; +import { GatsbyImageData } from 'gatsby-plugin-image'; + +export type Image = { + childImageSharp: GatsbyImageData; + extension: string; + publicURL: string; + relativePath: string; +}; + +export const findImage: (rawSrc: string) => Image | undefined = (images: Image[]) => { + return (rawSrc): Image | undefined => { + const src = rawSrc.replace('@', ''); + + return images.find((image) => image.relativePath === src); + }; +}; + +const ContentImagesContext = createContext([]); + +export const useContentImages = () => { + const images = useContext(ContentImagesContext); + + if (images === undefined) { + throw new Error('useContentImages context must be used within a ContentImagesProvider'); + } + + return { images: images, findImage: findImage(images) }; +}; + +interface ContentImagesProviderProps { + children: ReactNode; + images: Image[]; +} + +export const ContentImagesProvider: FC = ({ children, images }) => { + return {children}; +}; + +export const query = graphql` + fragment ContentImage on File { + publicURL + relativePath + childImageSharp { + gatsbyImageData + } + } +`; diff --git a/src/templates/document.tsx b/src/templates/document.tsx index 95ffff200a..7091db04fb 100644 --- a/src/templates/document.tsx +++ b/src/templates/document.tsx @@ -2,9 +2,19 @@ import React from 'react'; import { graphql } from 'gatsby'; import Template from './base-template'; import { AblyTemplateData } from './template-data'; +import { ContentImagesProvider } from 'src/contexts/content-images-context'; const Document = (props: AblyTemplateData) => { - return