generated from avior/template-web-astro
feat: Move to the Picture Component
Signed-off-by: Florian Bouillon <f.bouillon@aptatio.com>
This commit is contained in:
parent
0f1a3b7cc8
commit
9a70042506
1
src/assets/pages/404/404.light.svg
Normal file
1
src/assets/pages/404/404.light.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 23 KiB |
1
src/assets/pages/404/404.svg
Normal file
1
src/assets/pages/404/404.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 23 KiB |
88
src/components/Picture.astro
Normal file
88
src/components/Picture.astro
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
---
|
||||||
|
import { getImage } from 'astro:assets'
|
||||||
|
import AstroUtils from '../libs/AstroUtils'
|
||||||
|
import { objectOmit } from '@dzeio/object-util'
|
||||||
|
|
||||||
|
const formats = [
|
||||||
|
'avif',
|
||||||
|
'webp'
|
||||||
|
]
|
||||||
|
|
||||||
|
export interface Props extends Omit<astroHTML.JSX.ImgHTMLAttributes, 'src'> {
|
||||||
|
src: ImageMetadata | string
|
||||||
|
srcDark?: ImageMetadata | string
|
||||||
|
width?: number
|
||||||
|
height?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
type PictureResult = {
|
||||||
|
format: 'new'
|
||||||
|
formats: Array<{format: string, img: Awaited<ReturnType<typeof getImage>>}>
|
||||||
|
src: Awaited<ReturnType<typeof getImage>>
|
||||||
|
} | {
|
||||||
|
format: 'raw'
|
||||||
|
src: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Result {
|
||||||
|
light: PictureResult
|
||||||
|
dark?: PictureResult | undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
async function resolvePicture(image: ImageMetadata | string): Promise<PictureResult> {
|
||||||
|
const ext = typeof image === 'string' ? image.substring(image.lastIndexOf('.')) : image.format
|
||||||
|
if (ext === 'svg') {
|
||||||
|
return {
|
||||||
|
format: 'raw',
|
||||||
|
src: typeof image === 'string' ? image : image.src
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const imageFormats: Array<{format: string, img: Awaited<ReturnType<typeof getImage>>}> = await Promise.all(
|
||||||
|
formats.map(async (it) => ({
|
||||||
|
img: await getImage({src: Astro.props.src, format: it, width: Astro.props.width, height: Astro.props.height}),
|
||||||
|
format: it
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
|
||||||
|
const orig = await getImage({src: Astro.props.src, format: ext, width: Astro.props.width, height: Astro.props.height})
|
||||||
|
|
||||||
|
return {
|
||||||
|
format: 'new',
|
||||||
|
formats: imageFormats,
|
||||||
|
src: orig
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await AstroUtils.wrap<Result>(async () => {
|
||||||
|
return {
|
||||||
|
light: await resolvePicture(Astro.props.src),
|
||||||
|
dark: Astro.props.srcDark ? await resolvePicture(Astro.props.srcDark) : undefined
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const props = objectOmit(Astro.props, 'src', 'srcDark', 'class')
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
{res.light.format === 'new' && (
|
||||||
|
<picture {...props} {...res.light.src.attributes} class:list={[res.light.src.attributes.class, Astro.props.class, {'dark:hidden': res.dark}]}>
|
||||||
|
{res.light.formats.map((it) => (
|
||||||
|
<source srcset={it.img.src} type={`image/${it.format}`} />
|
||||||
|
))}
|
||||||
|
<img src={res.light.src.src} />
|
||||||
|
</picture>
|
||||||
|
) || (
|
||||||
|
<img {...props} class:list={[Astro.props.class, {'dark:hidden': res.dark}]} src={res.light.src as string} />
|
||||||
|
)}
|
||||||
|
|
||||||
|
{res.dark && res.dark.format === 'new' && (
|
||||||
|
<picture {...props} {...res.dark.src.attributes} class:list={[res.dark.src.attributes.class, Astro.props.class, 'hidden', 'dark:block']}>
|
||||||
|
{res.dark.formats.map((it) => (
|
||||||
|
<source srcset={it.img.src} type={`image/${it.format}`} />
|
||||||
|
))}
|
||||||
|
<img src={res.dark.src.src} />
|
||||||
|
</picture>
|
||||||
|
) || (res.dark && (
|
||||||
|
<img {...props} class:list={[Astro.props.class, 'hidden', 'dark:block']} src={res.dark.src as string} />
|
||||||
|
))}
|
@ -1,42 +0,0 @@
|
|||||||
---
|
|
||||||
import { LocalImageProps, RemoteImageProps, getImage } from 'astro:assets'
|
|
||||||
import AstroUtils from '../libs/AstroUtils'
|
|
||||||
type ImageProps = LocalImageProps | RemoteImageProps
|
|
||||||
export type Props = ImageProps
|
|
||||||
|
|
||||||
const res = await AstroUtils.wrap(async () => {
|
|
||||||
const image = Astro.props.src
|
|
||||||
const ext = typeof image === 'string' ? image.substring(image.lastIndexOf('.')) : image.format
|
|
||||||
if (ext === 'svg') {
|
|
||||||
return {
|
|
||||||
format: 'raw',
|
|
||||||
props: {
|
|
||||||
...Astro.props,
|
|
||||||
src: typeof image === 'string' ? image : image.src
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const avif = await getImage({src: Astro.props.src, format: 'avif'})
|
|
||||||
const webp = await getImage({src: Astro.props.src, format: 'webp'})
|
|
||||||
const orig = await getImage({src: Astro.props.src, format: ext})
|
|
||||||
|
|
||||||
return {
|
|
||||||
format: 'new',
|
|
||||||
avif,
|
|
||||||
webp,
|
|
||||||
orig
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
{res.format === 'new' && (
|
|
||||||
<picture class:list={[res.orig!.attributes.class, Astro.props.class]}>
|
|
||||||
<source srcset={res.avif!.src} type="image/avif" />
|
|
||||||
<source srcset={res.webp!.src} type="image/webp" />
|
|
||||||
<img src={res.orig!.src} class="" {...res.orig!.attributes} />
|
|
||||||
</picture>
|
|
||||||
) || (
|
|
||||||
<img {...res.props} />
|
|
||||||
)}
|
|
@ -1,13 +1,12 @@
|
|||||||
---
|
---
|
||||||
import Logo from 'assets/logo.svg'
|
import Logo from 'assets/logo.svg'
|
||||||
import LogoDark from 'assets/logo.dark.svg'
|
import LogoDark from 'assets/logo.dark.svg'
|
||||||
import { Image } from 'astro:assets'
|
import Picture from 'components/Picture.astro'
|
||||||
---
|
---
|
||||||
|
|
||||||
<header class="bg-white/1 z-10 justify-center sm:justify-normal transition-opacity
|
<header class="bg-white/1 z-10 justify-center sm:justify-normal transition-opacity
|
||||||
fixed w-full h-20 flex items-center border-b border-slate-900/10 backdrop-blur-md">
|
fixed w-full h-20 flex items-center border-b border-slate-900/10 backdrop-blur-md">
|
||||||
<a href="/">
|
<a href="/">
|
||||||
<Image src={Logo} alt="Avior.me Logo" class="h-9 dark:hidden" />
|
<Picture src={Logo} srcDark={LogoDark} alt="Avior.me Logo" class="h-9" />
|
||||||
<Image src={LogoDark} alt="Avior.me Logo" class="h-9 hidden dark:block" />
|
|
||||||
</a>
|
</a>
|
||||||
</header>
|
</header>
|
||||||
|
@ -15,7 +15,8 @@ const projectsCollection = defineCollection({
|
|||||||
}).optional(),
|
}).optional(),
|
||||||
disabled: z.string().optional(),
|
disabled: z.string().optional(),
|
||||||
created: z.date().optional(),
|
created: z.date().optional(),
|
||||||
updated: z.date().optional()
|
updated: z.date().optional(),
|
||||||
|
techs: z.string().array().optional()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
const blogCollection = defineCollection({
|
const blogCollection = defineCollection({
|
||||||
|
@ -7,6 +7,13 @@ link:
|
|||||||
image: ./og.png
|
image: ./og.png
|
||||||
created: 2022-09-03
|
created: 2022-09-03
|
||||||
updated: 2023-07-02
|
updated: 2023-07-02
|
||||||
|
techs:
|
||||||
|
- NextJS
|
||||||
|
- Typescript
|
||||||
|
- Appwrite
|
||||||
|
- Scrapping
|
||||||
|
- Docker
|
||||||
|
- Stylus
|
||||||
---
|
---
|
||||||
|
|
||||||

|

|
||||||
|
@ -6,6 +6,14 @@ link:
|
|||||||
image: ./og.png
|
image: ./og.png
|
||||||
created: 2018-09-10
|
created: 2018-09-10
|
||||||
updated: 2021-04-29
|
updated: 2021-04-29
|
||||||
|
techs:
|
||||||
|
- NextJS
|
||||||
|
- Typescript
|
||||||
|
- MongoDB
|
||||||
|
- Firebase
|
||||||
|
- Symphony
|
||||||
|
- Docker
|
||||||
|
- Stylus
|
||||||
---
|
---
|
||||||
|
|
||||||

|

|
||||||
|
25
src/pages/404.astro
Normal file
25
src/pages/404.astro
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
---
|
||||||
|
import Layout from 'layouts/Layout.astro'
|
||||||
|
import I404 from 'assets/pages/404/404.svg'
|
||||||
|
import I404Light from 'assets/pages/404/404.light.svg'
|
||||||
|
import Button from 'components/global/Button.astro'
|
||||||
|
import ButtonLink from 'components/global/ButtonLink.astro'
|
||||||
|
import Picture from 'components/Picture.astro'
|
||||||
|
---
|
||||||
|
|
||||||
|
<Layout>
|
||||||
|
<main class="container flex flex-col gap-24 justify-center items-center md:mt-6">
|
||||||
|
<h1 class="text-6xl text-center font-bold">404 La page recherché n'existe pas :(</h1>
|
||||||
|
<Picture src={I404Light} srcDark={I404} alt="404 error image" />
|
||||||
|
<div class="flex gap-6">
|
||||||
|
<ButtonLink href="/">Retour à la page d'accueil</ButtonLink>
|
||||||
|
<Button id="back_button">Retour à la page précédente</Button>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</Layout>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(document.querySelector('button.back_button') as HTMLButtonElement).addEventListener('click', () => {
|
||||||
|
history.back()
|
||||||
|
})
|
||||||
|
</script>
|
@ -2,6 +2,7 @@
|
|||||||
import { getCollection } from 'astro:content'
|
import { getCollection } from 'astro:content'
|
||||||
import { Image } from 'astro:assets'
|
import { Image } from 'astro:assets'
|
||||||
import Layout from 'layouts/Layout.astro'
|
import Layout from 'layouts/Layout.astro'
|
||||||
|
import Picture from 'components/Picture.astro'
|
||||||
|
|
||||||
const projects = await getCollection('projects')
|
const projects = await getCollection('projects')
|
||||||
const clients = await Promise.all((await getCollection('clients')).map(async (it) => ({...it, obj: await it.render()})))
|
const clients = await Promise.all((await getCollection('clients')).map(async (it) => ({...it, obj: await it.render()})))
|
||||||
@ -18,7 +19,7 @@ const clients = await Promise.all((await getCollection('clients')).map(async (it
|
|||||||
{projects.map((it) => (
|
{projects.map((it) => (
|
||||||
<a href={`/projets/${it.slug}`} class="flex flex-col gap-4 mb-6 md:mb-0">
|
<a href={`/projets/${it.slug}`} class="flex flex-col gap-4 mb-6 md:mb-0">
|
||||||
{it.data.image && (
|
{it.data.image && (
|
||||||
<Image src={it.data.image} alt="" />
|
<Picture src={it.data.image} alt="" />
|
||||||
)}
|
)}
|
||||||
<p>{it.data.title}</p>
|
<p>{it.data.title}</p>
|
||||||
</a>
|
</a>
|
||||||
@ -43,7 +44,7 @@ const clients = await Promise.all((await getCollection('clients')).map(async (it
|
|||||||
<div class="mt-6 md:mt-0 md:grid grid-cols-2 items-center">
|
<div class="mt-6 md:mt-0 md:grid grid-cols-2 items-center">
|
||||||
<a href={client.data.site} target="_blank" rel="noreferrer nofollow" class="flex flex-col gap-4">
|
<a href={client.data.site} target="_blank" rel="noreferrer nofollow" class="flex flex-col gap-4">
|
||||||
{client.data.logo && (
|
{client.data.logo && (
|
||||||
<Image class:list={{'mx-auto': true, 'md:mx-0': true, 'dark:invert': client.data.logo.invert}} src={client.data.logo.src} height={48} alt="" />
|
<Picture class:list={{'mx-auto': true, 'md:mx-0': true, 'dark:invert': client.data.logo.invert}} src={client.data.logo.src} height={48} alt="" />
|
||||||
) || (
|
) || (
|
||||||
<div>{client.data.title}</div>
|
<div>{client.data.title}</div>
|
||||||
)}
|
)}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
---
|
---
|
||||||
import { getCollection } from 'astro:content';
|
import { getCollection } from 'astro:content';
|
||||||
|
import Picture from 'components/Picture.astro'
|
||||||
import Article from 'layouts/Article.astro'
|
import Article from 'layouts/Article.astro'
|
||||||
|
|
||||||
export const prerender = true
|
export const prerender = true
|
||||||
@ -11,16 +12,18 @@ export async function getStaticPaths() {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
// 2. For your template, you can get the entry directly from the prop
|
// 2. For your template, you can get the entry directly from the prop
|
||||||
const { entry } = Astro.props;
|
const { entry } = Astro.props as Awaited<ReturnType<typeof getStaticPaths>>[0]['props'];
|
||||||
const { Content } = await entry.render();
|
const { Content } = await entry.render();
|
||||||
---
|
---
|
||||||
<Article title={entry.data.title} image={[entry.data.image]} description={entry.data.description} link={entry.data.link} breadcrumb={[{text: 'Accueil', href: '/'}, {text: 'Projets', href: '/projets'}, {text: entry.data.title}]}>
|
<Article title={entry.data.title} image={[entry.data.image]} description={entry.data.description} link={entry.data.link} breadcrumb={[{text: 'Accueil', href: '/'}, {text: 'Projets', href: '/projets'}, {text: entry.data.title}]}>
|
||||||
<h1>{entry.data.title}</h1>
|
<h1>{entry.data.title}</h1>
|
||||||
<p class="flex justify-end font-lights my-0">
|
<p class="flex justify-end font-lights my-0">
|
||||||
|
{entry.data.created && (
|
||||||
<span>Sortie initial le {entry.data.created.toLocaleDateString('fr')}</span>
|
<span>Sortie initial le {entry.data.created.toLocaleDateString('fr')}</span>
|
||||||
|
)}
|
||||||
<!-- <p>Software updated: {entry.data.updated.toLocaleDateString()}</p> -->
|
<!-- <p>Software updated: {entry.data.updated.toLocaleDateString()}</p> -->
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<Content />
|
<Content components={{img: Picture }}/>
|
||||||
|
|
||||||
</Article>
|
</Article>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user