Skip to content

Commit

Permalink
feat(overlay): Add a settings panel (#9058)
Browse files Browse the repository at this point in the history
  • Loading branch information
Princesseuh authored Nov 13, 2023
1 parent a7f8123 commit 5ef89ef
Show file tree
Hide file tree
Showing 12 changed files with 349 additions and 59 deletions.
5 changes: 5 additions & 0 deletions .changeset/six-chefs-flash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'astro': patch
---

Add a new settings panel to the dev overlay
19 changes: 19 additions & 0 deletions packages/astro/e2e/dev-overlay.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,4 +98,23 @@ test.describe('Dev Overlay', () => {
await expect(auditHighlight).not.toBeVisible();
await expect(auditHighlightTooltip).not.toBeVisible();
});

test('can open Settings plugin', async ({ page, astro }) => {
await page.goto(astro.resolveUrl('/'));

const overlay = page.locator('astro-dev-overlay');
const pluginButton = overlay.locator('button[data-plugin-id="astro:settings"]');
await pluginButton.click();

const settingsPluginCanvas = overlay.locator(
'astro-dev-overlay-plugin-canvas[data-plugin-id="astro:settings"]'
);
const settingsWindow = settingsPluginCanvas.locator('astro-dev-overlay-window');
await expect(settingsWindow).toHaveCount(1);
await expect(settingsWindow).toBeVisible();

// Toggle plugin off
await pluginButton.click();
await expect(settingsWindow).not.toBeVisible();
});
});
2 changes: 2 additions & 0 deletions packages/astro/src/@types/astro.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import type { AstroIntegrationLogger, Logger, LoggerLevel } from '../core/logger
import type { AstroDevOverlay, DevOverlayCanvas } from '../runtime/client/dev-overlay/overlay.js';
import type { DevOverlayHighlight } from '../runtime/client/dev-overlay/ui-library/highlight.js';
import type { Icon } from '../runtime/client/dev-overlay/ui-library/icons.js';
import type { DevOverlayToggle } from '../runtime/client/dev-overlay/ui-library/toggle.js';
import type { DevOverlayTooltip } from '../runtime/client/dev-overlay/ui-library/tooltip.js';
import type { DevOverlayWindow } from '../runtime/client/dev-overlay/ui-library/window.js';
import type { AstroComponentFactory, AstroComponentInstance } from '../runtime/server/index.js';
Expand Down Expand Up @@ -2578,5 +2579,6 @@ declare global {
'astro-dev-overlay-plugin-canvas': DevOverlayCanvas;
'astro-dev-overlay-tooltip': DevOverlayTooltip;
'astro-dev-overlay-highlight': DevOverlayHighlight;
'astro-dev-overlay-toggle': DevOverlayToggle;
}
}
14 changes: 11 additions & 3 deletions packages/astro/src/runtime/client/dev-overlay/entrypoint.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { DevOverlayPlugin as DevOverlayPluginDefinition } from '../../../@types/astro.js';
import { type AstroDevOverlay, type DevOverlayPlugin } from './overlay.js';
import { settings } from './settings.js';

let overlay: AstroDevOverlay;

Expand All @@ -9,22 +10,26 @@ document.addEventListener('DOMContentLoaded', async () => {
{ default: astroDevToolPlugin },
{ default: astroAuditPlugin },
{ default: astroXrayPlugin },
{ default: astroSettingsPlugin },
{ AstroDevOverlay, DevOverlayCanvas },
{ DevOverlayCard },
{ DevOverlayHighlight },
{ DevOverlayTooltip },
{ DevOverlayWindow },
{ DevOverlayToggle },
] = await Promise.all([
// @ts-expect-error
import('astro:dev-overlay'),
import('./plugins/astro.js'),
import('./plugins/audit.js'),
import('./plugins/xray.js'),
import('./plugins/settings.js'),
import('./overlay.js'),
import('./ui-library/card.js'),
import('./ui-library/highlight.js'),
import('./ui-library/tooltip.js'),
import('./ui-library/window.js'),
import('./ui-library/toggle.js'),
]);

// Register custom elements
Expand All @@ -34,6 +39,7 @@ document.addEventListener('DOMContentLoaded', async () => {
customElements.define('astro-dev-overlay-tooltip', DevOverlayTooltip);
customElements.define('astro-dev-overlay-highlight', DevOverlayHighlight);
customElements.define('astro-dev-overlay-card', DevOverlayCard);
customElements.define('astro-dev-overlay-toggle', DevOverlayToggle);

overlay = document.createElement('astro-dev-overlay');

Expand All @@ -60,7 +66,9 @@ document.addEventListener('DOMContentLoaded', async () => {
newState = evt.detail.state ?? true;
}

target.querySelector('.notification')?.toggleAttribute('data-active', newState);
if (settings.config.showPluginNotifications === false) {
target.querySelector('.notification')?.toggleAttribute('data-active', newState);
}
});

eventTarget.addEventListener('toggle-plugin', async (evt) => {
Expand All @@ -77,8 +85,8 @@ document.addEventListener('DOMContentLoaded', async () => {

const customPluginsDefinitions = (await loadDevOverlayPlugins()) as DevOverlayPluginDefinition[];
const plugins: DevOverlayPlugin[] = [
...[astroDevToolPlugin, astroXrayPlugin, astroAuditPlugin].map((pluginDef) =>
preparePlugin(pluginDef, true)
...[astroDevToolPlugin, astroXrayPlugin, astroAuditPlugin, astroSettingsPlugin].map(
(pluginDef) => preparePlugin(pluginDef, true)
),
...customPluginsDefinitions.map((pluginDef) => preparePlugin(pluginDef, false)),
];
Expand Down
26 changes: 18 additions & 8 deletions packages/astro/src/runtime/client/dev-overlay/overlay.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* eslint-disable no-console */
import type { DevOverlayPlugin as DevOverlayPluginDefinition } from '../../../@types/astro.js';
import { settings } from './settings.js';
import { getIconElement, isDefinedIcon, type Icon } from './ui-library/icons.js';

export type DevOverlayPlugin = DevOverlayPluginDefinition & {
Expand Down Expand Up @@ -235,14 +236,21 @@ export class AstroDevOverlay extends HTMLElement {
<div id="dev-bar">
<div id="bar-container">
${this.plugins
.filter((plugin) => plugin.builtIn)
.filter((plugin) => plugin.builtIn && plugin.id !== 'astro:settings')
.map((plugin) => this.getPluginTemplate(plugin))
.join('')}
${
this.plugins.filter((plugin) => !plugin.builtIn).length > 0
? `<div class="separator"></div>${this.plugins
.filter((plugin) => !plugin.builtIn)
.map((plugin) => this.getPluginTemplate(plugin))
.join('')}`
: ''
}
<div class="separator"></div>
${this.plugins
.filter((plugin) => !plugin.builtIn)
.map((plugin) => this.getPluginTemplate(plugin))
.join('')}
${this.getPluginTemplate(
this.plugins.find((plugin) => plugin.builtIn && plugin.id === 'astro:settings')!
)}
</div>
</div>
<button id="minimize-button">${getIconElement('arrow-down')?.outerHTML}</button>
Expand All @@ -254,7 +262,8 @@ export class AstroDevOverlay extends HTMLElement {
// Create plugin canvases
this.plugins.forEach(async (plugin) => {
if (!this.hasBeenInitialized) {
console.log(`Creating plugin canvas for ${plugin.id}`);
if (settings.config.verbose) console.log(`Creating plugin canvas for ${plugin.id}`);

const pluginCanvas = document.createElement('astro-dev-overlay-plugin-canvas');
pluginCanvas.dataset.pluginId = plugin.id;
this.shadowRoot?.append(pluginCanvas);
Expand Down Expand Up @@ -321,7 +330,7 @@ export class AstroDevOverlay extends HTMLElement {
if (this.isHidden()) {
this.hoverTimeout = window.setTimeout(() => {
this.toggleOverlay(true);
}, this.HOVER_DELAY);
}, this.HOVER_DELAY + 200); // Slightly higher delay here to prevent users opening the overlay by accident
} else {
this.hoverTimeout = window.setTimeout(() => {
this.toggleMinimizeButton(true);
Expand Down Expand Up @@ -374,7 +383,8 @@ export class AstroDevOverlay extends HTMLElement {
const shadowRoot = this.getPluginCanvasById(plugin.id)!.shadowRoot!;

try {
console.info(`Initializing plugin ${plugin.id}`);
if (settings.config.verbose) console.info(`Initializing plugin ${plugin.id}`);

await plugin.init?.(shadowRoot, plugin.eventTarget);
plugin.status = 'ready';

Expand Down
50 changes: 9 additions & 41 deletions packages/astro/src/runtime/client/dev-overlay/plugins/astro.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { DevOverlayPlugin } from '../../../../@types/astro.js';
import { createWindowWithTransition, waitForTransition } from './utils/window.js';

export default {
id: 'astro',
Expand All @@ -10,38 +11,10 @@ export default {
document.addEventListener('astro:after-swap', createWindow);

function createWindow() {
const style = document.createElement('style');
style.textContent = `
:host {
opacity: 0;
transition: opacity 0.15s ease-in-out;
}
:host([data-active]) {
opacity: 1;
}
@media screen and (prefers-reduced-motion: no-preference) {
:host astro-dev-overlay-window {
transform: translateY(55px) translate(-50%, -50%);
transition: transform 0.15s ease-in-out;
transform-origin: center bottom;
}
:host([data-active]) astro-dev-overlay-window {
transform: translateY(0) translate(-50%, -50%);
}
}
`;
canvas.append(style);

const astroWindow = document.createElement('astro-dev-overlay-window');

astroWindow.windowTitle = 'Astro';
astroWindow.windowIcon = 'astro:logo';

astroWindow.innerHTML = `
<style>
const window = createWindowWithTransition(
'Astro',
'astro:logo',
`<style>
#buttons-container {
display: flex;
gap: 16px;
Expand Down Expand Up @@ -91,18 +64,13 @@ export default {
<a href="https://astro.build" target="_blank">Visit the Astro website</a>
</footer>
</div>
`;
`
);

canvas.append(astroWindow);
canvas.append(window);
}
},
async beforeTogglingOff(canvas) {
canvas.host?.removeAttribute('data-active');

await new Promise((resolve) => {
canvas.host.addEventListener('transitionend', resolve);
});

return true;
return await waitForTransition(canvas);
},
} satisfies DevOverlayPlugin;
106 changes: 106 additions & 0 deletions packages/astro/src/runtime/client/dev-overlay/plugins/settings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import type { DevOverlayPlugin } from '../../../../@types/astro.js';
import { settings, type Settings } from '../settings.js';
import { createWindowWithTransition, waitForTransition } from './utils/window.js';

interface SettingRow {
name: string;
description: string;
input: 'checkbox' | 'text' | 'number' | 'select';
settingKey: keyof Settings;
changeEvent: (evt: Event) => void;
}

const settingsRows = [
{
name: 'Disable notifications',
description: 'Notification bubbles will not be shown when this is enabled.',
input: 'checkbox',
settingKey: 'showPluginNotifications',
changeEvent: (evt: Event) => {
if (evt.currentTarget instanceof HTMLInputElement) {
settings.updateSetting('showPluginNotifications', evt.currentTarget.checked);
}
},
},
{
name: 'Verbose logging',
description: 'Log additional information to the console.',
input: 'checkbox',
settingKey: 'verbose',
changeEvent: (evt: Event) => {
if (evt.currentTarget instanceof HTMLInputElement) {
settings.updateSetting('verbose', evt.currentTarget.checked);
}
},
},
] satisfies SettingRow[];

export default {
id: 'astro:settings',
name: 'Overlay settings',
icon: 'gear',
init(canvas) {
createSettingsWindow();

document.addEventListener('astro:after-swap', createSettingsWindow);

function createSettingsWindow() {
const window = createWindowWithTransition(
'Settings',
'gear',
`<style>
h2, h3 {
margin-top: 0;
}
.setting-row {
display: flex;
justify-content: space-between;
align-items: center;
}
h3 {
font-size: 16px;
font-weight: 400;
color: white;
margin-bottom: 0;
}
label {
font-size: 15px;
line-height: 1.5rem;
}
</style>
<h2>General</h2>
`,
settingsRows.flatMap((setting) => [
getElementForSettingAsString(setting),
document.createElement('hr'),
])
);
canvas.append(window);

function getElementForSettingAsString(setting: SettingRow) {
const label = document.createElement('label');
label.classList.add('setting-row');
const section = document.createElement('section');
section.innerHTML = `<h3>${setting.name}</h3>${setting.description}`;
label.append(section);

switch (setting.input) {
case 'checkbox': {
const astroToggle = document.createElement('astro-dev-overlay-toggle');
astroToggle.input.addEventListener('change', setting.changeEvent);
astroToggle.input.checked = settings.config[setting.settingKey];
label.append(astroToggle);
}
}

return label;
}
}
},
async beforeTogglingOff(canvas) {
return await waitForTransition(canvas);
},
} satisfies DevOverlayPlugin;
Loading

0 comments on commit 5ef89ef

Please sign in to comment.