Skip to content

Commit

Permalink
feat: add support for picture tag (#328)
Browse files Browse the repository at this point in the history
  • Loading branch information
ascorbic committed Oct 7, 2023
1 parent fb28be9 commit f94e508
Show file tree
Hide file tree
Showing 110 changed files with 2,599 additions and 4,688 deletions.
13 changes: 12 additions & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
{
"proseWrap": "always"
"proseWrap": "always",
"plugins": [
"prettier-plugin-astro"
],
"overrides": [
{
"files": "*.astro",
"options": {
"parser": "astro"
}
}
]
}
6 changes: 3 additions & 3 deletions docs/src/content/docs/img.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ githubRepo: "ascorbic/unpic-img"
---

A multi-framework component for responsive, high-performance images using image
CDNs
CDNs with no build step.

## Features

Expand All @@ -23,8 +23,8 @@ CDNs
browser.
- No build step or server-side rendering required for the images: uses your
existing image CDN or CMS, with no additional configuration.
- Uses [unpic](/lib) to support most image CDNs, including Cloudinary, Imgix,
and Shopify.
- Uses [unpic](/lib) to support most image CDNs and CMSs, including Cloudinary,
Imgix, Contentful and Shopify.
- Can generate a low-res background image for a blurred placeholder effect, or
use with [`@unpic/placeholder`](/placeholder/) for more options.

Expand Down
95 changes: 94 additions & 1 deletion docs/src/content/img/astro.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,20 @@ githubRepo: "ascorbic/unpic-img"
---

A high-performance, responsive image component for
[Astro](https://astro.build/).
[Astro](https://astro.build/). Automatically suppports most image CDNs and CMSs
with no build step needed.

## Installation and usage

```bash
npm install @unpic/astro
```

### `Image` component

In almost all cases you can just use the `Image` component, which will generate
an optimized, responsive image for you with automatic format detection.

```astro
---
import { Image } from "@unpic/astro";
Expand All @@ -26,3 +32,90 @@ import { Image } from "@unpic/astro";
alt="A lovely bath"
/>
```

### `Source` component

If you need to do art direction, or handle different formats in a CDN that
doesn't do auto-detection then you will need a `<picture>` element. You can use
the `Source` component to generate the correct `<source>` elements for you. The
usage depends on what you are trying to do.

#### Art direction

Art direction is where you want to use different images at different screen
sizes. For example, you might want to use a portrait image on mobile and a
landscape image on desktop. You can do this with a `<picture>` tag and the
`Source` component.

First use a normal `<picture>` tag, and then add a `Source` component for each
image you want to use. The `Source` component will generate a `<source>` tag
with the correct `srcset` and `sizes` attributes for you.

Each `Source` component takes a `media` prop, which is a media query that will
be used to determine if the image should be used. The first `Source` component
with a matching media query will be used, and the rest will be ignored. It also
takes `src`, `width`, `height` and `layout` props, which are the same as the
`Image` component. This means you can either use the same image with a different
crop or layout, or a completely different image.

You need to include an `<Image>` as the final element in the `<picture>` tag.
This is used as a fallback for browsers that don't support `<picture>`, or if
none of the media queries match. In a `<picture>` tag, any styling must be
applied to the `<img>` tag, and are applied whichever `<source>` is used.
`<source>` tags themselves cannot be styled. When using art direction you must
set the `unstyled` prop on the `<Image>` element, because otherwise the image
will have the same styling at all screen widths. Instead you need to use CSS
media queries to style the `<img>` tag.

```astro
---
import { Source } from "@unpic/astro";
---
<picture class="hero">
<!-- Large screens get a full-width hero image -->
<Source
src="https://images.unsplash.com/photo-1694406805270-f3a93e91f4b6"
media="(min-width: 601px)"
layout="fullWidth"
/>
<!-- Small screens get a constrained square image -->
<Source
src="https://images.unsplash.com/photo-1693711942336-f4f9963bd364"
media="(max-width: 600px)"
width={600}
height={600}
/>
<!-- Always include an Image as the final element -->
<Image
src="https://images.unsplash.com/photo-1693711942336-f4f9963bd364"
width={600}
height={600}
alt="Aurora"
unstyled
/>
</picture>
<style>
/* Style for all layouts */
.hero img {
object-fit: cover;
width: 100%;
}
@media (min-width: 601px) {
/* Style for full-width layout */
.hero img {
height: 600px;
}
}
@media (max-width: 600px) {
/* Style for constrained layout */
.hero img {
max-width: 600px;
/* Set the image aspect-ratio */
aspect-ratio: 1/1;
}
}
</style>
```
22 changes: 11 additions & 11 deletions docs/src/pages/[...slug].astro
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
---
import { CollectionEntry, getCollection } from 'astro:content';
import MainLayout from '../layouts/MainLayout.astro';
import { type CollectionEntry, getCollection } from "astro:content";
import MainLayout from "../layouts/MainLayout.astro";
export async function getStaticPaths() {
const docs = await getCollection('docs');
return docs.map((entry) => ({
params: {
slug: entry.slug,
},
props: entry,
}));
const docs = await getCollection("docs");
return docs.map((entry) => ({
params: {
slug: entry.slug,
},
props: entry,
}));
}
type Props = CollectionEntry<'docs'>;
type Props = CollectionEntry<"docs">;
const post = Astro.props;
const { Content, headings } = await post.render();
---

<MainLayout headings={headings} {...post.data}>
<Content />
<Content />
</MainLayout>
2 changes: 1 addition & 1 deletion docs/src/pages/img/[...slug].astro
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
import { CollectionEntry, getCollection } from "astro:content";
import { type CollectionEntry, getCollection } from "astro:content";
import MainLayout from "../../layouts/MainLayout.astro";
import { Content as Api, getHeadings } from "../../api.md";
Expand Down
1 change: 1 addition & 0 deletions examples/angular/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"@angular-devkit/build-angular": "^15.2.8",
"@angular/cli": "~15.2.8",
"@angular/compiler-cli": "^15.2.9",
"@testing-library/angular": "^14.3.0",
"@types/jasmine": "~4.3.4",
"jasmine-core": "~4.6.0",
"karma": "~6.4.2",
Expand Down
40 changes: 39 additions & 1 deletion examples/angular/src/app/app.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,44 @@
Height:
<input type="number" formControlName="height" />
</label>
<img unpic src="https://bunnyoptimizerdemo.b-cdn.net/bunny7.jpg?width=300" [width]="width" [height]="height" />
</form>

<img unpic src="https://bunnyoptimizerdemo.b-cdn.net/bunny7.jpg?width=300" [width]="width" [height]="height" />
<div>
<picture class="hero">
<!-- Large screens get a full-width hero image -->
<source unpic src="https://images.unsplash.com/photo-1694406805270-f3a93e91f4b6" media="(min-width: 601px)"
layout="fullWidth" />
<!-- Small screens get a constrained square image -->
<source unpic src="https://images.unsplash.com/photo-1693711942336-f4f9963bd364" media="(max-width: 600px)"
width="600" height="600" />
<!-- Always include an Image as the final element -->
<img unpic src="https://images.unsplash.com/photo-1693711942336-f4f9963bd364" width="600" height="600"
alt="Aurora" unstyled />
</picture>
</div>
<style>
/* Style for all layouts */
.hero img {
object-fit: cover;
width: 100%;
}

@media (min-width: 601px) {

/* Style for full-width layout */
.hero img {
height: 600px;
}
}

@media (max-width: 600px) {

/* Style for constrained layout */
.hero img {
max-width: 600px;
aspect-ratio: 1/1;
}
}
</style>
</main>
4 changes: 2 additions & 2 deletions examples/angular/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { ReactiveFormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { UnpicDirective } from '@unpic/angular';
import { UnpicModule } from '@unpic/angular';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, UnpicDirective, ReactiveFormsModule],
imports: [BrowserModule, UnpicModule, ReactiveFormsModule],
providers: [],
bootstrap: [AppComponent],
})
Expand Down
60 changes: 60 additions & 0 deletions examples/astro/src/pages/art-direction.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
---
import { Image, Source } from "@unpic/astro";
---

<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width" />
<meta name="generator" content={Astro.generator} />
<title>Astro</title>
</head>
<body>
<picture class="hero">
<!-- Large screens get a full-width hero image -->
<Source
src="https://images.unsplash.com/photo-1694406805270-f3a93e91f4b6"
media="(min-width: 601px)"
layout="fullWidth"
/>
<!-- Small screens get a constrained square image -->
<Source
src="https://images.unsplash.com/photo-1693711942336-f4f9963bd364"
media="(max-width: 600px)"
width={600}
height={600}
/>
<!-- Always include an Image as the final element -->
<Image
src="https://images.unsplash.com/photo-1693711942336-f4f9963bd364"
width={600}
height={600}
alt="Aurora"
unstyled
/>
</picture>

<style>
/* Style for all layouts */
.hero img {
object-fit: cover;
width: 100%;
}

@media (min-width: 601px) {
/* Style for full-width layout */
.hero img {
height: 600px;
}
}
@media (max-width: 600px) {
/* Style for constrained layout */
.hero img {
max-width: 600px;
aspect-ratio: 1/1;
}
}
</style>
</body>
</html>
24 changes: 24 additions & 0 deletions examples/astro/src/pages/picture.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
import { Image, Source } from "@unpic/astro";
const toy =
"https://images.ctfassets.net/yadj1kx9rmg0/wtrHxeu3zEoEce2MokCSi/cf6f68efdcf625fdc060607df0f3baef/quwowooybuqbl6ntboz3.jpg";
---

<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width" />
<meta name="generator" content={Astro.generator} />
<title>Astro</title>
</head>
<body>
<div>
<picture>
<Source src={toy} type="image/avif" width={800} height={600} />
<Source src={toy} type="image/webp" width={800} height={600} />
<Image src={toy} width={800} height={600} alt="Toy" />
</picture>
</div>
</body>
</html>
25 changes: 23 additions & 2 deletions examples/preact/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
/build
/*.log
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
1 change: 0 additions & 1 deletion examples/preact/.npmrc

This file was deleted.

19 changes: 19 additions & 0 deletions examples/preact/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Impala

<p align="center">
<img src="https://user-images.githubusercontent.com/213306/227727009-a4dc391f-efb1-4489-ad73-c3d3a327704a.png" width="100" />
</p>

Thanks for trying the pre-alpha of Impala. To get started, run the dev server:

```bash
npm run dev
```

When you're ready to build for production, run:

```bash
npm run build
```

See [the GitHub repo](https://githb.com/ascorbic/impala) for more help.
Loading

0 comments on commit f94e508

Please sign in to comment.