@lexingtonthemes/astro-image-inspector 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +80 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/toolbar-app.d.ts +3 -0
- package/dist/toolbar-app.d.ts.map +1 -0
- package/dist/toolbar-app.js +157 -0
- package/dist/types.d.ts +23 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/package.json +44 -0
package/README.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# @lexingtonthemes/astro-image-inspector
|
|
2
|
+
|
|
3
|
+
Astro Dev Toolbar app that lets you **inspect images on hover** during local development: see actual size, render size, loading mode, and common warnings (upscaled, oversized source, missing dimensions).
|
|
4
|
+
|
|
5
|
+
Only runs when `astro dev` is running; it does not appear in production builds.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @lexingtonthemes/astro-image-inspector --save-dev
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Setup
|
|
14
|
+
|
|
15
|
+
In `astro.config.mjs`:
|
|
16
|
+
|
|
17
|
+
```js
|
|
18
|
+
import { defineConfig } from 'astro/config';
|
|
19
|
+
import imageInspector from '@lexingtonthemes/astro-image-inspector';
|
|
20
|
+
|
|
21
|
+
export default defineConfig({
|
|
22
|
+
integrations: [
|
|
23
|
+
imageInspector(),
|
|
24
|
+
],
|
|
25
|
+
});
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
1. Run `astro dev`.
|
|
31
|
+
2. Hover near the bottom of the page to show the Dev Toolbar.
|
|
32
|
+
3. Click the **Image Inspector** icon to turn inspection on.
|
|
33
|
+
4. Hover over any `<img>` on the page to see:
|
|
34
|
+
- **src** – current image URL
|
|
35
|
+
- **natural** – intrinsic width×height
|
|
36
|
+
- **rendered** – displayed width×height
|
|
37
|
+
- **loading** – `lazy` / `eager` / `auto`
|
|
38
|
+
- **warnings** – e.g. Upscaled, Possibly oversized source, No width/height
|
|
39
|
+
|
|
40
|
+
The inspector draws a highlight around the hovered image and shows a small info panel (bottom-left by default).
|
|
41
|
+
|
|
42
|
+
## Config
|
|
43
|
+
|
|
44
|
+
| Option | Default | Description |
|
|
45
|
+
| ----------------- | ------------------ | -------------------------------------------------------- |
|
|
46
|
+
| `enabled` | `true` | Enable the Image Inspector app. |
|
|
47
|
+
| `appName` | `"Image Inspector"`| Label in the dev toolbar. |
|
|
48
|
+
| `showWarningsOnly`| `false` | *(Reserved)* Only show panel when there are warnings. |
|
|
49
|
+
| `warnOnUpscale` | `true` | *(Reserved)* Warn when image is rendered larger than source. |
|
|
50
|
+
| `warnOnOversized` | `true` | *(Reserved)* Warn when source is much larger than render size. |
|
|
51
|
+
|
|
52
|
+
Example:
|
|
53
|
+
|
|
54
|
+
```js
|
|
55
|
+
imageInspector({
|
|
56
|
+
enabled: true,
|
|
57
|
+
appName: 'Images',
|
|
58
|
+
}),
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Warnings
|
|
62
|
+
|
|
63
|
+
- **Upscaled** – Rendered size is larger than the image’s natural size.
|
|
64
|
+
- **Possibly oversized source** – Natural dimensions are more than 2× the rendered size (good candidate for resizing).
|
|
65
|
+
- **No width/height** – Missing `width`/`height` attributes (can affect layout and LCP).
|
|
66
|
+
|
|
67
|
+
## Publishing (maintainers)
|
|
68
|
+
|
|
69
|
+
This package is published under the [@lexingtonthemes](https://www.npmjs.com/settings/lexingtonthemes/packages) npm organization.
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
npm run build
|
|
73
|
+
npm publish
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Ensure you are logged in (`npm login`) and have access to the `lexingtonthemes` org.
|
|
77
|
+
|
|
78
|
+
## License
|
|
79
|
+
|
|
80
|
+
MIT © [Lexington Themes](https://www.npmjs.com/settings/lexingtonthemes/packages)
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { AstroIntegration } from "astro";
|
|
2
|
+
import type { ImageInspectorOptions } from "./types.js";
|
|
3
|
+
export type { ImageInspectorOptions };
|
|
4
|
+
export default function imageInspector(options?: ImageInspectorOptions): AstroIntegration;
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,OAAO,CAAC;AAC9C,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAExD,YAAY,EAAE,qBAAqB,EAAE,CAAC;AAEtC,MAAM,CAAC,OAAO,UAAU,cAAc,CACpC,OAAO,GAAE,qBAA0B,GAClC,gBAAgB,CAmBlB"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export default function imageInspector(options = {}) {
|
|
2
|
+
const enabled = options.enabled ?? true;
|
|
3
|
+
const appName = options.appName ?? "Image Inspector";
|
|
4
|
+
return {
|
|
5
|
+
name: "@lexingtonthemes/astro-image-inspector",
|
|
6
|
+
hooks: {
|
|
7
|
+
"astro:config:setup"({ addDevToolbarApp, command }) {
|
|
8
|
+
if (!enabled || command !== "dev")
|
|
9
|
+
return;
|
|
10
|
+
addDevToolbarApp({
|
|
11
|
+
id: "astro-image-inspector",
|
|
12
|
+
name: appName,
|
|
13
|
+
icon: "image",
|
|
14
|
+
entrypoint: new URL("./toolbar-app.js", import.meta.url),
|
|
15
|
+
});
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toolbar-app.d.ts","sourceRoot":"","sources":["../src/toolbar-app.ts"],"names":[],"mappings":";AAiKA,wBAuBG"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { defineToolbarApp } from "astro/toolbar";
|
|
2
|
+
const OVERLAY_ID = "astro-image-inspector-overlay";
|
|
3
|
+
const PANEL_ID = "astro-image-inspector-panel";
|
|
4
|
+
function getImageInfo(img) {
|
|
5
|
+
const rect = img.getBoundingClientRect();
|
|
6
|
+
const nw = img.naturalWidth || 0;
|
|
7
|
+
const nh = img.naturalHeight || 0;
|
|
8
|
+
const rw = Math.round(rect.width);
|
|
9
|
+
const rh = Math.round(rect.height);
|
|
10
|
+
const warnings = [];
|
|
11
|
+
if (nw > 0 && nh > 0) {
|
|
12
|
+
if (rw > nw || rh > nh)
|
|
13
|
+
warnings.push("Upscaled");
|
|
14
|
+
if (nw > rw * 2 || nh > rh * 2)
|
|
15
|
+
warnings.push("Possibly oversized source");
|
|
16
|
+
}
|
|
17
|
+
if (!img.hasAttribute("width") && !img.hasAttribute("height")) {
|
|
18
|
+
warnings.push("No width/height");
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
src: img.currentSrc || img.src || "",
|
|
22
|
+
naturalWidth: nw,
|
|
23
|
+
naturalHeight: nh,
|
|
24
|
+
renderedWidth: rw,
|
|
25
|
+
renderedHeight: rh,
|
|
26
|
+
loading: img.loading || "auto",
|
|
27
|
+
decoding: img.decoding || "auto",
|
|
28
|
+
warnings,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function ensureOverlay() {
|
|
32
|
+
let el = document.getElementById(OVERLAY_ID);
|
|
33
|
+
if (!el) {
|
|
34
|
+
el = document.createElement("div");
|
|
35
|
+
el.id = OVERLAY_ID;
|
|
36
|
+
el.style.cssText = `
|
|
37
|
+
position: fixed;
|
|
38
|
+
pointer-events: none;
|
|
39
|
+
border: 2px solid rgba(139, 92, 246, 0.8);
|
|
40
|
+
box-sizing: border-box;
|
|
41
|
+
z-index: 2147483646;
|
|
42
|
+
transition: top 0.05s, left 0.05s, width 0.05s, height 0.05s;
|
|
43
|
+
`;
|
|
44
|
+
document.body.appendChild(el);
|
|
45
|
+
}
|
|
46
|
+
return el;
|
|
47
|
+
}
|
|
48
|
+
function ensurePanel() {
|
|
49
|
+
let el = document.getElementById(PANEL_ID);
|
|
50
|
+
if (!el) {
|
|
51
|
+
el = document.createElement("div");
|
|
52
|
+
el.id = PANEL_ID;
|
|
53
|
+
el.style.cssText = `
|
|
54
|
+
position: fixed;
|
|
55
|
+
bottom: 60px;
|
|
56
|
+
left: 12px;
|
|
57
|
+
max-width: 360px;
|
|
58
|
+
padding: 12px;
|
|
59
|
+
background: rgba(30, 30, 40, 0.97);
|
|
60
|
+
color: #e2e8f0;
|
|
61
|
+
font-family: ui-monospace, monospace;
|
|
62
|
+
font-size: 12px;
|
|
63
|
+
border-radius: 8px;
|
|
64
|
+
box-shadow: 0 4px 20px rgba(0,0,0,0.3);
|
|
65
|
+
z-index: 2147483646;
|
|
66
|
+
pointer-events: auto;
|
|
67
|
+
line-height: 1.5;
|
|
68
|
+
`;
|
|
69
|
+
document.body.appendChild(el);
|
|
70
|
+
}
|
|
71
|
+
return el;
|
|
72
|
+
}
|
|
73
|
+
function hideOverlay() {
|
|
74
|
+
const el = document.getElementById(OVERLAY_ID);
|
|
75
|
+
if (el)
|
|
76
|
+
el.style.display = "none";
|
|
77
|
+
}
|
|
78
|
+
function hidePanel() {
|
|
79
|
+
const el = document.getElementById(PANEL_ID);
|
|
80
|
+
if (el)
|
|
81
|
+
el.style.display = "none";
|
|
82
|
+
}
|
|
83
|
+
function showOverlay(rect) {
|
|
84
|
+
const el = ensureOverlay();
|
|
85
|
+
el.style.display = "block";
|
|
86
|
+
el.style.top = `${rect.top + window.scrollY}px`;
|
|
87
|
+
el.style.left = `${rect.left + window.scrollX}px`;
|
|
88
|
+
el.style.width = `${rect.width}px`;
|
|
89
|
+
el.style.height = `${rect.height}px`;
|
|
90
|
+
el.style.borderColor = "rgba(139, 92, 246, 0.8)";
|
|
91
|
+
}
|
|
92
|
+
function showPanel(info) {
|
|
93
|
+
const el = ensurePanel();
|
|
94
|
+
el.style.display = "block";
|
|
95
|
+
const srcShort = info.src.length > 50 ? info.src.slice(0, 47) + "…" : info.src;
|
|
96
|
+
const warnText = info.warnings.length > 0
|
|
97
|
+
? `<span style="color: #fbbf24;">${info.warnings.join(", ")}</span>`
|
|
98
|
+
: "none";
|
|
99
|
+
el.innerHTML = `
|
|
100
|
+
<div><strong>src</strong> ${srcShort}</div>
|
|
101
|
+
<div><strong>natural</strong> ${info.naturalWidth}×${info.naturalHeight}</div>
|
|
102
|
+
<div><strong>rendered</strong> ${info.renderedWidth}×${info.renderedHeight}</div>
|
|
103
|
+
<div><strong>loading</strong> ${info.loading}</div>
|
|
104
|
+
<div><strong>warnings</strong> ${warnText}</div>
|
|
105
|
+
`;
|
|
106
|
+
}
|
|
107
|
+
function enableInspector(windowContent) {
|
|
108
|
+
windowContent.textContent = "Hover an image to inspect it.";
|
|
109
|
+
const onMouseOver = (event) => {
|
|
110
|
+
const target = event.target;
|
|
111
|
+
if (!(target instanceof HTMLImageElement)) {
|
|
112
|
+
hideOverlay();
|
|
113
|
+
hidePanel();
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
const info = getImageInfo(target);
|
|
117
|
+
showOverlay(target.getBoundingClientRect());
|
|
118
|
+
showPanel(info);
|
|
119
|
+
};
|
|
120
|
+
const onMouseOut = (event) => {
|
|
121
|
+
const related = event.relatedTarget;
|
|
122
|
+
if (related && document.body.contains(related))
|
|
123
|
+
return;
|
|
124
|
+
hideOverlay();
|
|
125
|
+
hidePanel();
|
|
126
|
+
};
|
|
127
|
+
document.addEventListener("mouseover", onMouseOver, true);
|
|
128
|
+
document.addEventListener("mouseout", onMouseOut, true);
|
|
129
|
+
return () => {
|
|
130
|
+
document.removeEventListener("mouseover", onMouseOver, true);
|
|
131
|
+
document.removeEventListener("mouseout", onMouseOut, true);
|
|
132
|
+
hideOverlay();
|
|
133
|
+
hidePanel();
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
export default defineToolbarApp({
|
|
137
|
+
init(canvas, app) {
|
|
138
|
+
const windowEl = document.createElement("astro-dev-toolbar-window");
|
|
139
|
+
const content = document.createElement("div");
|
|
140
|
+
content.style.cssText = "padding: 12px; font-size: 14px;";
|
|
141
|
+
content.textContent = "Toggle on and hover an image to inspect it.";
|
|
142
|
+
windowEl.appendChild(content);
|
|
143
|
+
canvas.appendChild(windowEl);
|
|
144
|
+
let cleanup = null;
|
|
145
|
+
app.onToggled(({ state }) => {
|
|
146
|
+
if (cleanup) {
|
|
147
|
+
cleanup();
|
|
148
|
+
cleanup = null;
|
|
149
|
+
}
|
|
150
|
+
if (!state) {
|
|
151
|
+
content.textContent = "Toggle on and hover an image to inspect it.";
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
cleanup = enableInspector(content);
|
|
155
|
+
});
|
|
156
|
+
},
|
|
157
|
+
});
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface ImageInspectorOptions {
|
|
2
|
+
/** Enable the Image Inspector toolbar app. Default: true */
|
|
3
|
+
enabled?: boolean;
|
|
4
|
+
/** Label shown in the dev toolbar. Default: "Image Inspector" */
|
|
5
|
+
appName?: string;
|
|
6
|
+
/** Only show the panel when there are warnings. Default: false */
|
|
7
|
+
showWarningsOnly?: boolean;
|
|
8
|
+
/** Warn when the image is rendered larger than its natural size. Default: true */
|
|
9
|
+
warnOnUpscale?: boolean;
|
|
10
|
+
/** Warn when natural size is more than 2x rendered size. Default: true */
|
|
11
|
+
warnOnOversized?: boolean;
|
|
12
|
+
}
|
|
13
|
+
export interface ImageInfo {
|
|
14
|
+
src: string;
|
|
15
|
+
naturalWidth: number;
|
|
16
|
+
naturalHeight: number;
|
|
17
|
+
renderedWidth: number;
|
|
18
|
+
renderedHeight: number;
|
|
19
|
+
loading: string;
|
|
20
|
+
decoding: string;
|
|
21
|
+
warnings: string[];
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,qBAAqB;IACpC,4DAA4D;IAC5D,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,iEAAiE;IACjE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kEAAkE;IAClE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,kFAAkF;IAClF,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,0EAA0E;IAC1E,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lexingtonthemes/astro-image-inspector",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Astro Dev Toolbar app to inspect images on hover: actual size, render size, and warnings",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"import": "./dist/index.js",
|
|
10
|
+
"default": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"README.md"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc",
|
|
19
|
+
"prepublishOnly": "npm run build"
|
|
20
|
+
},
|
|
21
|
+
"peerDependencies": {
|
|
22
|
+
"astro": ">=4.7.0"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"astro": "^5.0.0",
|
|
26
|
+
"typescript": "^5.0.0"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"astro",
|
|
30
|
+
"astro-integration",
|
|
31
|
+
"dev-toolbar",
|
|
32
|
+
"images",
|
|
33
|
+
"inspector",
|
|
34
|
+
"lexingtonthemes"
|
|
35
|
+
],
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "https://github.com/lexingtonthemes/astro-image-inspector"
|
|
39
|
+
},
|
|
40
|
+
"license": "MIT",
|
|
41
|
+
"publishConfig": {
|
|
42
|
+
"access": "public"
|
|
43
|
+
}
|
|
44
|
+
}
|