Skip to content
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
20 changes: 20 additions & 0 deletions .changeset/tidy-moles-brush.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
'astro': minor
---

Adds optional `placement` config option for the dev toolbar.

You can now configure the default toolbar position (`'bottom-left'`, `'bottom-center'`, or `'bottom-right'`) via `devToolbar.placement` in your Astro config. This option is helpful for sites with UI elements (chat widgets, cookie banners) that are consistently obscured by the toolbar in the dev environment.

You can set a project default that is consistent across environments (e.g. dev machines, browser instances, team members):

```js
// astro.config.mjs
export default defineConfig({
devToolbar: {
placement: 'bottom-left',
},
});
```

User preferences from the toolbar UI (stored in `localStorage`) still take priority, so this setting can be overridden in individual situations as necessary.
1 change: 1 addition & 0 deletions packages/astro/src/core/config/schemas/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ export const AstroConfigSchema = z.object({
devToolbar: z
.object({
enabled: z.boolean().default(ASTRO_CONFIG_DEFAULTS.devToolbar.enabled),
placement: z.enum(['bottom-left', 'bottom-center', 'bottom-right']).optional(),
})
.default(ASTRO_CONFIG_DEFAULTS.devToolbar),
markdown: z
Expand Down
12 changes: 11 additions & 1 deletion packages/astro/src/runtime/client/dev-toolbar/settings.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { Placement } from './ui-library/window.js';
import type { DevToolbarMetadata } from '../../../types/public/toolbar.js';
import { isValidPlacement, type Placement } from './ui-library/window.js';

export interface Settings {
disableAppNotification: boolean;
Expand All @@ -15,7 +16,16 @@ export const defaultSettings = {
export const settings = getSettings();

function getSettings() {
// 1. Start with hardcoded defaults
let _settings: Settings = { ...defaultSettings };

// 2. Override with config placement (if provided)
const configPlacement = (globalThis as DevToolbarMetadata).__astro_dev_toolbar__?.placement;
if (configPlacement && isValidPlacement(configPlacement)) {
_settings.placement = configPlacement;
}

// 3. Override with localStorage (preserves user's UI choice)
const toolbarSettings = localStorage.getItem('astro:dev-toolbar:settings');

if (toolbarSettings) {
Expand Down
13 changes: 13 additions & 0 deletions packages/astro/src/types/public/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1171,6 +1171,19 @@ export interface AstroUserConfig<
* This option is scoped to the entire project, to only disable the toolbar for yourself, run `npm run astro preferences disable devToolbar`. To disable the toolbar for all your Astro projects, run `npm run astro preferences disable devToolbar --global`.
*/
enabled: boolean;

/**
* @docs
* @name devToolbar.placement
Comment thread
tony marked this conversation as resolved.
* @version 5.17.0
* @type {'bottom-left' | 'bottom-center' | 'bottom-right'}
* @default `'bottom-center'`
* @description
* The default placement of the Astro Dev Toolbar on the screen.
*
* The placement of the toolbar can still be changed via the toolbar settings UI. Once changed, the user's preference is saved in `localStorage` and overrides this configuration value.
*/
placement?: 'bottom-left' | 'bottom-center' | 'bottom-right';
};

/**
Expand Down
3 changes: 3 additions & 0 deletions packages/astro/src/types/public/toolbar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,15 @@ export type DevToolbarApp = {
// An app that has been loaded and as such contain all of its properties
export type ResolvedDevToolbarApp = DevToolbarAppMeta & DevToolbarApp;

export type DevToolbarPlacement = 'bottom-left' | 'bottom-center' | 'bottom-right';

export type DevToolbarMetadata = Window &
typeof globalThis & {
__astro_dev_toolbar__: {
root: string;
version: string;
latestAstroVersion: string | undefined;
debugInfo: string;
placement?: DevToolbarPlacement;
};
};
1 change: 1 addition & 0 deletions packages/astro/src/vite-plugin-astro-server/pipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ export class DevPipeline extends Pipeline {
// enabled, it would nice to request the debug info through import.meta.hot
// when the button is click to defer execution as much as possible
debugInfo: await this.getDebugInfo(),
placement: settings.config.devToolbar.placement,
};

// Additional data for the dev overlay
Expand Down
25 changes: 25 additions & 0 deletions packages/astro/test/units/config/config-validate.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -589,4 +589,29 @@ describe('Config Validation', () => {
);
});
});

describe('devToolbar', () => {
it('should allow valid placement values', async () => {
for (const placement of ['bottom-left', 'bottom-center', 'bottom-right']) {
const result = await validateConfig({
devToolbar: { placement },
});
assert.equal(result.devToolbar.placement, placement);
}
});

it('should allow omitting placement (optional)', async () => {
const result = await validateConfig({
devToolbar: { enabled: true },
});
assert.equal(result.devToolbar.placement, undefined);
});

it('should reject invalid placement values', async () => {
const configError = await validateConfig({
devToolbar: { placement: 'top-left' },
}).catch((err) => err);
assert.equal(configError instanceof z.ZodError, true);
});
});
});