mirror of
https://github.com/withastro/astro.git
synced 2025-01-27 22:19:04 -05:00
feat(audits): Add UI with list of audits (#10074)
* feat(audits): Add UI with list of audits * style: slightly better UI * requested design changes * chore: changeset * add test * remove unwanted file
This commit is contained in:
parent
31de1ea8b8
commit
7443929381
6 changed files with 155 additions and 3 deletions
5
.changeset/lovely-yaks-obey.md
Normal file
5
.changeset/lovely-yaks-obey.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
"astro": minor
|
||||
---
|
||||
|
||||
Add a UI showing the list of found problems when using the audit app in the dev toolbar
|
|
@ -130,6 +130,23 @@ test.describe('Dev Toolbar', () => {
|
|||
await expect(auditWindow.locator('astro-dev-toolbar-icon[icon=check-circle]')).toBeVisible();
|
||||
});
|
||||
|
||||
test('audit shows a window with list of problems', async ({ page, astro }) => {
|
||||
await page.goto(astro.resolveUrl('/'));
|
||||
|
||||
const toolbar = page.locator('astro-dev-toolbar');
|
||||
const appButton = toolbar.locator('button[data-app-id="astro:audit"]');
|
||||
await appButton.click();
|
||||
|
||||
const auditCanvas = toolbar.locator('astro-dev-toolbar-app-canvas[data-app-id="astro:audit"]');
|
||||
const auditWindow = auditCanvas.locator('astro-dev-toolbar-window');
|
||||
await expect(auditWindow).toHaveCount(1);
|
||||
await expect(auditWindow).toBeVisible();
|
||||
|
||||
// Toggle app off
|
||||
await appButton.click();
|
||||
await expect(auditWindow).not.toBeVisible();
|
||||
});
|
||||
|
||||
test('adjusts tooltip position if off-screen', async ({ page, astro }) => {
|
||||
await page.goto(astro.resolveUrl('/tooltip-position'));
|
||||
|
||||
|
|
|
@ -124,6 +124,7 @@
|
|||
"@babel/plugin-transform-react-jsx": "^7.22.5",
|
||||
"@babel/traverse": "^7.23.3",
|
||||
"@babel/types": "^7.23.3",
|
||||
"@medv/finder": "^3.1.0",
|
||||
"@types/babel__core": "^7.20.4",
|
||||
"acorn": "^8.11.2",
|
||||
"aria-query": "^5.3.0",
|
||||
|
|
|
@ -8,6 +8,7 @@ import {
|
|||
} from '../utils/highlight.js';
|
||||
import { createWindowElement } from '../utils/window.js';
|
||||
import { a11y } from './a11y.js';
|
||||
import { finder } from '@medv/finder';
|
||||
import { perf } from './perf.js';
|
||||
|
||||
const icon =
|
||||
|
@ -60,7 +61,11 @@ export default {
|
|||
name: 'Audit',
|
||||
icon: icon,
|
||||
async init(canvas, eventTarget) {
|
||||
let audits: { highlightElement: DevToolbarHighlight; auditedElement: HTMLElement }[] = [];
|
||||
let audits: {
|
||||
highlightElement: DevToolbarHighlight;
|
||||
auditedElement: HTMLElement;
|
||||
rule: AuditRule;
|
||||
}[] = [];
|
||||
|
||||
await lint();
|
||||
|
||||
|
@ -126,6 +131,119 @@ export default {
|
|||
},
|
||||
})
|
||||
);
|
||||
|
||||
const auditListWindow = createWindowElement(
|
||||
`
|
||||
<style>
|
||||
astro-dev-toolbar-window {
|
||||
left: initial;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
transform: none;
|
||||
width: 320px;
|
||||
max-height: 320px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 18px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 22px;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
ul, li {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
h1, h2 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin: 0;
|
||||
margin-bottom: 8px;
|
||||
color: white;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.audit-title {
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
margin-right: 1ch;
|
||||
}
|
||||
|
||||
#audit-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
|
||||
<header>
|
||||
<h1>Audits</h1>
|
||||
<astro-dev-toolbar-badge size="large">${audits.length} problem${
|
||||
audits.length > 1 ? 's' : ''
|
||||
} found</astro-dev-toolbar-badge>
|
||||
</header>
|
||||
<hr />`
|
||||
);
|
||||
|
||||
const auditListUl = document.createElement('ul');
|
||||
auditListUl.id = 'audit-list';
|
||||
audits.forEach((audit, index) => {
|
||||
const resolvedRule = resolveAuditRule(audit.rule, audit.auditedElement);
|
||||
const card = document.createElement('astro-dev-toolbar-card');
|
||||
|
||||
card.shadowRoot.innerHTML = `
|
||||
<style>
|
||||
:host>button {
|
||||
text-align: left;
|
||||
box-shadow: none !important;
|
||||
${
|
||||
index + 1 < audits.length
|
||||
? 'border-radius: 0 !important;'
|
||||
: 'border-radius: 0 0 8px 8px !important;'
|
||||
}
|
||||
}
|
||||
|
||||
:host>button:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>`;
|
||||
|
||||
card.clickAction = () => {
|
||||
audit.highlightElement.scrollIntoView();
|
||||
audit.highlightElement.focus();
|
||||
};
|
||||
const h3 = document.createElement('h3');
|
||||
h3.innerText = finder(audit.auditedElement);
|
||||
card.appendChild(h3);
|
||||
const div = document.createElement('div');
|
||||
const title = document.createElement('span');
|
||||
title.classList.add('audit-title');
|
||||
title.innerHTML = resolvedRule.title;
|
||||
div.appendChild(title);
|
||||
card.appendChild(div);
|
||||
auditListUl.appendChild(card);
|
||||
});
|
||||
|
||||
auditListWindow.appendChild(auditListUl);
|
||||
|
||||
canvas.append(auditListWindow);
|
||||
} else {
|
||||
eventTarget.dispatchEvent(
|
||||
new CustomEvent('toggle-notification', {
|
||||
|
@ -229,7 +347,11 @@ export default {
|
|||
attachTooltipToHighlight(highlight, tooltip, originalElement);
|
||||
|
||||
canvas.append(highlight);
|
||||
audits.push({ highlightElement: highlight, auditedElement: originalElement as HTMLElement });
|
||||
audits.push({
|
||||
highlightElement: highlight,
|
||||
auditedElement: originalElement as HTMLElement,
|
||||
rule: rule,
|
||||
});
|
||||
}
|
||||
|
||||
function buildAuditTooltip(rule: AuditRule, element: Element) {
|
||||
|
|
|
@ -13,7 +13,7 @@ export class DevToolbarCard extends HTMLElement {
|
|||
connectedCallback() {
|
||||
const element = this.link ? 'a' : this.clickAction ? 'button' : 'div';
|
||||
|
||||
this.shadowRoot.innerHTML = `
|
||||
this.shadowRoot.innerHTML += `
|
||||
<style>
|
||||
:host>a, :host>button, :host>div {
|
||||
box-sizing: border-box;
|
||||
|
|
7
pnpm-lock.yaml
generated
7
pnpm-lock.yaml
generated
|
@ -524,6 +524,9 @@ importers:
|
|||
'@babel/types':
|
||||
specifier: ^7.23.3
|
||||
version: 7.23.6
|
||||
'@medv/finder':
|
||||
specifier: ^3.1.0
|
||||
version: 3.1.0
|
||||
'@types/babel__core':
|
||||
specifier: ^7.20.4
|
||||
version: 7.20.5
|
||||
|
@ -6831,6 +6834,10 @@ packages:
|
|||
- supports-color
|
||||
dev: false
|
||||
|
||||
/@medv/finder@3.1.0:
|
||||
resolution: {integrity: sha512-ojkXjR3K0Zz3jnCR80tqPL+0yvbZk/lEodb6RIVjLz7W8RVA2wrw8ym/CzCpXO9SYVUIKHFUpc7jvf8UKfIM3w==}
|
||||
dev: false
|
||||
|
||||
/@nanostores/preact@0.5.0(nanostores@0.9.5)(preact@10.19.3):
|
||||
resolution: {integrity: sha512-Zq5DEAY+kIfwJ1NPd43D1mpsbISuiD6N/SuTHrt/8jUoifLwXaReaZMAnvkvbIGOgcB1Hy++A9jZix2taNNYxQ==}
|
||||
engines: {node: ^16.0.0 || ^18.0.0 || >=20.0.0}
|
||||
|
|
Loading…
Add table
Reference in a new issue