@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 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)
@@ -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,3 @@
1
+ declare const _default: import("astro").DevToolbarApp;
2
+ export default _default;
3
+ //# sourceMappingURL=toolbar-app.d.ts.map
@@ -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
+ });
@@ -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
+ }