🔥 Use Directus Storage Assets Presets only for images

Block the generation of other image sizes from the URL

TODO: Block the access to root asset url as it still displays the original file
This commit is contained in:
2021-10-17 22:17:52 +02:00
parent 56857fe30d
commit f29b4c3bb0
10 changed files with 103 additions and 47 deletions

View File

@@ -1,14 +1,13 @@
<script lang="ts"> <script lang="ts">
import { getAssetUrl } from '$utils/helpers' import { getAssetUrlKey } from '$utils/helpers'
export let src: string = undefined export let src: string = undefined
export let id: string = undefined export let id: string = undefined
export let sizeKey: string = undefined
export let sizes: Sizes = undefined export let sizes: Sizes = undefined
export let width: number = sizes && sizes.medium && sizes.medium.width export let width: number = sizes && sizes.medium && sizes.medium.width
export let height: number = sizes && sizes.medium && sizes.medium.height export let height: number = sizes && sizes.medium && sizes.medium.height
export let ratio: number = undefined export let ratio: number = undefined
export let quality: number = 80
export let fit: string = 'inside'
export let alt: string export let alt: string
export let lazy: boolean = true export let lazy: boolean = true
@@ -18,6 +17,17 @@
large?: { width?: number, height?: number } large?: { width?: number, height?: number }
} }
/**
* Get asset url from size
* @description Adds the size and the format to the result
* @returns string `id?key={key}-{size}-{format}`
*/
const getSizeUrl = (key: string, size: string, format: string) => {
return getAssetUrlKey(id, `${key}-${size}-${format}`)
}
/** /**
* Define height from origin ratio if not defined * Define height from origin ratio if not defined
*/ */
@@ -44,28 +54,20 @@
*/ */
const imgWidth: number = sizes && sizes.small ? sizes.small.width : width const imgWidth: number = sizes && sizes.small ? sizes.small.width : width
const imgHeight: number = sizes && sizes.small ? sizes.small.height : height const imgHeight: number = sizes && sizes.small ? sizes.small.height : height
const imgSrc = id ? getAssetUrl(id, imgWidth, imgHeight, quality, fit, 'jpg') : src ? src : null const imgSrc = id ? getSizeUrl(sizeKey, 'small', 'jpg') : src ? src : null
</script> </script>
<picture class={$$props.class ? $$props.class : ''}> <picture class={$$props.class ? $$props.class : ''}>
<source <source
type="image/webp" type="image/webp"
srcset=" srcset="{getSizeUrl(sizeKey, 'small', 'webp')} 345w {sizes && sizes.medium ? `, ${getSizeUrl(sizeKey, 'medium', 'webp')} 768w,` : ''} {sizes && sizes.large ? `, ${getSizeUrl(sizeKey, 'large', 'webp')} 1280w` : ''}"
{getAssetUrl(id, imgWidth, imgHeight, quality, fit, 'webp')} 345w,
{sizes && sizes.medium ? `${getAssetUrl(id, sizes.medium.width, sizes.medium.height, quality, fit, 'webp')} 768w,` : ''}
{sizes && sizes.large ? `${getAssetUrl(id, sizes.large.width, sizes.large.height, quality, fit, 'webp')} 1280w,` : ''}
"
> >
<img <img
src={imgSrc} src={imgSrc}
sizes="(min-width: 1200px) 864px, (min-width: 992px) 708px, (min-width: 768px) 540px, 100%" sizes="(min-width: 1200px) 864px, (min-width: 992px) 708px, (min-width: 768px) 540px, 100%"
srcset=" srcset="{getSizeUrl(sizeKey, 'small', 'jpg')} 300w {sizes && sizes.medium ? `, ${getSizeUrl(sizeKey, 'medium', 'jpg')} 768w` : ''} {sizes && sizes.large ? `, ${getSizeUrl(sizeKey, 'large', 'jpg')} 1280w` : ''}"
{getAssetUrl(id, imgWidth, imgHeight, quality, fit)} 300w, width={imgWidth}
{sizes && sizes.medium ? `${getAssetUrl(id, sizes.medium.width, sizes.medium.height, quality, fit)} 768w,` : ''} height={imgHeight}
{sizes && sizes.large ? `${getAssetUrl(id, sizes.large.width, sizes.large.height, quality, fit)} 1280w,` : ''}
"
width={width}
height={height}
alt={alt} alt={alt}
loading={lazy ? 'lazy' : undefined} loading={lazy ? 'lazy' : undefined}
/> />

View File

@@ -55,7 +55,13 @@
on:mouseleave={handleMouseLeave} on:mouseleave={handleMouseLeave}
sveltekit-noscroll sveltekit-noscroll
> >
<Image class="location__flag" id={location.country.flag.id} alt="Flag of {location.country.name}" width={32} height={32} /> <Image
class="location__flag"
id={location.country.flag.id}
sizeKey="square"
width={32} height={32}
alt="Flag of {location.country.name}"
/>
<div class="text"> <div class="text">
<dl> <dl>
<dt class="location__name"> <dt class="location__name">
@@ -75,8 +81,10 @@
{#each location.photos as { image }, index} {#each location.photos as { image }, index}
<Image <Image
class={index === photoIndex ? 'is-visible' : null} class={index === photoIndex ? 'is-visible' : null}
id={image.id} alt={image.title} id={image.id}
width={340} height={226} quality={70} sizeKey="photo-thumbnail"
width={340} height={226}
alt={image.title}
/> />
{/each} {/each}
</div> </div>

View File

@@ -17,6 +17,7 @@
<a href={url}> <a href={url}>
<Image <Image
id={id} id={id}
sizeKey="postcard"
{sizes} {sizes}
ratio={1.5} ratio={1.5}
alt={alt} alt={alt}
@@ -25,6 +26,7 @@
{:else} {:else}
<Image <Image
id={id} id={id}
sizeKey="postcard"
{sizes} {sizes}
ratio={1.5} ratio={1.5}
alt={alt} alt={alt}

View File

@@ -20,7 +20,13 @@
<div class="frame"> <div class="frame">
<img src="/images/icons/stamp.svg" width="32" height="42" alt="Stamp"> <img src="/images/icons/stamp.svg" width="32" height="42" alt="Stamp">
</div> </div>
<Image class="flag" id={flagId} width={32} height={32} alt="Flag of {country}" /> <Image
class="flag"
id={flagId}
sizeKey="square"
width={32} height={32}
alt="Flag of {country}"
/>
</div> </div>
<ul class="postcard__address"> <ul class="postcard__address">
<li>{street}</li> <li>{street}</li>

View File

@@ -14,7 +14,15 @@
<div class="shop shadow-box-dark"> <div class="shop shadow-box-dark">
<div class="content"> <div class="content">
<div class="shop__image"> <div class="shop__image">
<Image id={shop.module_image.id} alt={shop.module_image.title} width={800} height={800} /> <Image
id={shop.module_image.id}
sizeKey="square"
sizes={{
small: { width: 400, height: 400 },
large: { width: 800, height: 800 },
}}
alt={shop.module_image.title}
/>
</div> </div>
<div class="shop__content"> <div class="shop__content">

View File

@@ -56,10 +56,11 @@
<Image <Image
id={currentPhoto.image.id} id={currentPhoto.image.id}
alt={currentPhoto.title} alt={currentPhoto.title}
sizeKey="photo-list"
sizes={{ sizes={{
small: { width: 500 }, small: { width: 500 },
medium: { width: 900 }, medium: { width: 850 },
large: { width: 1440 }, large: { width: 1280 },
}} }}
ratio={1.5} ratio={1.5}
/> />

View File

@@ -3,14 +3,14 @@
import dayjs from 'dayjs' import dayjs from 'dayjs'
import advancedFormat from 'dayjs/plugin/advancedFormat.js' import advancedFormat from 'dayjs/plugin/advancedFormat.js'
import relativeTime from 'dayjs/plugin/relativeTime.js' import relativeTime from 'dayjs/plugin/relativeTime.js'
import { getAssetUrl } from '$utils/helpers' import { getAssetUrlKey } from '$utils/helpers'
// Components // Components
import Button from '$components/atoms/Button.svelte' import Button from '$components/atoms/Button.svelte'
import IconEarth from '$components/atoms/IconEarth.svelte' import IconEarth from '$components/atoms/IconEarth.svelte'
import Image from '$components/atoms/Image.svelte' import Image from '$components/atoms/Image.svelte'
import Newsletter from '$components/organisms/Newsletter.svelte' import Newsletter from '$components/organisms/Newsletter.svelte'
export let data: any export let location: any
export let photos: any[] export let photos: any[]
export let lastUpdated: string export let lastUpdated: string
export let totalPhotos: number export let totalPhotos: number
@@ -88,9 +88,9 @@
<main class="location-page"> <main class="location-page">
<section class="location-page__intro grid" <section class="location-page__intro grid"
style=" style="
--illus-desktop: url({getAssetUrl(data.illustration_desktop.id, 1600, 1466, 90)}); --illus-desktop: url({getAssetUrlKey(location.illustration_desktop.id, 'illustration-desktop-1x')});
--illus-desktop-2x: url({getAssetUrl(data.illustration_desktop_2x.id, 3200, 2932, 90)}); --illus-desktop-2x: url({getAssetUrlKey(location.illustration_desktop_2x.id, 'illustration-desktop-2x')});
--illus-mobile: url({getAssetUrl(data.illustration_mobile.id, 1125, 2317, 90)}); --illus-mobile: url({getAssetUrlKey(location.illustration_mobile.id, 'illustration-mobile')});
" "
> >
<h1 class="title"> <h1 class="title">
@@ -99,19 +99,19 @@
<span>of</span> <span>of</span>
</span> </span>
<strong class="city"> <strong class="city">
{data.name} {location.name}
</strong> </strong>
</h1> </h1>
<div class="location-page__description grid" bind:this={descriptionEl}> <div class="location-page__description grid" bind:this={descriptionEl}>
<div class="wrap"> <div class="wrap">
<div class="text-medium"> <div class="text-medium">
Houses of {data.name} {data.description} Houses of {location.name} {location.description}
</div> </div>
<div class="info"> <div class="info">
<p class="text-label"> <p class="text-label">
Photos by Photos by
{#each data.credits as { credit_id: { name, website }}} {#each location.credits as { credit_id: { name, website }}}
{#if website} {#if website}
<a href={website} target="_blank" rel="noopener external"> <a href={website} target="_blank" rel="noopener external">
{name} {name}
@@ -159,19 +159,25 @@
</time> </time>
</a> </a>
</div> </div>
<a class="house__photo" href="/{params.country}/{params.location}/{slug}"> <div class="photo house__photo shadow-photo">
<a href="/{params.country}/{params.location}/{slug}">
<Image <Image
id={id} id={id}
sizeKey="photo-list"
sizes={{
small: { width: 500 },
medium: { width: 850 },
large: { width: 1280 },
}}
ratio={1.5}
alt="{alt}" alt="{alt}"
width={1280}
height={853}
class="shadow-photo"
/> />
<span class="house__index title-index"> <span class="house__index title-index">
{(totalPhotos - index < 10) ? '0' : ''}{totalPhotos - index} {(totalPhotos - index < 10) ? '0' : ''}{totalPhotos - index}
</span> </span>
</a> </a>
</div> </div>
</div>
{/each} {/each}
</section> </section>
@@ -199,7 +205,7 @@
{:else} {:else}
<div class="location-page__message"> <div class="location-page__message">
<p> <p>
No photos available for {data.name}.<br> No photos available for {location.name}.<br>
Come back later! Come back later!
</p> </p>
</div> </div>
@@ -268,7 +274,7 @@
return { return {
props: { props: {
data: data.location[0], location: data.location[0],
photos: data.photos, photos: data.photos,
totalPhotos: data.photos.length ? locationPhotosCount.count.id : 0, totalPhotos: data.photos.length ? locationPhotosCount.count.id : 0,
lastUpdated: data.photos.length ? data.photos[0].date_created : undefined, lastUpdated: data.photos.length ? data.photos[0].date_created : undefined,

View File

@@ -202,7 +202,13 @@
value={filterCountry} value={filterCountry}
> >
{#if countryFlagId} {#if countryFlagId}
<Image id={countryFlagId} width={26} height={26} alt="{filterCountry} flag" class="icon" /> <Image
class="icon"
id={countryFlagId}
sizeKey="square"
width={26} height={26}
alt="{filterCountry} flag"
/>
{:else} {:else}
<IconEarth class="icon" /> <IconEarth class="icon" />
{/if} {/if}
@@ -262,6 +268,7 @@
<a href="/{location.country.slug}/{location.slug}/{slug}"> <a href="/{location.country.slug}/{location.slug}/{slug}">
<Image <Image
id={image.id} id={image.id}
sizeKey="photo-grid"
sizes={{ sizes={{
small: { width: 500 }, small: { width: 500 },
medium: { width: 900 }, medium: { width: 900 },

View File

@@ -29,7 +29,12 @@
{#each issues as { issue, title, date_sent, link, thumbnail: { id } }} {#each issues as { issue, title, date_sent, link, thumbnail: { id } }}
<li class="issue"> <li class="issue">
<a href={link} target="_blank" rel="external noreferrer noopener"> <a href={link} target="_blank" rel="external noreferrer noopener">
<Image id={id} width={160} height={112} alt="Issue {issue} thumbnail" /> <Image
id={id}
sizeKey="issue-thumbnail"
width={160} height={112}
alt="Issue {issue} thumbnail"
/>
<dl> <dl>
<dt>Issue #{issue}</dt> <dt>Issue #{issue}</dt>
<dd> <dd>

View File

@@ -20,3 +20,14 @@ export const getAssetUrl = (
return `${API_URL}/assets/${id}?width=${width}&height=${height}&fit=${fit}${args}` return `${API_URL}/assets/${id}?width=${width}&height=${height}&fit=${fit}${args}`
} }
/**
* Get a Directus asset URL from parameters
*/
export const getAssetUrlKey = (
id: string,
key: string
) => {
return `${API_URL}/assets/${id}?key=${key}`
}