From 959ca5f9f86ef2c0a5a23080cc01c25f53d613a9 Mon Sep 17 00:00:00 2001 From: Erika <3019731+Princesseuh@users.noreply.github.com> Date: Fri, 8 Mar 2024 11:52:50 +0100 Subject: [PATCH] feat(toolbar): Allow every element to have every color (#10186) * feat(toolbar): Allow every element to have every color * chore: changeset * fix: add validatio * fix: ok but what happened even * nit: cooler messages * fix: toggles --- .changeset/khaki-elephants-hang.md | 5 + .../runtime/client/dev-toolbar/settings.ts | 10 +- .../client/dev-toolbar/ui-library/badge.ts | 120 +++++++++---- .../client/dev-toolbar/ui-library/button.ts | 163 ++++++++++++------ .../client/dev-toolbar/ui-library/card.ts | 72 +++++++- .../dev-toolbar/ui-library/highlight.ts | 66 ++++++- .../client/dev-toolbar/ui-library/toggle.ts | 76 +++++++- 7 files changed, 413 insertions(+), 99 deletions(-) create mode 100644 .changeset/khaki-elephants-hang.md diff --git a/.changeset/khaki-elephants-hang.md b/.changeset/khaki-elephants-hang.md new file mode 100644 index 000000000000..fded6066008d --- /dev/null +++ b/.changeset/khaki-elephants-hang.md @@ -0,0 +1,5 @@ +--- +"astro": minor +--- + +Adds the ability to set colors on all the included UI elements for dev toolbar apps. Previously, only badge and buttons could be customized. diff --git a/packages/astro/src/runtime/client/dev-toolbar/settings.ts b/packages/astro/src/runtime/client/dev-toolbar/settings.ts index ee7386d4f565..d031b636da1d 100644 --- a/packages/astro/src/runtime/client/dev-toolbar/settings.ts +++ b/packages/astro/src/runtime/client/dev-toolbar/settings.ts @@ -30,9 +30,9 @@ function getSettings() { localStorage.setItem('astro:dev-toolbar:settings', JSON.stringify(_settings)); } - function log(message: string) { + function log(message: string, level: 'log' | 'warn' | 'error' = 'log') { // eslint-disable-next-line no-console - console.log( + console[level]( `%cAstro`, 'background: linear-gradient(66.77deg, #D83333 0%, #F041FF 100%); color: white; padding-inline: 4px; border-radius: 2px; font-family: monospace;', message @@ -46,6 +46,12 @@ function getSettings() { updateSetting, logger: { log, + warn: (message: string) => { + log(message, 'warn'); + }, + error: (message: string) => { + log(message, 'error'); + }, verboseLog: (message: string) => { if (_settings.verbose) { log(message); diff --git a/packages/astro/src/runtime/client/dev-toolbar/ui-library/badge.ts b/packages/astro/src/runtime/client/dev-toolbar/ui-library/badge.ts index 9d10b65be27a..5d45f071bbe8 100644 --- a/packages/astro/src/runtime/client/dev-toolbar/ui-library/badge.ts +++ b/packages/astro/src/runtime/client/dev-toolbar/ui-library/badge.ts @@ -1,22 +1,53 @@ -type BadgeSize = 'small' | 'large'; -type BadgeStyle = 'purple' | 'gray' | 'red' | 'green' | 'yellow'; +import { settings } from '../settings.js'; + +const sizes = ['small', 'large'] as const; +const styles = ['purple', 'gray', 'red', 'green', 'yellow', 'blue'] as const; + +type BadgeSize = (typeof sizes)[number]; +type BadgeStyle = (typeof styles)[number]; export class DevToolbarBadge extends HTMLElement { - size: BadgeSize = 'small'; - badgeStyle: BadgeStyle = 'purple'; + _size: BadgeSize = 'small'; + _badgeStyle: BadgeStyle = 'purple'; + + get size() { + return this._size; + } + + set size(value) { + if (!sizes.includes(value)) { + settings.logger.error( + `Invalid size: ${value}, expected one of ${sizes.join(', ')}, got ${value}.` + ); + return; + } + this._size = value; + this.updateStyle(); + } + + get badgeStyle() { + return this._badgeStyle; + } + + set badgeStyle(value) { + if (!styles.includes(value)) { + settings.logger.error( + `Invalid style: ${value}, expected one of ${styles.join(', ')}, got ${value}.` + ); + return; + } + this._badgeStyle = value; + this.updateStyle(); + } shadowRoot: ShadowRoot; + static observedAttributes = ['badge-style', 'size']; + constructor() { super(); this.shadowRoot = this.attachShadow({ mode: 'open' }); - if (this.hasAttribute('size')) this.size = this.getAttribute('size') as BadgeSize; - - if (this.hasAttribute('badge-style')) - this.badgeStyle = this.getAttribute('badge-style') as BadgeStyle; - - const classes = [`badge--${this.size}`, `badge--${this.badgeStyle}`]; this.shadowRoot.innerHTML = ` + -
+
`; } + + connectedCallback() { + this.updateStyle(); + } + + attributeChangedCallback() { + if (this.hasAttribute('badge-style')) + this.badgeStyle = this.getAttribute('badge-style') as BadgeStyle; + + if (this.hasAttribute('size')) this.size = this.getAttribute('size') as BadgeSize; + } + + updateStyle() { + const style = this.shadowRoot.getElementById('selected-style') as HTMLStyleElement; + + style.innerHTML = ` + .badge { + --text-color: var(--${this.badgeStyle}-text); + --border-color: var(--${this.badgeStyle}-border); + --size: var(--${this.size}); + } + `; + } } diff --git a/packages/astro/src/runtime/client/dev-toolbar/ui-library/button.ts b/packages/astro/src/runtime/client/dev-toolbar/ui-library/button.ts index 3f625376d774..c63528c4447e 100644 --- a/packages/astro/src/runtime/client/dev-toolbar/ui-library/button.ts +++ b/packages/astro/src/runtime/client/dev-toolbar/ui-library/button.ts @@ -1,9 +1,46 @@ -type ButtonSize = 'small' | 'medium' | 'large'; -type ButtonStyle = 'ghost' | 'outline' | 'purple' | 'gray' | 'red'; +import { settings } from '../settings.js'; + +const sizes = ['small', 'medium', 'large'] as const; +const styles = ['ghost', 'outline', 'purple', 'gray', 'red', 'green', 'yellow', 'blue'] as const; + +type ButtonSize = (typeof sizes)[number]; +type ButtonStyle = (typeof styles)[number]; export class DevToolbarButton extends HTMLElement { - size: ButtonSize = 'small'; - buttonStyle: ButtonStyle = 'purple'; + _size: ButtonSize = 'small'; + _buttonStyle: ButtonStyle = 'purple'; + + get size() { + return this._size; + } + + set size(value) { + if (!sizes.includes(value)) { + settings.logger.error( + `Invalid size: ${value}, expected one of ${sizes.join(', ')}, got ${value}.` + ); + return; + } + this._size = value; + this.updateStyle(); + } + + get buttonStyle() { + return this._buttonStyle; + } + + set buttonStyle(value) { + if (!styles.includes(value)) { + settings.logger.error( + `Invalid style: ${value}, expected one of ${styles.join(', ')}, got ${value}.` + ); + return; + } + this._buttonStyle = value; + this.updateStyle(); + } + + static observedAttributes = ['button-style', 'size']; shadowRoot: ShadowRoot; @@ -11,65 +48,63 @@ export class DevToolbarButton extends HTMLElement { super(); this.shadowRoot = this.attachShadow({ mode: 'open' }); - if (this.hasAttribute('size')) this.size = this.getAttribute('size') as ButtonSize; - - if (this.hasAttribute('button-style')) - this.buttonStyle = this.getAttribute('button-style') as ButtonStyle; - - const classes = [`button--${this.size}`, `button--${this.buttonStyle}`]; - this.shadowRoot.innerHTML = ` + - `; } + + connectedCallback() { + this.updateStyle(); + } + + updateStyle() { + const style = this.shadowRoot.getElementById('selected-style') as HTMLStyleElement; + + style.innerHTML = ` + button { + --background: var(--${this.buttonStyle}-background); + --border: var(--${this.buttonStyle}-border); + --font-size: var(--${this.size}-font-size); + --padding: var(--${this.size}-padding); + --text-color: var(--${this.buttonStyle}-text); + } + `; + } + + attributeChangedCallback() { + if (this.hasAttribute('size')) this.size = this.getAttribute('size') as ButtonSize; + + if (this.hasAttribute('button-style')) + this.buttonStyle = this.getAttribute('button-style') as ButtonStyle; + } } diff --git a/packages/astro/src/runtime/client/dev-toolbar/ui-library/card.ts b/packages/astro/src/runtime/client/dev-toolbar/ui-library/card.ts index 6d1d5c381b19..82113b21bd6e 100644 --- a/packages/astro/src/runtime/client/dev-toolbar/ui-library/card.ts +++ b/packages/astro/src/runtime/client/dev-toolbar/ui-library/card.ts @@ -1,8 +1,33 @@ +import { settings } from '../settings.js'; + +const styles = ['purple', 'gray', 'red', 'green', 'yellow', 'blue'] as const; + +type CardStyle = (typeof styles)[number]; + export class DevToolbarCard extends HTMLElement { link?: string | undefined | null; clickAction?: () => void | (() => Promise); shadowRoot: ShadowRoot; + _cardStyle: CardStyle = 'purple'; + + get cardStyle() { + return this._cardStyle; + } + + set cardStyle(value) { + if (!styles.includes(value)) { + settings.logger.error( + `Invalid style: ${value}, expected one of ${styles.join(', ')}, got ${value}.` + ); + return; + } + this._cardStyle = value; + this.updateStyle(); + } + + static observedAttributes = ['card-style']; + constructor() { super(); this.shadowRoot = this.attachShadow({ mode: 'open' }); @@ -10,11 +35,51 @@ export class DevToolbarCard extends HTMLElement { this.link = this.getAttribute('link'); } + attributeChangedCallback() { + if (this.hasAttribute('card-style')) + this.cardStyle = this.getAttribute('card-style') as CardStyle; + + this.updateStyle(); + } + + updateStyle() { + const style = this.shadowRoot.getElementById('selected-style'); + + if (style) { + style.innerHTML = ` + :host { + --hover-background: var(--${this.cardStyle}-hover-background); + --hover-border: var(--${this.cardStyle}-hover-border); + } + `; + } + } + connectedCallback() { const element = this.link ? 'a' : this.clickAction ? 'button' : 'div'; this.shadowRoot.innerHTML += ` + <${element}${this.link ? ` href="${this.link}" target="_blank"` : ``} id="astro-overlay-card"> `; + this.updateStyle(); + if (this.clickAction) { this.shadowRoot .getElementById('astro-overlay-card') diff --git a/packages/astro/src/runtime/client/dev-toolbar/ui-library/highlight.ts b/packages/astro/src/runtime/client/dev-toolbar/ui-library/highlight.ts index 2dbe1a9eb8b0..fa6d06ad9b98 100644 --- a/packages/astro/src/runtime/client/dev-toolbar/ui-library/highlight.ts +++ b/packages/astro/src/runtime/client/dev-toolbar/ui-library/highlight.ts @@ -1,7 +1,30 @@ -import { type Icon, getIconElement, isDefinedIcon } from './icons.js'; +import { getIconElement, isDefinedIcon, type Icon } from './icons.js'; +import { settings } from '../settings.js'; + +const styles = ['purple', 'gray', 'red', 'green', 'yellow', 'blue'] as const; + +type HighlightStyle = (typeof styles)[number]; export class DevToolbarHighlight extends HTMLElement { icon?: Icon | undefined | null; + _highlightStyle: HighlightStyle = 'purple'; + + get highlightStyle() { + return this._highlightStyle; + } + + set highlightStyle(value) { + if (!styles.includes(value)) { + settings.logger.error( + `Invalid style: ${value}, expected one of ${styles.join(', ')}, got ${value}.` + ); + return; + } + this._highlightStyle = value; + this.updateStyle(); + } + + static observedAttributes = ['highlight-style']; shadowRoot: ShadowRoot; @@ -14,14 +37,33 @@ export class DevToolbarHighlight extends HTMLElement { this.shadowRoot.innerHTML = ` + `; } + updateStyle() { + const style = this.shadowRoot.getElementById('selected-style') as HTMLStyleElement; + style.innerHTML = ` + :host { + --background: var(--${this.highlightStyle}-background); + --border: var(--${this.highlightStyle}-border); + } + `; + } + + attributeChangedCallback() { + if (this.hasAttribute('highlight-style')) + this.highlightStyle = this.getAttribute('highlight-style') as HighlightStyle; + } + connectedCallback() { + this.updateStyle(); + if (this.icon) { let iconContainer = document.createElement('div'); iconContainer.classList.add('icon'); diff --git a/packages/astro/src/runtime/client/dev-toolbar/ui-library/toggle.ts b/packages/astro/src/runtime/client/dev-toolbar/ui-library/toggle.ts index 9b45fb14d78a..7d8cb71bafdb 100644 --- a/packages/astro/src/runtime/client/dev-toolbar/ui-library/toggle.ts +++ b/packages/astro/src/runtime/client/dev-toolbar/ui-library/toggle.ts @@ -1,6 +1,28 @@ +import { settings } from '../settings.js'; + +const styles = ['purple', 'gray', 'red', 'green', 'yellow', 'blue'] as const; + +type ToggleStyle = (typeof styles)[number]; + export class DevToolbarToggle extends HTMLElement { shadowRoot: ShadowRoot; input: HTMLInputElement; + _toggleStyle: ToggleStyle = 'gray'; + + get toggleStyle() { + return this._toggleStyle; + } + + set toggleStyle(value) { + if (!styles.includes(value)) { + settings.logger.error(`Invalid style: ${value}, expected one of ${styles.join(', ')}.`); + return; + } + this._toggleStyle = value; + this.updateStyle(); + } + + static observedAttributes = ['toggle-style']; constructor() { super(); @@ -8,11 +30,37 @@ export class DevToolbarToggle extends HTMLElement { this.shadowRoot.innerHTML = ` + `; this.input = document.createElement('input'); } + attributeChangedCallback() { + if (this.hasAttribute('toggle-style')) + this.toggleStyle = this.getAttribute('toggle-style') as ToggleStyle; + } + + updateStyle() { + const style = this.shadowRoot.getElementById('selected-style') as HTMLStyleElement; + style.innerHTML = ` + :host { + --bg-on: var(--${this.toggleStyle}-bg-on); + --border-off: var(--${this.toggleStyle}-border-off); + --border-on: var(--${this.toggleStyle}-border-on); + } + `; + } + connectedCallback() { this.input.type = 'checkbox'; this.shadowRoot.append(this.input); + this.updateStyle(); } get value() {