From 66f7b5aa3f85df3642febadbeeb624bf2ab0b4fe Mon Sep 17 00:00:00 2001 From: Princesseuh Date: Thu, 5 Oct 2023 20:51:30 +0200 Subject: [PATCH] feat: initial commit for dev overlay --- .eslintrc.cjs | 8 + examples/dev-overlay/.codesandbox/Dockerfile | 1 + examples/dev-overlay/.gitignore | 21 ++ examples/dev-overlay/.vscode/extensions.json | 4 + examples/dev-overlay/.vscode/launch.json | 11 + examples/dev-overlay/README.md | 47 +++++ examples/dev-overlay/astro-devtools-plugin.js | 5 + examples/dev-overlay/astro.config.mjs | 11 + examples/dev-overlay/components/Component.tsx | 3 + examples/dev-overlay/package.json | 18 ++ examples/dev-overlay/public/astro-logo.png | Bin 0 -> 10367 bytes examples/dev-overlay/public/favicon.svg | 9 + examples/dev-overlay/src/pages/index.astro | 23 +++ examples/dev-overlay/tsconfig.json | 7 + packages/astro/src/@types/astro.ts | 11 + packages/astro/src/core/config/schema.ts | 6 + packages/astro/src/core/create-vite.ts | 2 + .../src/runtime/client/dev-overlay/overlay.ts | 189 ++++++++++++++++++ .../client/dev-overlay/plugins/astro.ts | 12 ++ .../client/dev-overlay/plugins/audit.ts | 121 +++++++++++ .../client/dev-overlay/plugins/xray.ts | 84 ++++++++ .../runtime/client/dev-overlay/ui-toolkit.ts | 148 ++++++++++++++ .../src/vite-plugin-astro-server/route.ts | 7 + .../vite-plugin-dev-tools.ts | 31 +++ pnpm-lock.yaml | 21 +- tsconfig.eslint.json | 1 + 26 files changed, 787 insertions(+), 14 deletions(-) create mode 100644 examples/dev-overlay/.codesandbox/Dockerfile create mode 100644 examples/dev-overlay/.gitignore create mode 100644 examples/dev-overlay/.vscode/extensions.json create mode 100644 examples/dev-overlay/.vscode/launch.json create mode 100644 examples/dev-overlay/README.md create mode 100644 examples/dev-overlay/astro-devtools-plugin.js create mode 100644 examples/dev-overlay/astro.config.mjs create mode 100644 examples/dev-overlay/components/Component.tsx create mode 100644 examples/dev-overlay/package.json create mode 100644 examples/dev-overlay/public/astro-logo.png create mode 100644 examples/dev-overlay/public/favicon.svg create mode 100644 examples/dev-overlay/src/pages/index.astro create mode 100644 examples/dev-overlay/tsconfig.json create mode 100644 packages/astro/src/runtime/client/dev-overlay/overlay.ts create mode 100644 packages/astro/src/runtime/client/dev-overlay/plugins/astro.ts create mode 100644 packages/astro/src/runtime/client/dev-overlay/plugins/audit.ts create mode 100644 packages/astro/src/runtime/client/dev-overlay/plugins/xray.ts create mode 100644 packages/astro/src/runtime/client/dev-overlay/ui-toolkit.ts create mode 100644 packages/astro/src/vite-plugin-dev-tools/vite-plugin-dev-tools.ts diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 750f56aba..16d3d96c7 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -1,5 +1,7 @@ +// eslint-disable-next-line @typescript-eslint/no-var-requires const { builtinModules } = require('module'); +/** @type {import("@types/eslint").Linter.Config} */ module.exports = { extends: [ 'plugin:@typescript-eslint/recommended-type-checked', @@ -69,6 +71,12 @@ module.exports = { ], }, }, + { + files: ['packages/astro/src/runtime/client/**/*.ts'], + env: { + browser: true, + }, + }, { files: ['packages/**/test/*.js', 'packages/**/*.js'], env: { diff --git a/examples/dev-overlay/.codesandbox/Dockerfile b/examples/dev-overlay/.codesandbox/Dockerfile new file mode 100644 index 000000000..c3b5c81a1 --- /dev/null +++ b/examples/dev-overlay/.codesandbox/Dockerfile @@ -0,0 +1 @@ +FROM node:18-bullseye diff --git a/examples/dev-overlay/.gitignore b/examples/dev-overlay/.gitignore new file mode 100644 index 000000000..6240da8b1 --- /dev/null +++ b/examples/dev-overlay/.gitignore @@ -0,0 +1,21 @@ +# build output +dist/ +# generated types +.astro/ + +# dependencies +node_modules/ + +# logs +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + + +# environment variables +.env +.env.production + +# macOS-specific files +.DS_Store diff --git a/examples/dev-overlay/.vscode/extensions.json b/examples/dev-overlay/.vscode/extensions.json new file mode 100644 index 000000000..22a15055d --- /dev/null +++ b/examples/dev-overlay/.vscode/extensions.json @@ -0,0 +1,4 @@ +{ + "recommendations": ["astro-build.astro-vscode"], + "unwantedRecommendations": [] +} diff --git a/examples/dev-overlay/.vscode/launch.json b/examples/dev-overlay/.vscode/launch.json new file mode 100644 index 000000000..d64220976 --- /dev/null +++ b/examples/dev-overlay/.vscode/launch.json @@ -0,0 +1,11 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "command": "./node_modules/.bin/astro dev", + "name": "Development server", + "request": "launch", + "type": "node-terminal" + } + ] +} diff --git a/examples/dev-overlay/README.md b/examples/dev-overlay/README.md new file mode 100644 index 000000000..906665df0 --- /dev/null +++ b/examples/dev-overlay/README.md @@ -0,0 +1,47 @@ +# Astro Starter Kit: Dev Overlay Showcase + +```sh +npm create astro@latest -- --template dev-overlay +``` + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/withastro/astro/tree/latest/examples/minimal) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/withastro/astro/tree/latest/examples/minimal) +[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/withastro/astro?devcontainer_path=.devcontainer/minimal/devcontainer.json) + +> 🧑‍🚀 **Seasoned astronaut?** Delete this file. Have fun! + +## 🚀 Project Structure + +Inside of your Astro project, you'll see the following folders and files: + +```text +/ +├── public/ +├── src/ +│ └── pages/ +│ └── index.astro +└── package.json +``` + +Astro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page is exposed as a route based on its file name. + +There's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components. + +Any static assets, like images, can be placed in the `public/` directory. + +## 🧞 Commands + +All commands are run from the root of the project, from a terminal: + +| Command | Action | +| :------------------------ | :----------------------------------------------- | +| `npm install` | Installs dependencies | +| `npm run dev` | Starts local dev server at `localhost:4321` | +| `npm run build` | Build your production site to `./dist/` | +| `npm run preview` | Preview your build locally, before deploying | +| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` | +| `npm run astro -- --help` | Get help using the Astro CLI | + +## 👀 Want to learn more? + +Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat). diff --git a/examples/dev-overlay/astro-devtools-plugin.js b/examples/dev-overlay/astro-devtools-plugin.js new file mode 100644 index 000000000..409d4d1f0 --- /dev/null +++ b/examples/dev-overlay/astro-devtools-plugin.js @@ -0,0 +1,5 @@ +export default { + id: 'custom', + title: "I'm a plugin!", + icon: '', +}; diff --git a/examples/dev-overlay/astro.config.mjs b/examples/dev-overlay/astro.config.mjs new file mode 100644 index 000000000..8947c2b60 --- /dev/null +++ b/examples/dev-overlay/astro.config.mjs @@ -0,0 +1,11 @@ +import { defineConfig } from 'astro/config'; + +import solidJs from "@astrojs/solid-js"; + +// https://astro.build/config +export default defineConfig({ + devTools: { + plugins: ['./astro-devtools-plugin.js'] + }, + integrations: [solidJs()] +}); \ No newline at end of file diff --git a/examples/dev-overlay/components/Component.tsx b/examples/dev-overlay/components/Component.tsx new file mode 100644 index 000000000..a482e0c64 --- /dev/null +++ b/examples/dev-overlay/components/Component.tsx @@ -0,0 +1,3 @@ +export function HelloWorld(props: { text: string }) { + return <>
{props.text}

; +} diff --git a/examples/dev-overlay/package.json b/examples/dev-overlay/package.json new file mode 100644 index 000000000..fc66654c6 --- /dev/null +++ b/examples/dev-overlay/package.json @@ -0,0 +1,18 @@ +{ + "name": "@example/dev-overlay", + "type": "module", + "version": "0.0.1", + "private": true, + "scripts": { + "dev": "astro dev", + "start": "astro dev", + "build": "astro build", + "preview": "astro preview", + "astro": "astro" + }, + "dependencies": { + "astro": "^3.2.0", + "@astrojs/solid-js": "^3.0.1", + "solid-js": "^1.7.11" + } +} diff --git a/examples/dev-overlay/public/astro-logo.png b/examples/dev-overlay/public/astro-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..300e7633a71e023cc7191ac2f54c1c0b6ecf235a GIT binary patch literal 10367 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 F|9{*r*t!4! literal 0 HcmV?d00001 diff --git a/examples/dev-overlay/public/favicon.svg b/examples/dev-overlay/public/favicon.svg new file mode 100644 index 000000000..f157bd1c5 --- /dev/null +++ b/examples/dev-overlay/public/favicon.svg @@ -0,0 +1,9 @@ + + + + diff --git a/examples/dev-overlay/src/pages/index.astro b/examples/dev-overlay/src/pages/index.astro new file mode 100644 index 000000000..efdbd621e --- /dev/null +++ b/examples/dev-overlay/src/pages/index.astro @@ -0,0 +1,23 @@ +--- +import { HelloWorld } from '../../components/Component'; +--- + + + + + + + + Astro + + +

Astro

+ +

Audit

+ + +

Components

+ + + + diff --git a/examples/dev-overlay/tsconfig.json b/examples/dev-overlay/tsconfig.json new file mode 100644 index 000000000..d8a3e745d --- /dev/null +++ b/examples/dev-overlay/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "astro/tsconfigs/base", + "compilerOptions": { + "jsx": "preserve", + "jsxImportSource": "solid-js" + } +} \ No newline at end of file diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts index 109629428..29123235f 100644 --- a/packages/astro/src/@types/astro.ts +++ b/packages/astro/src/@types/astro.ts @@ -1084,6 +1084,10 @@ export interface AstroUserConfig { remotePatterns?: Partial[]; }; + devTools?: { + plugins: string[]; + }; + /** * @docs * @kind heading @@ -2263,3 +2267,10 @@ export interface ClientDirectiveConfig { name: string; entrypoint: string; } + +export interface DevOverlayItem { + id: string; + name: string; + icon: string; + init?(canvas: ShadowRoot, eventTarget: EventTarget): void | Promise; +} diff --git a/packages/astro/src/core/config/schema.ts b/packages/astro/src/core/config/schema.ts index 4ac40d4c5..6eb8b5281 100644 --- a/packages/astro/src/core/config/schema.ts +++ b/packages/astro/src/core/config/schema.ts @@ -32,6 +32,9 @@ const ASTRO_CONFIG_DEFAULTS = { image: { service: { entrypoint: 'astro/assets/services/sharp', config: {} }, }, + devTools: { + plugins: [], + }, compressHTML: true, server: { host: false, @@ -220,6 +223,9 @@ export const AstroConfigSchema = z.object({ .default([]), }) .default(ASTRO_CONFIG_DEFAULTS.image), + devTools: z + .object({ plugins: z.array(z.string()).default([]) }) + .default(ASTRO_CONFIG_DEFAULTS.devTools), markdown: z .object({ drafts: z.boolean().default(false), diff --git a/packages/astro/src/core/create-vite.ts b/packages/astro/src/core/create-vite.ts index 3c59b1fb4..dfb4c5ad6 100644 --- a/packages/astro/src/core/create-vite.ts +++ b/packages/astro/src/core/create-vite.ts @@ -16,6 +16,7 @@ import astroPostprocessVitePlugin from '../vite-plugin-astro-postprocess/index.j import { vitePluginAstroServer } from '../vite-plugin-astro-server/index.js'; import astroVitePlugin from '../vite-plugin-astro/index.js'; import configAliasVitePlugin from '../vite-plugin-config-alias/index.js'; +import astroDevTools from '../vite-plugin-dev-tools/vite-plugin-dev-tools.js'; import envVitePlugin from '../vite-plugin-env/index.js'; import astroHeadPlugin from '../vite-plugin-head/index.js'; import htmlVitePlugin from '../vite-plugin-html/index.js'; @@ -134,6 +135,7 @@ export async function createVite( vitePluginSSRManifest(), astroAssetsPlugin({ settings, logger, mode }), astroTransitions(), + astroDevTools({ settings, logger }), ], publicDir: fileURLToPath(settings.config.publicDir), root: fileURLToPath(settings.config.root), diff --git a/packages/astro/src/runtime/client/dev-overlay/overlay.ts b/packages/astro/src/runtime/client/dev-overlay/overlay.ts new file mode 100644 index 000000000..4cf94d1db --- /dev/null +++ b/packages/astro/src/runtime/client/dev-overlay/overlay.ts @@ -0,0 +1,189 @@ +// @ts-expect-error +import { loadDevToolsPlugins } from 'astro:dev-tools'; +import type { DevOverlayItem as DevOverlayItemDefinition } from '../../../@types/astro.js'; +import astroDevToolPlugin from './plugins/astro.js'; +import astroAuditPlugin from './plugins/audit.js'; +import astroXrayPlugin from './plugins/xray.js'; +import { DevOverlayHighlight, DevOverlayTooltip, DevOverlayWindow } from './ui-toolkit.js'; + +type DevOverlayItem = DevOverlayItemDefinition & { + active: boolean; + inited: boolean; + eventTarget: EventTarget; +}; + +document.addEventListener('DOMContentLoaded', async () => { + const builtinPlugins: DevOverlayItem[] = [ + astroDevToolPlugin, + astroXrayPlugin, + astroAuditPlugin, + ].map((plugin) => ({ ...plugin, active: false, inited: false, eventTarget: new EventTarget() })); + const customPluginsImports = (await loadDevToolsPlugins()) as DevOverlayItem[]; + const customPlugins: DevOverlayItem[] = []; + customPlugins.push(...customPluginsImports.map((plugin) => ({ ...plugin, active: false }))); + + const plugins: DevOverlayItem[] = [...builtinPlugins, ...customPlugins]; + + class AstroDevOverlay extends HTMLElement { + shadowRoot: ShadowRoot; + + constructor() { + super(); + this.shadowRoot = this.attachShadow({ mode: 'closed' }); + } + + // connect component + async connectedCallback() { + this.shadowRoot.innerHTML = ` + + +
+
+ ${builtinPlugins.map((plugin) => this.getPluginTemplate(plugin)).join('')} +
+ ${customPluginsImports.map((plugin) => this.getPluginTemplate(plugin)).join('')} +
+
`; + + this.attachClickEvents(); + } + + attachClickEvents() { + const items = this.shadowRoot.querySelectorAll('.item'); + if (!items) return; + items.forEach((item) => { + item.addEventListener('click', async (e) => { + const target = e.currentTarget; + if (!target || !(target instanceof HTMLElement)) return; + + const id = target.dataset.pluginId; + if (!id) return; + + const plugin = this.getPluginById(id); + if (!plugin) return; + const shadowRoot = this.getPluginCanvasById(plugin.id)!.shadowRoot!; + if (!plugin.inited) { + await plugin.init?.(shadowRoot, plugin.eventTarget); + plugin.inited = true; + } + + this.togglePluginStatus(plugin); + plugin.eventTarget.dispatchEvent( + new CustomEvent('plugin-toggle', { + detail: { + state: plugin.active, + plugin, + }, + }) + ); + }); + }); + } + + getPluginTemplate(plugin: DevOverlayItem) { + return `
+
${plugin.icon}
+
`; + } + + getPluginById(id: string) { + return plugins.find((plugin) => plugin.id === id); + } + + getPluginCanvasById(id: string) { + return this.shadowRoot.querySelector(`astro-overlay-plugin-canvas[data-plugin-id="${id}"]`); + } + + togglePluginStatus(plugin: DevOverlayItem, status?: boolean) { + plugin.active = status ?? !plugin.active; + const target = this.shadowRoot.querySelector(`[data-plugin-id="${plugin.id}"]`); + if (!target) return; + target.classList.toggle('active', plugin.active); + this.getPluginCanvasById(plugin.id)?.toggleAttribute('data-active', plugin.active); + } + } + + class DevOverlayCanvas extends HTMLElement { + shadowRoot: ShadowRoot; + + constructor() { + super(); + this.shadowRoot = this.attachShadow({ mode: 'closed' }); + } + + // connect component + async connectedCallback() { + this.shadowRoot.innerHTML = ``; + } + } + + customElements.define('astro-dev-overlay', AstroDevOverlay); + customElements.define('astro-dev-overlay-window', DevOverlayWindow); + customElements.define('astro-overlay-plugin-canvas', DevOverlayCanvas); + customElements.define('astro-overlay-tooltip', DevOverlayTooltip); + customElements.define('astro-overlay-highlight', DevOverlayHighlight); + + const overlay = document.createElement('astro-dev-overlay'); + overlay.style.zIndex = '999999'; + document.body.appendChild(overlay); + + // Create plugin canvases + plugins.forEach((plugin) => { + const pluginCanvas = document.createElement('astro-overlay-plugin-canvas'); + pluginCanvas.dataset.pluginId = plugin.id; + overlay.shadowRoot?.appendChild(pluginCanvas); + }); +}); diff --git a/packages/astro/src/runtime/client/dev-overlay/plugins/astro.ts b/packages/astro/src/runtime/client/dev-overlay/plugins/astro.ts new file mode 100644 index 000000000..552b6bb8d --- /dev/null +++ b/packages/astro/src/runtime/client/dev-overlay/plugins/astro.ts @@ -0,0 +1,12 @@ +import type { DevOverlayItem } from '../../../../@types/astro.js'; + +export default { + id: 'astro', + name: 'Astro', + icon: '', + toggleStatus(status) { + if (status == true) { + window.open('https://astro.build'); + } + }, +} satisfies DevOverlayItem; diff --git a/packages/astro/src/runtime/client/dev-overlay/plugins/audit.ts b/packages/astro/src/runtime/client/dev-overlay/plugins/audit.ts new file mode 100644 index 000000000..f5bcc05c0 --- /dev/null +++ b/packages/astro/src/runtime/client/dev-overlay/plugins/audit.ts @@ -0,0 +1,121 @@ +import type { DevOverlayItem } from '../../../../@types/astro.js'; +import type { DevOverlayTooltip } from '../ui-toolkit.js'; + +interface AuditRule { + title: string; + message: string; +} + +const selectorBasedRules: (AuditRule & { selector: string })[] = [ + { + title: 'Missing `alt` tag', + message: 'The alt attribute is important for accessibility.', + selector: 'img:not([alt])', + }, +]; + +export default { + id: 'astro:audit', + name: 'Audit', + icon: '', + init(canvas) { + createBase(); + + selectorBasedRules.forEach((rule) => { + document.querySelectorAll(rule.selector).forEach((el) => { + canvas.appendChild(createAuditProblem(rule, el)); + }); + }); + + function createAuditProblem(rule: AuditRule, originalElement: Element) { + const el = document.createElement('div'); + el.className = 'astro-audit-problem'; + el.style.position = 'absolute'; + + const rect = originalElement.getBoundingClientRect(); + el.style.top = `${Math.max(rect.top - 10, 0)}px`; + el.style.left = `${Math.max(rect.left - 10, 0)}px`; + el.style.width = `${rect.width + 15}px`; + el.style.height = `${rect.height + 15}px`; + + el.innerHTML = ` +
+ + + +
+ + `; + + const tooltip = document.createElement('astro-overlay-tooltip') as DevOverlayTooltip; + tooltip.sections = [ + { + icon: '', + title: rule.title, + }, + { + content: rule.message, + }, + { + content: '/src/somewhere/component.astro', + clickDescription: 'Click to go to file', + clickAction() { + // TODO: Implement this + }, + }, + ]; + + tooltip.style.position = 'absolute'; + tooltip.style.top = `${rect.height}px`; + tooltip.style.left = `${Math.max(rect.left - 10, 5)}px`; + tooltip.style.margin = '0'; + + el.appendChild(tooltip); + + el.addEventListener('mouseover', () => { + tooltip.dialog.show(); + }); + + el.addEventListener('mouseout', () => { + tooltip.dialog.close(); + }); + + return el; + } + + function createBase() { + // Create style + const style = document.createElement('style'); + // TODO: Should this be in the astro-overlay-highlight component? + style.innerHTML = ` + .astro-audit-problem .icon { + width: 24px; + height: 24px; + background: linear-gradient(0deg, #B33E66, #B33E66), linear-gradient(0deg, #351722, #351722); + border: 1px solid rgba(53, 23, 34, 1); + border-radius: 9999px; + display: flex; + justify-content: center; + align-items: center; + position: absolute; + top: -15px; + } + `; + + const svgSymbols = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); + svgSymbols.setAttribute('aria-hidden', 'true'); + svgSymbols.setAttribute( + 'style', + 'position: absolute; width: 0; height: 0; overflow: hidden;' + ); + svgSymbols.innerHTML = ` + + + + `; + + canvas.appendChild(style); + canvas.appendChild(svgSymbols); + } + }, +} satisfies DevOverlayItem; diff --git a/packages/astro/src/runtime/client/dev-overlay/plugins/xray.ts b/packages/astro/src/runtime/client/dev-overlay/plugins/xray.ts new file mode 100644 index 000000000..a99206b94 --- /dev/null +++ b/packages/astro/src/runtime/client/dev-overlay/plugins/xray.ts @@ -0,0 +1,84 @@ +import type { DevOverlayItem } from '../../../../@types/astro.js'; +import type { DevOverlayTooltip } from '../ui-toolkit.js'; + +export default { + id: 'astro:xray', + name: 'Xray', + icon: '', + init(canvas) { + const islands = document.querySelectorAll('astro-island'); + + islands.forEach((island) => { + const el = document.createElement('div'); + el.style.position = 'absolute'; + + const rect = island.children[0] + ? island.children[0].getBoundingClientRect() + : island.getBoundingClientRect(); + + el.style.top = `${Math.max(rect.top - 10, 0)}px`; + el.style.left = `${Math.max(rect.left - 10, 0)}px`; + el.style.width = `${rect.width + 15}px`; + el.style.height = `${rect.height + 15}px`; + + el.innerHTML = ` + + `; + + const islandProps = island.getAttribute('props') + ? JSON.parse(island.getAttribute('props')!) + : {}; + const islandClientDirective = island.getAttribute('client'); + + const tooltip = document.createElement('astro-overlay-tooltip') as DevOverlayTooltip; + tooltip.sections = []; + + if (islandClientDirective) { + tooltip.sections.push({ + title: 'Client directive', + content: `client:${islandClientDirective}`, + }); + } + + if (Object.keys(islandProps).length > 0) { + tooltip.sections.push({ + title: 'Props', + content: `${Object.entries(islandProps) + .map((prop) => `${prop[0]}="${getPropValue(prop[1] as any)}"`) + .join(', ')}`, + }); + } + + tooltip.sections.push({ + content: '/src/somewhere/component.astro', + clickDescription: 'Click to go to file', + clickAction() { + // TODO: Implement this + }, + }); + + tooltip.style.position = 'absolute'; + tooltip.style.top = `${rect.height}px`; + tooltip.style.left = `${Math.max(rect.left - 10, 5)}px`; + tooltip.style.margin = '0'; + + el.appendChild(tooltip); + + el.addEventListener('mouseover', () => { + tooltip.dialog.show(); + }); + + el.addEventListener('mouseout', () => { + tooltip.dialog.close(); + }); + + canvas.appendChild(el); + }); + + function getPropValue(prop: [number, any]) { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const [_, value] = prop; + return JSON.stringify(value, null, 2); + } + }, +} satisfies DevOverlayItem; diff --git a/packages/astro/src/runtime/client/dev-overlay/ui-toolkit.ts b/packages/astro/src/runtime/client/dev-overlay/ui-toolkit.ts new file mode 100644 index 000000000..c31c67684 --- /dev/null +++ b/packages/astro/src/runtime/client/dev-overlay/ui-toolkit.ts @@ -0,0 +1,148 @@ +export class DevOverlayWindow extends HTMLElement { + title: string; + + constructor() { + super(); + this.title = 'World'; + } + + async connectedCallback() { + const shadow = this.attachShadow({ mode: 'closed' }); + shadow.innerHTML = ` + + +
+

${this.title}

+
+ `; + } +} + +interface DevOverlayTooltipSection { + title?: string; + icon?: string; + content?: string; + clickAction?: () => void; + clickDescription?: string; +} + +export class DevOverlayTooltip extends HTMLElement { + sections: DevOverlayTooltipSection[] = []; + dialog: HTMLDialogElement; + + constructor() { + super(); + this.dialog = document.createElement('dialog'); + } + + connectedCallback() { + this.style.width = '100%'; + this.innerHTML = ` + + `; + } +} diff --git a/packages/astro/src/vite-plugin-astro-server/route.ts b/packages/astro/src/vite-plugin-astro-server/route.ts index a567c3266..5885f949d 100644 --- a/packages/astro/src/vite-plugin-astro-server/route.ts +++ b/packages/astro/src/vite-plugin-astro-server/route.ts @@ -282,6 +282,13 @@ async function getScriptsAndStyles({ pipeline, filePath }: GetScriptsAndStylesPa }, children: '', }); + scripts.add({ + props: { + type: 'module', + src: await resolveIdToUrl(moduleLoader, 'astro/runtime/client/dev-overlay/overlay.js'), + }, + children: '', + }); } // TODO: We should allow adding generic HTML elements to the head, not just scripts diff --git a/packages/astro/src/vite-plugin-dev-tools/vite-plugin-dev-tools.ts b/packages/astro/src/vite-plugin-dev-tools/vite-plugin-dev-tools.ts new file mode 100644 index 000000000..d766062e7 --- /dev/null +++ b/packages/astro/src/vite-plugin-dev-tools/vite-plugin-dev-tools.ts @@ -0,0 +1,31 @@ +import type * as vite from 'vite'; +import type { AstroPluginOptions } from '../@types/astro.js'; + +const VIRTUAL_MODULE_ID = 'astro:dev-tools'; +const resolvedVirtualModuleId = '\0' + VIRTUAL_MODULE_ID; + +export default function astroDevTools({ settings }: AstroPluginOptions): vite.Plugin { + return { + name: 'astro:dev-tools', + resolveId(id) { + if (id === VIRTUAL_MODULE_ID) { + return resolvedVirtualModuleId; + } + }, + load(id) { + if (id === resolvedVirtualModuleId) { + return ` + export const loadDevToolsPlugins = async () => { + return [${settings.config.devTools.plugins.map((p) => `(await import('${p}')).default`).join(',')}]; + }; + `; + } + }, + configureServer(server) { + // Example: wait for a client to connect before sending a message + server.ws.on('connection', () => { + server.ws.send('astro-dev-tools', { msg: 'hello' }); + }); + }, + }; +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0d5045374..57a2b7ca7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -149,15 +149,17 @@ importers: specifier: ^3.2.0 version: link:../../packages/astro - examples/deno: + examples/dev-overlay: dependencies: + '@astrojs/solid-js': + specifier: ^3.0.1 + version: link:../../packages/integrations/solid astro: specifier: ^3.2.0 version: link:../../packages/astro - devDependencies: - '@astrojs/deno': - specifier: ^5.0.1 - version: 5.0.1(astro@packages+astro) + solid-js: + specifier: ^1.7.11 + version: 1.7.11 examples/framework-alpine: dependencies: @@ -5224,15 +5226,6 @@ packages: resolution: {integrity: sha512-Mp+qrNhly+27bL/Zq8lGeUY+YrdoU0eDfIlAeGIPrzt0PnI/jGpvPUdCaugv4zbCrDkOUScFfcbeEiYumrdJnw==} dev: false - /@astrojs/deno@5.0.1(astro@packages+astro): - resolution: {integrity: sha512-nYztGqHqC+q3A9ynjj3gblAkO/ZylDwahjVTx+2DvZgX4U+BJU/gL5BZkNtL+P10opCKJi29NvvVFvk6jwZHmA==} - peerDependencies: - astro: '*' - dependencies: - astro: link:packages/astro - esbuild: 0.19.2 - dev: true - /@astrojs/language-server@2.3.0(prettier-plugin-astro@0.12.0)(prettier@3.0.3)(typescript@5.1.6): resolution: {integrity: sha512-NFSzszjR4+f0+fTUCuFKXrLWusJFqWvHMrIzHB0lXUE8dt3Dm1Ok9Emrdj3s3BvlguJz05MV9xSIz1puMvomtQ==} hasBin: true diff --git a/tsconfig.eslint.json b/tsconfig.eslint.json index 678a223c9..cd1bdb234 100644 --- a/tsconfig.eslint.json +++ b/tsconfig.eslint.json @@ -2,5 +2,6 @@ "compilerOptions": { "allowJs": true }, + "include": [".eslintrc.cjs"], "extends": "./tsconfig.base.json" }