diff --git a/src/cards/trash-card/container/cards.ts b/src/cards/trash-card/container/cards.ts index ed38056..03a913c 100644 --- a/src/cards/trash-card/container/cards.ts +++ b/src/cards/trash-card/container/cards.ts @@ -47,7 +47,7 @@ class Cards extends LitElement implements BaseContainerElement { const cssStyleMap = styleMap({ // eslint-disable-next-line @typescript-eslint/naming-convention - 'grid-template-columns': `repeat(${itemsPerRow}, calc(calc(100% - calc(${(itemsPerRow - 1)} * var(--grid-card-gap, 2px))) / ${itemsPerRow}))` + 'grid-template-columns': `repeat(${itemsPerRow}, calc(calc(100% - calc(${itemsPerRow - 1} * var(--grid-card-gap, 2px))) / ${itemsPerRow}))` }); return html` diff --git a/src/cards/trash-card/elements/icon.ts b/src/cards/trash-card/elements/icon.ts index 2a29946..5a194d4 100644 --- a/src/cards/trash-card/elements/icon.ts +++ b/src/cards/trash-card/elements/icon.ts @@ -7,7 +7,7 @@ import type { CardStyleConfig } from '../trash-card-config'; import type { CalendarItem } from '../../../utils/calendarItem'; @customElement(`${TRASH_CARD_NAME}-element-icon`) -class ItemCard extends LitElement { +class Icon extends LitElement { @state() private readonly item?: CalendarItem; @state() private readonly hass?: HomeAssistant; @@ -41,5 +41,5 @@ class ItemCard extends LitElement { } export { - ItemCard + Icon }; diff --git a/src/cards/trash-card/elements/picture.ts b/src/cards/trash-card/elements/picture.ts new file mode 100644 index 0000000..9259967 --- /dev/null +++ b/src/cards/trash-card/elements/picture.ts @@ -0,0 +1,43 @@ +import { LitElement, css, html, nothing } from 'lit'; +import { customElement, state } from 'lit/decorators.js'; +import { TRASH_CARD_NAME } from '../const'; + +import type { HomeAssistant } from '../../../utils/ha'; +import type { CardStyleConfig } from '../trash-card-config'; +import type { CalendarItem } from '../../../utils/calendarItem'; + +@customElement(`${TRASH_CARD_NAME}-element-picture`) +class Picture extends LitElement { + @state() private readonly item?: CalendarItem; + + @state() private readonly hass?: HomeAssistant; + + @state() private readonly config?: CardStyleConfig; + + @state() private readonly pictureUrl?: string; + + public render () { + if (!this.pictureUrl) { + return nothing; + } + + return html``; + } + + public static get styles () { + return [ + css` + img { + height: var(--mdc-icon-size); + width: var(--mdc-icon-size); + object-fit: contain; + } + ` + ]; + } +} + +export { + Picture +}; diff --git a/src/cards/trash-card/formSchemas.ts b/src/cards/trash-card/formSchemas.ts index baa0880..b9d4aed 100644 --- a/src/cards/trash-card/formSchemas.ts +++ b/src/cards/trash-card/formSchemas.ts @@ -35,6 +35,15 @@ const getPatternSchema = (customLocalize: ReturnType selector: { text: {} } + }, + { + label: customLocalize(`editor.card.trash.pattern.fields.picture_url`), + helper: customLocalize(`editor.card.trash.pattern.fields.picture_url_description`), + name: 'picture', + selector: { + text: {} + }, + context: { icon_entity: 'entity' } } ]; diff --git a/src/cards/trash-card/items/BaseItemElement.ts b/src/cards/trash-card/items/BaseItemElement.ts index 858dd80..9610ccb 100644 --- a/src/cards/trash-card/items/BaseItemElement.ts +++ b/src/cards/trash-card/items/BaseItemElement.ts @@ -1,8 +1,12 @@ /* eslint-disable unicorn/filename-case */ import { LitElement, css, html } from 'lit'; import { state } from 'lit/decorators.js'; +import { getPicture } from '../../../utils/getPicture'; import { classMap } from 'lit-html/directives/class-map.js'; +import '../elements/icon'; +import '../elements/picture'; + import type { CardStyleConfig } from '../trash-card-config'; import type { CalendarItem } from '../../../utils/calendarItem'; import type { HomeAssistant } from '../../../utils/ha'; @@ -15,8 +19,11 @@ class BaseItemElement extends LitElement { @state() protected readonly config?: CardStyleConfig; - // eslint-disable-next-line @typescript-eslint/no-inferrable-types - protected withBackground: boolean = false; + protected withBackground = false; + + protected getPictureUrl () { + return getPicture(this.item!.picture, this.hass!); + } protected getWithBackgroundClass () { return { @@ -24,6 +31,20 @@ class BaseItemElement extends LitElement { }; } + protected renderPicture (pictureUrl: string) { + const cssClass = { + ...this.getWithBackgroundClass() + }; + + return html` + `; + } + protected renderIcon () { const cssClass = { ...this.getWithBackgroundClass() diff --git a/src/cards/trash-card/items/card.ts b/src/cards/trash-card/items/card.ts index 11f72a9..9068a32 100644 --- a/src/cards/trash-card/items/card.ts +++ b/src/cards/trash-card/items/card.ts @@ -8,8 +8,6 @@ import { defaultHaCardStyle } from '../../../utils/defaultHaCardStyle'; import { getColoredStyle } from '../../../utils/getColoredStyle'; import { BaseItemElement } from './BaseItemElement'; -import '../elements/icon'; - @customElement(`${TRASH_CARD_NAME}-item-card`) class ItemCard extends BaseItemElement { public render () { @@ -32,15 +30,17 @@ class ItemCard extends BaseItemElement { const secondary = getDateString(item, hide_time_range ?? false, day_style, this.hass); + const pictureUrl = this.getPictureUrl(); + this.withBackground = true; return html` - - ${this.renderIcon()} - +
+ ${pictureUrl ? this.renderPicture(pictureUrl) : this.renderIcon()} +
- ${this.renderIcon()} + ${pictureUrl ? this.renderPicture(pictureUrl) : this.renderIcon()} ${with_label ? html`${item.label}` : nothing} ${content ? html`${content}` : nothing} @@ -52,7 +52,7 @@ class ItemChip extends BaseItemElement { ...BaseItemElement.styles, css` mushroom-chip { - --mdc-icon-size: 16px; + --mdc-icon-size: var(--trash-card-icon-size, 16px); --chip-background: var(--trash-card-background, var(--ha-card-background, var(--card-background-color, #fff) diff --git a/src/cards/trash-card/items/icon.ts b/src/cards/trash-card/items/icon.ts index cbe01a6..71b7520 100644 --- a/src/cards/trash-card/items/icon.ts +++ b/src/cards/trash-card/items/icon.ts @@ -9,8 +9,6 @@ import { getColoredStyle } from '../../../utils/getColoredStyle'; import { daysTill } from '../../../utils/daysTill'; import { BaseItemElement } from './BaseItemElement'; -import '../elements/icon'; - @customElement(`${TRASH_CARD_NAME}-icon-card`) class IconCard extends BaseItemElement<{ nextEvent: boolean }> { public render () { @@ -26,7 +24,7 @@ class IconCard extends BaseItemElement<{ nextEvent: boolean }> { const style = { ...getColoredStyle([ 'icon', 'background' ], item), // eslint-disable-next-line @typescript-eslint/naming-convention - '--trash-card-icon-size': `${this.config.icon_size}px` + '--trash-card-icon-size': `${this.config.icon_size ?? 40}px` }; const cssClass = { @@ -36,15 +34,17 @@ class IconCard extends BaseItemElement<{ nextEvent: boolean }> { const daysLeft = daysTill(item); + const pictureUrl = this.getPictureUrl(); + this.withBackground = true; return html` - - ${this.renderIcon()} - +
+ ${pictureUrl ? this.renderPicture(pictureUrl) : this.renderIcon()} +
${daysLeft} @@ -89,10 +89,6 @@ class IconCard extends BaseItemElement<{ nextEvent: boolean }> { box-shadow: var(--chip-box-shadow); box-sizing: content-box; } - .nextEvent .badge { - font-size: 90; - - } ` ]; } diff --git a/src/cards/trash-card/trash-card-config.ts b/src/cards/trash-card/trash-card-config.ts index f3c6615..b9b7307 100644 --- a/src/cards/trash-card/trash-card-config.ts +++ b/src/cards/trash-card/trash-card-config.ts @@ -38,6 +38,7 @@ type EntityWithOutIcon = Omit; card_style?: typeof CARDSTYLES[number]; color_mode?: typeof COLORMODES[number]; refresh_rate?: number; + icon_size?: number; debug?: boolean; with_label?: boolean; }; @@ -73,6 +74,7 @@ const entityCardConfigStruct = assign( icon: optional(string()), label: optional(string()), pattern: optional(string()), + picture: optional(string()), type: string() }) )) diff --git a/src/translations/de.json b/src/translations/de.json index e29e2a8..76a3454 100644 --- a/src/translations/de.json +++ b/src/translations/de.json @@ -78,7 +78,9 @@ "label": "Bezeichnung", "color": "Farbe", "icon": "Symbol", - "pattern": "erkennen an Muster" + "pattern": "erkennen an Muster", + "picture_url": "Bild URL", + "picture_url_description": "Wenn eine Bild URL angegeben wird, wird das entsprechende Bild anstelle das Icon angezeigt. Lege ein Bild in dem `/config/www` Ordner ab und verwende `/local/[Dateiname]`." } } } diff --git a/src/translations/en.json b/src/translations/en.json index ce1507e..4b4a588 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -78,7 +78,9 @@ "label": "Label", "color": "Color", "icon": "Icon", - "pattern": "Detection pattern" + "pattern": "Detection pattern", + "picture_url": "Picture URL", + "picture_url_description": "If a picture URL is specified, the corresponding picture is displayed instead of the icon. Place an image in the `/config/www` folder and use `/local/[filename]`." } } } diff --git a/src/translations/fr.json b/src/translations/fr.json index 11d6e2e..442f9d9 100644 --- a/src/translations/fr.json +++ b/src/translations/fr.json @@ -78,7 +78,9 @@ "label": "Étiquette", "color": "Couleur", "icon": "Icône", - "pattern": "Modèle de détection" + "pattern": "Modèle de détection", + "picture_url" : "URL de l'image", + "picture_url_description" : "Si une URL d'image est indiquée, l'image correspondante sera affichée au lieu de l'icône. Placez une image dans le dossier `/config/www` et utilisez `/local/[nom de fichier]`" } } } diff --git a/src/translations/hu.json b/src/translations/hu.json index 45beff6..e4674dd 100644 --- a/src/translations/hu.json +++ b/src/translations/hu.json @@ -78,7 +78,9 @@ "label": "Cimke", "color": "Szín", "icon": "Ikon", - "pattern": "Felismerési minta" + "pattern": "Felismerési minta", + "picture_url": "Kép URL címe", + "picture_url_description": "Ha egy kép URL címe van megadva, akkor az ikon helyett a megfelelő kép jelenik meg. Helyezzen el egy képet a `/config/www` mappában, és használja a `/local/[fájlnév]`" } } } diff --git a/src/translations/it.json b/src/translations/it.json index d4cf032..33d1d08 100644 --- a/src/translations/it.json +++ b/src/translations/it.json @@ -78,7 +78,9 @@ "label": "Etichetta", "color": "Colore", "icon": "Icona", - "pattern": "Pattern identificazione" + "pattern": "Pattern identificazione", + "picture_url": "URL immagine", + "picture_url_description": "Se viene specificato un URL dell'immagine, al posto dell'icona viene visualizzata l'immagine corrispondente. Posizionare un'immagine nella cartella `/config/www` e utilizzare `/local/[filename]`." } } } diff --git a/src/translations/pl.json b/src/translations/pl.json index 3853c0c..cdbcde3 100644 --- a/src/translations/pl.json +++ b/src/translations/pl.json @@ -78,7 +78,9 @@ "label": "Oznaczenie", "color": "Kolor", "icon": "Ikona", - "pattern": "Szablon wzorca" + "pattern": "Szablon wzorca", + "picture_url": "Adres URL obrazka", + "picture_url_description": "Jeśli podano adres URL obrazu, odpowiedni obraz jest wyświetlany zamiast ikony. Umieść obrazek w folderze `/config/www` i użyj `/local/[nazwa_pliku]`." } } } diff --git a/src/translations/sk.json b/src/translations/sk.json index f847954..414a8a8 100644 --- a/src/translations/sk.json +++ b/src/translations/sk.json @@ -78,7 +78,9 @@ "label": "štítok", "color": "Farba", "icon": "Ikona", - "pattern": "Vzor detekcie" + "pattern": "Vzor detekcie", + "picture_url": "URL obrázku", + "picture_url_description": "Ak je zadaná adresa URL obrázka, namiesto ikony sa zobrazí príslušný obrázok. Umiestnite obrázok do priečinka `/config/www` a použite `/local/[meno súboru]`." } } } diff --git a/src/utils/calendarItem.ts b/src/utils/calendarItem.ts index e47b30e..d711191 100644 --- a/src/utils/calendarItem.ts +++ b/src/utils/calendarItem.ts @@ -5,6 +5,7 @@ interface CalendarItem extends CalendarEvent { color?: string; icon?: string; type: `custom-${number}` | 'organic' | 'paper' | 'recycle' | 'waste' | 'others'; + picture?: string; } export type { diff --git a/src/utils/eventsToItems.ts b/src/utils/eventsToItems.ts index 3401c54..850a36f 100644 --- a/src/utils/eventsToItems.ts +++ b/src/utils/eventsToItems.ts @@ -21,9 +21,8 @@ const getLabel = (event: CalendarEvent, settings: ItemSettings, useSummary: bool const getData = (event: CalendarEvent, pattern: Pattern & { idx: number }, useSummary: boolean): CalendarItem => ({ ...event, + ...pattern, label: getLabel(event, pattern, useSummary), - icon: pattern.icon!, - color: pattern.color!, type: pattern.type === 'custom' ? `custom-${pattern.idx}` : pattern.type }); diff --git a/src/utils/getPicture.ts b/src/utils/getPicture.ts new file mode 100644 index 0000000..90d1e8b --- /dev/null +++ b/src/utils/getPicture.ts @@ -0,0 +1,8 @@ +import type { HomeAssistant } from './ha'; + +const getPicture = (url: string | undefined, hass: HomeAssistant): string | undefined => + url ? `${hass.hassUrl(url)}` : undefined; + +export { + getPicture +}; diff --git a/src/utils/itemSettings.ts b/src/utils/itemSettings.ts index 66ce5f6..959afe7 100644 --- a/src/utils/itemSettings.ts +++ b/src/utils/itemSettings.ts @@ -4,6 +4,7 @@ interface ItemSettings { pattern?: string; icon?: string; type: 'custom' | 'organic' | 'paper' | 'recycle' | 'waste' | 'others'; + picutre?: string; } export type {