Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(dev-overlay): Hide plugins into a separate menu when there's too many enabled #9102

Merged
merged 5 commits into from
Nov 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fresh-garlics-film.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'astro': patch
---

In the dev overlay, when there's too many plugins enabled at once, some of the plugins will now be hidden in a separate sub menu to avoid the bar becoming too long
175 changes: 171 additions & 4 deletions packages/astro/src/runtime/client/dev-overlay/entrypoint.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import type { DevOverlayPlugin as DevOverlayPluginDefinition } from '../../../@types/astro.js';
import { type AstroDevOverlay, type DevOverlayPlugin } from './overlay.js';

import { settings } from './settings.js';
import type { Icon } from './ui-library/icons.js';

let overlay: AstroDevOverlay;

Expand All @@ -17,6 +19,7 @@ document.addEventListener('DOMContentLoaded', async () => {
{ DevOverlayTooltip },
{ DevOverlayWindow },
{ DevOverlayToggle },
{ getIconElement, isDefinedIcon },
] = await Promise.all([
// @ts-expect-error
import('astro:dev-overlay'),
Expand All @@ -30,6 +33,7 @@ document.addEventListener('DOMContentLoaded', async () => {
import('./ui-library/tooltip.js'),
import('./ui-library/window.js'),
import('./ui-library/toggle.js'),
import('./ui-library/icons.js'),
]);

// Register custom elements
Expand All @@ -53,6 +57,7 @@ document.addEventListener('DOMContentLoaded', async () => {
builtIn: builtIn,
active: false,
status: 'loading' as const,
notification: { state: false },
eventTarget: eventTarget,
};

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

if (settings.config.showPluginNotifications === false) {
plugin.notification.state = newState;

if (settings.config.disablePluginNotification === false) {
target.querySelector('.notification')?.toggleAttribute('data-active', newState);
}
});
Expand All @@ -83,11 +90,171 @@ document.addEventListener('DOMContentLoaded', async () => {
return plugin;
};

const astromorePlugin = {
id: 'astro:more',
name: 'More',
icon: 'dots-three',
init(canvas, eventTarget) {
const hiddenPlugins = plugins.filter((p) => !p.builtIn).slice(overlay.customPluginsToShow);

createDropdown();

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

function createDropdown() {
const style = document.createElement('style');
style.innerHTML = `
#dropdown {
background: rgba(19, 21, 26, 1);
border: 1px solid rgba(52, 56, 65, 1);
border-radius: 12px;
box-shadow: 0px 0px 0px 0px rgba(19, 21, 26, 0.30), 0px 1px 2px 0px rgba(19, 21, 26, 0.29), 0px 4px 4px 0px rgba(19, 21, 26, 0.26), 0px 10px 6px 0px rgba(19, 21, 26, 0.15), 0px 17px 7px 0px rgba(19, 21, 26, 0.04), 0px 26px 7px 0px rgba(19, 21, 26, 0.01);
width: 180px;
padding: 8px;
z-index: 9999999999;
}

.notification {
display: none;
position: absolute;
top: -4px;
right: -6px;
width: 8px;
height: 8px;
border-radius: 9999px;
border: 1px solid rgba(19, 21, 26, 1);
background: #B33E66;
}

.notification[data-active] {
display: block;
}

#dropdown button {
border: 0;
background: transparent;
color: white;
font-family: system-ui, sans-serif;
font-size: 16px;
line-height: 1.2;
white-space: nowrap;
text-decoration: none;
margin: 0;
display: flex;
align-items: center;
width: 100%;
padding: 8px;
border-radius: 8px;
}

#dropdown button:hover, #dropdown button:focus-visible {
background: rgba(27, 30, 36, 1);
cursor: pointer;
}

#dropdown button.active {
background: rgba(71, 78, 94, 1);
}

#dropdown .icon {
position: relative;
height: 24px;
width: 24px;
margin-right: 0.5em;
}

#dropdown .icon svg {
max-height: 100%;
max-width: 100%;
}
`;
canvas.append(style);

const dropdown = document.createElement('div');
dropdown.id = 'dropdown';

for (const plugin of hiddenPlugins) {
const buttonContainer = document.createElement('div');
buttonContainer.classList.add('item');
const button = document.createElement('button');
button.setAttribute('data-plugin-id', plugin.id);

const iconContainer = document.createElement('div');
const iconElement = getPluginIcon(plugin.icon);
iconContainer.append(iconElement);

const notification = document.createElement('div');
notification.classList.add('notification');
iconContainer.append(notification);
iconContainer.classList.add('icon');

button.append(iconContainer);
button.append(document.createTextNode(plugin.name));

button.addEventListener('click', () => {
overlay.togglePluginStatus(plugin);
});
buttonContainer.append(button);

dropdown.append(buttonContainer);

eventTarget.addEventListener('plugin-toggled', positionDropdown);
window.addEventListener('resize', positionDropdown);

plugin.eventTarget.addEventListener('toggle-notification', (evt) => {
if (!(evt instanceof CustomEvent)) return;

if (settings.config.disablePluginNotification === false) {
notification.toggleAttribute('data-active', evt.detail.state ?? true);
}

eventTarget.dispatchEvent(
new CustomEvent('toggle-notification', {
detail: {
state: hiddenPlugins.some((p) => p.notification.state === true),
},
})
);
});
}

canvas.append(dropdown);

function getPluginIcon(icon: Icon) {
if (isDefinedIcon(icon)) {
return getIconElement(icon)!;
}

return icon;
}

function positionDropdown() {
const moreButtonRect = overlay.shadowRoot
.querySelector('[data-plugin-id="astro:more"]')
?.getBoundingClientRect();
const dropdownRect = dropdown.getBoundingClientRect();

if (moreButtonRect && dropdownRect) {
dropdown.style.position = 'absolute';
dropdown.style.top = `${moreButtonRect.top - dropdownRect.height - 12}px`;
dropdown.style.left = `${
moreButtonRect.left + moreButtonRect.width - dropdownRect.width
}px`;
}
}
}
},
} satisfies DevOverlayPluginDefinition;

const customPluginsDefinitions = (await loadDevOverlayPlugins()) as DevOverlayPluginDefinition[];
const plugins: DevOverlayPlugin[] = [
...[astroDevToolPlugin, astroXrayPlugin, astroAuditPlugin, astroSettingsPlugin].map(
(pluginDef) => preparePlugin(pluginDef, true)
),
...[
astroDevToolPlugin,
astroXrayPlugin,
astroAuditPlugin,
astroSettingsPlugin,
astromorePlugin,
].map((pluginDef) => preparePlugin(pluginDef, true)),
...customPluginsDefinitions.map((pluginDef) => preparePlugin(pluginDef, false)),
];

Expand Down
36 changes: 30 additions & 6 deletions packages/astro/src/runtime/client/dev-overlay/overlay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ export type DevOverlayPlugin = DevOverlayPluginDefinition & {
builtIn: boolean;
active: boolean;
status: 'ready' | 'loading' | 'error';
notification: {
state: boolean;
};
eventTarget: EventTarget;
};

Expand All @@ -20,6 +23,7 @@ export class AstroDevOverlay extends HTMLElement {
plugins: DevOverlayPlugin[] = [];
HOVER_DELAY = 750;
hasBeenInitialized = false;
customPluginsToShow = 3;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, this is hardcoded. In the future, we plan to make it so it depends on the width of your screen. Unfortunately, this requires quite some refactoring in how the dev overlay UI is built to ensure compatibility with view transitions and stuff, so will tackle it later.


constructor() {
super();
Expand Down Expand Up @@ -164,8 +168,8 @@ export class AstroDevOverlay extends HTMLElement {
#dev-bar .item .notification {
display: none;
position: absolute;
top: -2px;
right: 0;
top: -4px;
right: -6px;
width: 8px;
height: 8px;
border-radius: 9999px;
Expand Down Expand Up @@ -236,17 +240,27 @@ export class AstroDevOverlay extends HTMLElement {
<div id="dev-bar">
<div id="bar-container">
${this.plugins
.filter((plugin) => plugin.builtIn && plugin.id !== 'astro:settings')
.filter(
(plugin) => plugin.builtIn && !['astro:settings', 'astro:more'].includes(plugin.id)
)
.map((plugin) => this.getPluginTemplate(plugin))
.join('')}
${
this.plugins.filter((plugin) => !plugin.builtIn).length > 0
? `<div class="separator"></div>${this.plugins
.filter((plugin) => !plugin.builtIn)
.slice(0, this.customPluginsToShow)
.map((plugin) => this.getPluginTemplate(plugin))
.join('')}`
: ''
}
${
this.plugins.filter((plugin) => !plugin.builtIn).length > this.customPluginsToShow
? this.getPluginTemplate(
this.plugins.find((plugin) => plugin.builtIn && plugin.id === 'astro:more')!
)
: ''
}
<div class="separator"></div>
${this.getPluginTemplate(
this.plugins.find((plugin) => plugin.builtIn && plugin.id === 'astro:settings')!
Expand Down Expand Up @@ -438,9 +452,19 @@ export class AstroDevOverlay extends HTMLElement {
}

plugin.active = newStatus ?? !plugin.active;
const target = this.shadowRoot.querySelector(`[data-plugin-id="${plugin.id}"]`);
if (!target) return;
target.classList.toggle('active', plugin.active);
const mainBarButton = this.shadowRoot.querySelector(`[data-plugin-id="${plugin.id}"]`);
const moreBarButton = this.getPluginCanvasById('astro:more')?.shadowRoot?.querySelector(
`[data-plugin-id="${plugin.id}"]`
);

if (mainBarButton) {
mainBarButton.classList.toggle('active', plugin.active);
}

if (moreBarButton) {
moreBarButton.classList.toggle('active', plugin.active);
}

pluginCanvas.style.display = plugin.active ? 'block' : 'none';

window.requestAnimationFrame(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ const settingsRows = [
name: 'Disable notifications',
description: 'Notification bubbles will not be shown when this is enabled.',
input: 'checkbox',
settingKey: 'showPluginNotifications',
settingKey: 'disablePluginNotification',
changeEvent: (evt: Event) => {
if (evt.currentTarget instanceof HTMLInputElement) {
settings.updateSetting('showPluginNotifications', evt.currentTarget.checked);
settings.updateSetting('disablePluginNotification', evt.currentTarget.checked);
}
},
},
Expand Down
4 changes: 2 additions & 2 deletions packages/astro/src/runtime/client/dev-overlay/settings.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
export interface Settings {
showPluginNotifications: boolean;
disablePluginNotification: boolean;
verbose: boolean;
}

export const defaultSettings = {
showPluginNotifications: true,
disablePluginNotification: false,
verbose: false,
} satisfies Settings;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,6 @@ const icons = {
'check-circle':
'<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14"><path fill="#fff" d="M10.0306 4.96938c.0699.06967.1254.15247.1633.24363.0378.09116.0573.1889.0573.28762 0 .09871-.0195.19645-.0573.28761-.0379.09116-.0934.17396-.1633.24364L6.53063 9.53187c-.06968.06992-.15247.1254-.24364.16326-.09116.03785-.1889.05734-.28761.05734-.09871 0-.19645-.01949-.28762-.05734-.09116-.03786-.17395-.09334-.24363-.16326l-1.5-1.5c-.06977-.06976-.12511-.15258-.16286-.24373-.03776-.09116-.05719-.18885-.05719-.28752 0-.09866.01943-.19635.05719-.28751.03775-.09115.09309-.17397.16286-.24373.06976-.06977.15259-.12511.24374-.16287.09115-.03775.18885-.05719.28751-.05719s.19636.01944.28751.05719c.09115.03776.17397.0931.24374.16287L6 7.9375l2.96938-2.97c.06978-.06961.15259-.12478.24371-.16237.09111-.03758.18874-.05683.2873-.05666.09856.00018.19612.01978.28711.05768.09098.0379.1736.09337.2431.16323ZM13.75 7c0 1.33502-.3959 2.64007-1.1376 3.7501-.7417 1.11-1.7959 1.9752-3.02928 2.4861-1.23341.5109-2.5906.6446-3.89998.3841-1.30937-.2605-2.5121-.9033-3.45611-1.8473-.944-.944-1.586877-2.14677-1.847328-3.45614-.26045-1.30937-.126777-2.66657.384114-3.89997C1.27471 3.18349 2.13987 2.12928 3.2499 1.38758 4.35994.645881 5.66498.25 7 .25c1.78961.001985 3.5053.713781 4.7708 1.97922C13.0362 3.49466 13.748 5.2104 13.75 7Zm-1.5 0c0-1.03835-.3079-2.05339-.8848-2.91674-.5769-.86336-1.3968-1.53627-2.35611-1.93363-.95931-.39736-2.01491-.50133-3.03331-.29875-1.0184.20257-1.95386.70258-2.68809 1.43681-.73422.73422-1.23424 1.66969-1.43681 2.68809-.20257 1.0184-.0986 2.074.29876 3.03331.39736.95931 1.07026 1.77921 1.93362 2.35611.86336.5769 1.87839.8848 2.91674.8848 1.39193-.0015 2.72643-.5551 3.7107-1.5393C11.6949 9.72642 12.2485 8.39193 12.25 7Z"/></svg>',
gear: '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 22 22"><path fill="#fff" d="M11 6.12507c-.9642 0-1.90671.28592-2.7084.82159-.80169.53567-1.42653 1.29704-1.79551 2.18783-.36898.89081-.46552 1.87101-.27742 2.81661.18811.9457.6524 1.8143 1.33419 2.4961.68178.6818 1.55042 1.1461 2.49604 1.3342.9457.1881 1.9259.0916 2.8167-.2774s1.6521-.9938 2.1878-1.7955c.5357-.8017.8216-1.7442.8216-2.7084-.0015-1.2925-.5156-2.53161-1.4295-3.44553-.9139-.91392-2.153-1.42801-3.4455-1.4295Zm0 7.50003c-.5192 0-1.02669-.154-1.45837-.4424-.43168-.2885-.76813-.6984-.96681-1.1781-.19868-.4796-.25067-1.0074-.14938-1.5166.10129-.50924.35129-.97697.71841-1.34408.36711-.36712.83484-.61712 1.34405-.71841.5092-.10129 1.037-.0493 1.5166.14938.4797.19868.8897.53513 1.1781.96681.2884.43168.4424.9392.4424 1.4584 0 .6962-.2766 1.3638-.7688 1.8561-.4923.4923-1.16.7689-1.8562.7689Zm8.625-2.551v-.1481l1.3125-1.64155c.1102-.13755.1865-.29905.2228-.4715s.0316-.35102-.0137-.52131c-.2369-.89334-.5909-1.75142-1.0528-2.55188-.089-.15264-.2127-.28218-.3611-.37811-.1484-.09594-.3173-.15557-.493-.17408l-2.0888-.23437-.104-.10406-.2344-2.08969c-.0186-.17556-.0783-.34426-.1743-.49247-.0959-.1482-.2254-.27175-.3779-.36066-.8005-.46341-1.6589-.81869-2.5528-1.056559-.1704-.044683-.349-.048704-.5213-.01174-.1723.036965-.3335.113881-.4706.224549l-1.6415 1.3125h-.1482l-1.64152-1.3125C9.14683.9524 8.98532.87608 8.81288.839767c-.17245-.036314-.35102-.031606-.52132.013744-.89357.238319-1.75165.593909-2.55187 1.057499-.15205.08854-.28121.2115-.37712.35901-.0959.14752-.15586.31547-.17507.49037l-.23437 2.08875-.10407.10406-2.08968.23437c-.17556.01865-.34426.07835-.49247.17428-.14821.09593-.27176.22539-.36066.37791-.46211.80072-.81613 1.65912-1.052812 2.55281-.045195.17016-.049823.34855-.013512.52082.03631.17227.112546.33362.222574.47106L2.375 10.926v.1481l-1.3125 1.6416c-.110173.1375-.186492.299-.222806.4715-.036313.1724-.031605.351.013744.5213.238622.8936.594522 1.7517 1.058442 2.5519.08844.1519.21126.281.3586.3769.14734.0959.3151.1559.48983.1753l2.08875.2325.10407.104.23437 2.0916c.01865.1756.07835.3443.17428.4925.09592.1482.22538.2717.37791.3606.80052.4634 1.65893.8187 2.55281 1.0566.17045.0447.349.0487.52129.0117.17228-.0369.33347-.1139.47059-.2245l1.64152-1.3125h.1482l1.6415 1.3125c.1376.1101.2991.1865.4715.2228.1725.0363.351.0316.5213-.0138.8934-.2368 1.7514-.5908 2.5519-1.0528.1524-.0883.2819-.2112.3782-.3587.0962-.1475.1565-.3156.1759-.4907l.2325-2.0887.104-.1041 2.0897-.239c.1751-.0194.3432-.0797.4907-.1759.1475-.0963.2704-.2258.3587-.3782.4634-.8005.8187-1.6589 1.0566-2.5528.0448-.1699.0493-.3479.013-.5198-.0363-.172-.1124-.333-.2221-.4702l-1.3125-1.6416Zm-2.2612-.4584c.015.256.015.5127 0 .7687-.0168.2784.0704.553.2446.7707l1.2038 1.5047c-.1136.3363-.2492.6648-.406.9834l-1.9153.2128c-.2773.0317-.5329.1654-.7171.375-.1704.1919-.3519.3735-.5438.5438-.2096.1842-.3433.4398-.375.7171l-.2119 1.9144c-.3185.1574-.647.2936-.9834.4078l-1.5047-1.2047c-.1997-.1593-.4477-.2459-.7031-.2456h-.0675c-.2561.015-.5127.015-.7688 0-.2781-.0165-.5525.0703-.7706.2438l-1.50469 1.2047c-.33634-.1137-.66486-.2493-.98343-.406l-.21282-1.9153c-.0317-.2773-.16536-.5329-.375-.7172-.19187-.1703-.37344-.3519-.54375-.5437-.18426-.2097-.43988-.3433-.71718-.375l-1.91438-.2119c-.15734-.3185-.29357-.647-.40781-.9834l1.20375-1.5047c.17424-.2177.26144-.4923.24469-.7707-.01501-.256-.01501-.5127 0-.7687.01675-.2783-.07045-.553-.24469-.77063L3.18781 8.34038c.11364-.33634.24924-.66486.40594-.98343l1.91531-.21281c.27731-.03171.53292-.16537.71719-.375.17031-.19188.35188-.37345.54375-.54375.20964-.18427.3433-.43989.375-.71719l.21188-1.91438c.31852-.15734.64704-.29357.98343-.40781L9.845 4.3907c.2181.17343.4925.26023.7706.24375.2561-.015.5127-.015.7688 0 .2782.01701.5528-.06985.7706-.24375l1.5047-1.20469c.3364.11424.6649.25047.9834.40781l.2128 1.91532c.0317.2773.1654.53292.375.71718.1919.17031.3735.35188.5438.54375.1843.20964.4399.3433.7172.375l1.9143.21188c.1574.31852.2936.64704.4079.98343l-1.2038 1.50469c-.1749.21743-.2628.49203-.2465.77063Z"/></svg>',
'dots-three':
'<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 16 4"><path fill="#fff" d="M9.5 2c0 .29667-.08797.58668-.2528.83336-.16482.24667-.39908.43893-.67317.55246-.27409.11353-.57569.14324-.86666.08536-.29098-.05788-.55825-.20074-.76803-.41052-.20978-.20978-.35264-.47705-.41052-.76802-.05788-.29098-.02817-.59258.08536-.86666.11353-.27409.30579-.508362.55247-.673184C7.41332.587974 7.70333.5 8 .5c.39783 0 .77936.158036 1.06066.43934C9.34196 1.22064 9.5 1.60218 9.5 2ZM1.625.5c-.29667 0-.58668.087974-.833354.252796-.246674.164822-.438933.399094-.552465.673184-.113531.27408-.1432361.57568-.085358.86666.057878.29097.200739.55824.410518.76802.209778.20978.477049.35264.768029.41052.29097.05788.59257.02817.86666-.08536.27408-.11353.50835-.30579.67318-.55246C3.03703 2.58668 3.125 2.29667 3.125 2c0-.39782-.15803-.77936-.43934-1.06066C2.40436.658036 2.02283.5 1.625.5Zm12.75 0c-.2967 0-.5867.087974-.8334.252796-.2466.164822-.4389.399094-.5524.673184-.1135.27408-.1433.57568-.0854.86666.0579.29097.2008.55824.4105.76802.2098.20978.4771.35264.7681.41052.2909.05788.5925.02817.8666-.08536s.5084-.30579.6732-.55246c.1648-.24668.2528-.53669.2528-.83336 0-.39782-.158-.77936-.4393-1.06066C15.1544.658036 14.7728.5 14.375.5Z"/></svg>',
} as const;
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,12 @@ export class DevOverlayToggle extends HTMLElement {
this.input.type = 'checkbox';
this.shadowRoot.append(this.input);
}

get value() {
return this.input.value;
}

set value(val) {
this.input.value = val;
}
}
Loading