Skip to content

Commit

Permalink
In useOgImage() hook adds searchParams option for setting arbitrary q…
Browse files Browse the repository at this point in the history
…uery string vars to generated URL (redwoodjs#10677)

Found a missing feature while working on adding og:image support to
Cambium:

Right now setting the width or height of an og:image will add those
properties as query string variables in the URL that's generated:

    http://localhost:8910/photo.png?width=1000&height=800

But you may need variables that you'll use to modify the image you
generate. We need a way to also add these to the final URL:

    http://localhost:8910/photo.png?brightness=0.8&contrast=1.5

I'm thinking of having useOgImage() accept an additional key in its
object argument, which is an object containing all of the vars you 
want to append to the URL. This can be a simple object or an 
instance of URLSearchParams and we'll do the right thing:

    const { url } = useOgImage({ searchParams: { brightness: 0.9, contrast: 1.5 } })
// url => http://localhost:8910/photo.png?brightness=0.9&contrast=1.5
  • Loading branch information
cannikin authored May 23, 2024
1 parent ea82ca0 commit de67ddf
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 7 deletions.
6 changes: 6 additions & 0 deletions .changesets/10677.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
- Adds `searchParams` option to `useOgImage()` hook for adding arbitrary query string vars to generated URL (#10677) by @cannikin

```
const { url } = useOgImage({ searchParams: { foo: 'bar' })
console.log(url) // => http://localhost:8910/photo.png?foo=bar
```
45 changes: 44 additions & 1 deletion packages/ogimage-gen/src/hooks.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,48 @@ describe('useOgImage', () => {
expect(url).toBe('http://localhost/about.png?foo=bar')
})

test('can include additional query variables in the form of URLSearchParams', () => {
mockLocation.mockReturnValue({
origin: 'http://localhost',
pathname: '/about',
searchParams: new URLSearchParams('foo=bar'),
})

const { url } = useOgImage({
searchParams: new URLSearchParams({ baz: 'qux' }),
})

expect(url).toBe('http://localhost/about.png?foo=bar&baz=qux')
})

test('can include additional query variables in the form of an object', () => {
mockLocation.mockReturnValue({
origin: 'http://localhost',
pathname: '/about',
searchParams: new URLSearchParams('foo=bar'),
})

const { url } = useOgImage({
searchParams: { baz: 'qux' },
})

expect(url).toBe('http://localhost/about.png?foo=bar&baz=qux')
})

test('searchParams should override existing query variables', () => {
mockLocation.mockReturnValue({
origin: 'http://localhost',
pathname: '/about',
searchParams: new URLSearchParams('foo=bar'),
})

const { url } = useOgImage({
searchParams: { foo: 'baz' },
})

expect(url).toBe('http://localhost/about.png?foo=baz')
})

test('allows setting a custom extension', () => {
mockLocation.mockReturnValue({
origin: 'http://localhost',
Expand Down Expand Up @@ -166,10 +208,11 @@ describe('useOgImage', () => {
width: 1024,
height: 768,
quality: 75,
searchParams: new URLSearchParams({ baz: 'qux' }),
})

expect(url).toBe(
'http://localhost/user/1.png?foo=bar&width=1024&height=768&quality=75',
'http://localhost/user/1.png?foo=bar&baz=qux&width=1024&height=768&quality=75',
)
expect(width).toBe(1024)
expect(height).toBe(768)
Expand Down
22 changes: 16 additions & 6 deletions packages/ogimage-gen/src/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export type OgImageUrlOptions = {
width?: number
height?: number
quality?: number
searchParams?: URLSearchParams | Record<string, string>
}

export const OGIMAGE_DEFAULTS = {
Expand All @@ -15,11 +16,20 @@ export const OGIMAGE_DEFAULTS = {
}

export const useOgImage = (options?: OgImageUrlOptions) => {
const { origin, pathname, searchParams } = useLocation()
const { origin, pathname, searchParams: locationSearchParams } = useLocation()
const ext = options?.extension || OGIMAGE_DEFAULTS.extension
const width = options?.width
const height = options?.height
const quality = options?.quality
const searchParams =
options?.searchParams instanceof URLSearchParams
? options?.searchParams
: new URLSearchParams(options?.searchParams || {})
const outputSearchParams = new URLSearchParams({
...Object.fromEntries(locationSearchParams),
...Object.fromEntries(searchParams),
})

const output = [origin]

// special case if we're at the root, image is available at /index.ext
Expand All @@ -32,18 +42,18 @@ export const useOgImage = (options?: OgImageUrlOptions) => {
output.push(`.${ext}`)

if (width) {
searchParams.append('width', width.toString())
outputSearchParams.append('width', width.toString())
}
if (height) {
searchParams.append('height', height.toString())
outputSearchParams.append('height', height.toString())
}
if (quality) {
searchParams.append('quality', quality.toString())
outputSearchParams.append('quality', quality.toString())
}

// only append search params if there are any, so we don't up with a trailing `?`
if (searchParams.size) {
output.push(`?${searchParams}`)
if (outputSearchParams.size) {
output.push(`?${outputSearchParams}`)
}

return {
Expand Down

0 comments on commit de67ddf

Please sign in to comment.