mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-24 09:46:36 +00:00
Clean domain icons (#19533)
* Use state icon inside alarm control panel card * Add domain icon component and clean old files * Clean code * Migrate area card * Remove some icon rules * Update ha-bar-media-player.ts Co-authored-by: Bram Kragten <mail@bramkragten.nl> * Update ha-domain-icon.ts Co-authored-by: Bram Kragten <mail@bramkragten.nl> --------- Co-authored-by: Bram Kragten <mail@bramkragten.nl>
This commit is contained in:
parent
6dcc70f6fc
commit
314499005d
@ -1,6 +1,7 @@
|
||||
/** Constants to be used in the frontend. */
|
||||
|
||||
import {
|
||||
mdiAccount,
|
||||
mdiAirFilter,
|
||||
mdiAlert,
|
||||
mdiAngleAcute,
|
||||
@ -50,8 +51,10 @@ import {
|
||||
mdiProgressClock,
|
||||
mdiRayVertex,
|
||||
mdiRemote,
|
||||
mdiRobot,
|
||||
mdiRobotMower,
|
||||
mdiRobotVacuum,
|
||||
mdiRoomService,
|
||||
mdiScriptText,
|
||||
mdiSineWave,
|
||||
mdiSpeakerMessage,
|
||||
@ -61,6 +64,7 @@ import {
|
||||
mdiThermometerLines,
|
||||
mdiThermostat,
|
||||
mdiTimerOutline,
|
||||
mdiToggleSwitch,
|
||||
mdiTransmissionTower,
|
||||
mdiWater,
|
||||
mdiWaterPercent,
|
||||
@ -69,6 +73,7 @@ import {
|
||||
mdiWeatherRainy,
|
||||
mdiWeatherWindy,
|
||||
mdiWeight,
|
||||
mdiWhiteBalanceSunny,
|
||||
mdiWifi,
|
||||
} from "@mdi/js";
|
||||
|
||||
@ -78,6 +83,9 @@ import { mdiHomeAssistant } from "../resources/home-assistant-logo-svg";
|
||||
// Arrays with values should be alphabetically sorted if order doesn't matter.
|
||||
// Each constant should have a description what it is supposed to be used for.
|
||||
|
||||
/** Icon to use when no icon specified for service. */
|
||||
export const DEFAULT_SERVICE_ICON = mdiRoomService;
|
||||
|
||||
/** Icon to use when no icon specified for domain. */
|
||||
export const DEFAULT_DOMAIN_ICON = mdiBookmark;
|
||||
|
||||
@ -85,20 +93,23 @@ export const DEFAULT_DOMAIN_ICON = mdiBookmark;
|
||||
export const FIXED_DOMAIN_ICONS = {
|
||||
air_quality: mdiAirFilter,
|
||||
alert: mdiAlert,
|
||||
automation: mdiRobot,
|
||||
calendar: mdiCalendar,
|
||||
climate: mdiThermostat,
|
||||
configurator: mdiCog,
|
||||
conversation: mdiMicrophoneMessage,
|
||||
counter: mdiCounter,
|
||||
datetime: mdiCalendarClock,
|
||||
date: mdiCalendar,
|
||||
datetime: mdiCalendarClock,
|
||||
demo: mdiHomeAssistant,
|
||||
device_tracker: mdiAccount,
|
||||
google_assistant: mdiGoogleAssistant,
|
||||
group: mdiGoogleCirclesCommunities,
|
||||
homeassistant: mdiHomeAssistant,
|
||||
homekit: mdiHomeAutomation,
|
||||
image: mdiImage,
|
||||
image_processing: mdiImageFilterFrames,
|
||||
image: mdiImage,
|
||||
input_boolean: mdiToggleSwitch,
|
||||
input_button: mdiButtonPointer,
|
||||
input_datetime: mdiCalendarClock,
|
||||
input_number: mdiRayVertex,
|
||||
@ -110,6 +121,7 @@ export const FIXED_DOMAIN_ICONS = {
|
||||
notify: mdiCommentAlert,
|
||||
number: mdiRayVertex,
|
||||
persistent_notification: mdiBell,
|
||||
person: mdiAccount,
|
||||
plant: mdiFlower,
|
||||
proximity: mdiAppleSafari,
|
||||
remote: mdiRemote,
|
||||
@ -121,10 +133,11 @@ export const FIXED_DOMAIN_ICONS = {
|
||||
simple_alarm: mdiBell,
|
||||
siren: mdiBullhorn,
|
||||
stt: mdiMicrophoneMessage,
|
||||
sun: mdiWhiteBalanceSunny,
|
||||
text: mdiFormTextbox,
|
||||
todo: mdiClipboardList,
|
||||
time: mdiClock,
|
||||
timer: mdiTimerOutline,
|
||||
todo: mdiClipboardList,
|
||||
tts: mdiSpeakerMessage,
|
||||
vacuum: mdiRobotVacuum,
|
||||
wake_word: mdiChatSleep,
|
||||
|
@ -1,36 +0,0 @@
|
||||
/** Return an icon representing a alarm panel state. */
|
||||
|
||||
import {
|
||||
mdiShieldLock,
|
||||
mdiShieldAirplane,
|
||||
mdiShieldHome,
|
||||
mdiShieldMoon,
|
||||
mdiSecurity,
|
||||
mdiShieldOutline,
|
||||
mdiBellRing,
|
||||
mdiShieldOff,
|
||||
mdiShield,
|
||||
} from "@mdi/js";
|
||||
|
||||
export const alarmPanelIcon = (state?: string) => {
|
||||
switch (state) {
|
||||
case "armed_away":
|
||||
return mdiShieldLock;
|
||||
case "armed_vacation":
|
||||
return mdiShieldAirplane;
|
||||
case "armed_home":
|
||||
return mdiShieldHome;
|
||||
case "armed_night":
|
||||
return mdiShieldMoon;
|
||||
case "armed_custom_bypass":
|
||||
return mdiSecurity;
|
||||
case "pending":
|
||||
return mdiShieldOutline;
|
||||
case "triggered":
|
||||
return mdiBellRing;
|
||||
case "disarmed":
|
||||
return mdiShieldOff;
|
||||
default:
|
||||
return mdiShield;
|
||||
}
|
||||
};
|
@ -1,92 +1,59 @@
|
||||
/** Return an icon representing a battery state. */
|
||||
import {
|
||||
mdiBattery,
|
||||
mdiBattery10,
|
||||
mdiBattery20,
|
||||
mdiBattery30,
|
||||
mdiBattery40,
|
||||
mdiBattery50,
|
||||
mdiBattery60,
|
||||
mdiBattery70,
|
||||
mdiBattery80,
|
||||
mdiBattery90,
|
||||
mdiBatteryAlert,
|
||||
mdiBatteryAlertVariantOutline,
|
||||
mdiBatteryCharging,
|
||||
mdiBatteryCharging10,
|
||||
mdiBatteryCharging20,
|
||||
mdiBatteryCharging30,
|
||||
mdiBatteryCharging40,
|
||||
mdiBatteryCharging50,
|
||||
mdiBatteryCharging60,
|
||||
mdiBatteryCharging70,
|
||||
mdiBatteryCharging80,
|
||||
mdiBatteryCharging90,
|
||||
mdiBatteryChargingOutline,
|
||||
mdiBatteryUnknown,
|
||||
} from "@mdi/js";
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
|
||||
const BATTERY_ICONS = {
|
||||
10: mdiBattery10,
|
||||
20: mdiBattery20,
|
||||
30: mdiBattery30,
|
||||
40: mdiBattery40,
|
||||
50: mdiBattery50,
|
||||
60: mdiBattery60,
|
||||
70: mdiBattery70,
|
||||
80: mdiBattery80,
|
||||
90: mdiBattery90,
|
||||
100: mdiBattery,
|
||||
10: "mdi:battery-10",
|
||||
20: "mdi:battery-20",
|
||||
30: "mdi:battery-30",
|
||||
40: "mdi:battery-40",
|
||||
50: "mdi:battery-50",
|
||||
60: "mdi:battery-60",
|
||||
70: "mdi:battery-70",
|
||||
80: "mdi:battery-80",
|
||||
90: "mdi:battery-90",
|
||||
100: "mdi:battery",
|
||||
};
|
||||
const BATTERY_CHARGING_ICONS = {
|
||||
10: mdiBatteryCharging10,
|
||||
20: mdiBatteryCharging20,
|
||||
30: mdiBatteryCharging30,
|
||||
40: mdiBatteryCharging40,
|
||||
50: mdiBatteryCharging50,
|
||||
60: mdiBatteryCharging60,
|
||||
70: mdiBatteryCharging70,
|
||||
80: mdiBatteryCharging80,
|
||||
90: mdiBatteryCharging90,
|
||||
100: mdiBatteryCharging,
|
||||
10: "mdi:battery-charging-10",
|
||||
20: "mdi:battery-charging-20",
|
||||
30: "mdi:battery-charging-30",
|
||||
40: "mdi:battery-charging-40",
|
||||
50: "mdi:battery-charging-50",
|
||||
60: "mdi:battery-charging-60",
|
||||
70: "mdi:battery-charging-70",
|
||||
80: "mdi:battery-charging-80",
|
||||
90: "mdi:battery-charging-90",
|
||||
100: "mdi:battery-charging",
|
||||
};
|
||||
|
||||
export const batteryStateIcon = (
|
||||
batteryState: HassEntity,
|
||||
batteryChargingState?: HassEntity
|
||||
) => {
|
||||
const battery = batteryState.state;
|
||||
const batteryCharging =
|
||||
batteryChargingState && batteryChargingState.state === "on";
|
||||
|
||||
return batteryIcon(battery, batteryCharging);
|
||||
export const batteryIcon = (stateObj: HassEntity, state?: string) => {
|
||||
const level = state ?? stateObj.state;
|
||||
return batteryLevelIcon(level);
|
||||
};
|
||||
|
||||
export const batteryIcon = (
|
||||
batteryState: number | string,
|
||||
batteryCharging?: boolean
|
||||
) => {
|
||||
const batteryValue = Number(batteryState);
|
||||
export const batteryLevelIcon = (
|
||||
batteryLevel: number | string,
|
||||
isBatteryCharging?: boolean
|
||||
): string => {
|
||||
const batteryValue = Number(batteryLevel);
|
||||
if (isNaN(batteryValue)) {
|
||||
if (batteryState === "off") {
|
||||
return mdiBattery;
|
||||
if (batteryLevel === "off") {
|
||||
return "mdi:battery";
|
||||
}
|
||||
if (batteryState === "on") {
|
||||
return mdiBatteryAlert;
|
||||
if (batteryLevel === "on") {
|
||||
return "mdi:battery-alert";
|
||||
}
|
||||
return mdiBatteryUnknown;
|
||||
return "mdi:battery-unknown";
|
||||
}
|
||||
|
||||
const batteryRound = Math.round(batteryValue / 10) * 10;
|
||||
if (batteryCharging && batteryValue >= 10) {
|
||||
if (isBatteryCharging && batteryValue >= 10) {
|
||||
return BATTERY_CHARGING_ICONS[batteryRound];
|
||||
}
|
||||
if (batteryCharging) {
|
||||
return mdiBatteryChargingOutline;
|
||||
if (isBatteryCharging) {
|
||||
return "mdi:battery-charging-outline";
|
||||
}
|
||||
if (batteryValue <= 5) {
|
||||
return mdiBatteryAlertVariantOutline;
|
||||
return "mdi:battery-alert-variant-outline";
|
||||
}
|
||||
return BATTERY_ICONS[batteryRound];
|
||||
};
|
||||
|
@ -1,108 +0,0 @@
|
||||
import {
|
||||
mdiAlertCircle,
|
||||
mdiBattery,
|
||||
mdiBatteryCharging,
|
||||
mdiBatteryOutline,
|
||||
mdiBrightness5,
|
||||
mdiBrightness7,
|
||||
mdiCheckboxMarkedCircle,
|
||||
mdiCheckNetworkOutline,
|
||||
mdiCloseNetworkOutline,
|
||||
mdiCheckCircle,
|
||||
mdiCropPortrait,
|
||||
mdiDoorClosed,
|
||||
mdiDoorOpen,
|
||||
mdiFire,
|
||||
mdiGarage,
|
||||
mdiGarageOpen,
|
||||
mdiHome,
|
||||
mdiHomeOutline,
|
||||
mdiLock,
|
||||
mdiLockOpen,
|
||||
mdiMusicNote,
|
||||
mdiMusicNoteOff,
|
||||
mdiMotionSensor,
|
||||
mdiMotionSensorOff,
|
||||
mdiPackage,
|
||||
mdiPackageUp,
|
||||
mdiPlay,
|
||||
mdiPowerPlug,
|
||||
mdiPowerPlugOff,
|
||||
mdiRadioboxBlank,
|
||||
mdiSnowflake,
|
||||
mdiSmokeDetector,
|
||||
mdiSmokeDetectorAlert,
|
||||
mdiSmokeDetectorVariant,
|
||||
mdiSmokeDetectorVariantAlert,
|
||||
mdiSquare,
|
||||
mdiSquareOutline,
|
||||
mdiStop,
|
||||
mdiThermometer,
|
||||
mdiVibrate,
|
||||
mdiWater,
|
||||
mdiWaterOff,
|
||||
mdiWindowClosed,
|
||||
mdiWindowOpen,
|
||||
} from "@mdi/js";
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
|
||||
/** Return an icon representing a binary sensor state. */
|
||||
|
||||
export const binarySensorIcon = (state?: string, stateObj?: HassEntity) => {
|
||||
const is_off = state === "off";
|
||||
switch (stateObj?.attributes.device_class) {
|
||||
case "battery":
|
||||
return is_off ? mdiBattery : mdiBatteryOutline;
|
||||
case "battery_charging":
|
||||
return is_off ? mdiBattery : mdiBatteryCharging;
|
||||
case "carbon_monoxide":
|
||||
return is_off ? mdiSmokeDetector : mdiSmokeDetectorAlert;
|
||||
case "cold":
|
||||
return is_off ? mdiThermometer : mdiSnowflake;
|
||||
case "connectivity":
|
||||
return is_off ? mdiCloseNetworkOutline : mdiCheckNetworkOutline;
|
||||
case "door":
|
||||
return is_off ? mdiDoorClosed : mdiDoorOpen;
|
||||
case "garage_door":
|
||||
return is_off ? mdiGarage : mdiGarageOpen;
|
||||
case "power":
|
||||
return is_off ? mdiPowerPlugOff : mdiPowerPlug;
|
||||
case "gas":
|
||||
case "problem":
|
||||
case "safety":
|
||||
case "tamper":
|
||||
return is_off ? mdiCheckCircle : mdiAlertCircle;
|
||||
case "smoke":
|
||||
return is_off ? mdiSmokeDetectorVariant : mdiSmokeDetectorVariantAlert;
|
||||
case "heat":
|
||||
return is_off ? mdiThermometer : mdiFire;
|
||||
case "light":
|
||||
return is_off ? mdiBrightness5 : mdiBrightness7;
|
||||
case "lock":
|
||||
return is_off ? mdiLock : mdiLockOpen;
|
||||
case "moisture":
|
||||
return is_off ? mdiWaterOff : mdiWater;
|
||||
case "motion":
|
||||
return is_off ? mdiMotionSensorOff : mdiMotionSensor;
|
||||
case "occupancy":
|
||||
return is_off ? mdiHomeOutline : mdiHome;
|
||||
case "opening":
|
||||
return is_off ? mdiSquare : mdiSquareOutline;
|
||||
case "plug":
|
||||
return is_off ? mdiPowerPlugOff : mdiPowerPlug;
|
||||
case "presence":
|
||||
return is_off ? mdiHomeOutline : mdiHome;
|
||||
case "running":
|
||||
return is_off ? mdiStop : mdiPlay;
|
||||
case "sound":
|
||||
return is_off ? mdiMusicNoteOff : mdiMusicNote;
|
||||
case "update":
|
||||
return is_off ? mdiPackage : mdiPackageUp;
|
||||
case "vibration":
|
||||
return is_off ? mdiCropPortrait : mdiVibrate;
|
||||
case "window":
|
||||
return is_off ? mdiWindowClosed : mdiWindowOpen;
|
||||
default:
|
||||
return is_off ? mdiRadioboxBlank : mdiCheckboxMarkedCircle;
|
||||
}
|
||||
};
|
@ -1,132 +1,12 @@
|
||||
/** Return an icon representing a cover state. */
|
||||
import {
|
||||
mdiArrowUpBox,
|
||||
mdiArrowDownBox,
|
||||
mdiGarage,
|
||||
mdiGarageOpen,
|
||||
mdiGateArrowRight,
|
||||
mdiGate,
|
||||
mdiGateOpen,
|
||||
mdiDoorOpen,
|
||||
mdiDoorClosed,
|
||||
mdiCircle,
|
||||
mdiWindowShutter,
|
||||
mdiWindowShutterOpen,
|
||||
mdiBlindsHorizontal,
|
||||
mdiBlindsHorizontalClosed,
|
||||
mdiRollerShade,
|
||||
mdiRollerShadeClosed,
|
||||
mdiWindowClosed,
|
||||
mdiWindowOpen,
|
||||
mdiArrowExpandHorizontal,
|
||||
mdiArrowUp,
|
||||
mdiArrowCollapseHorizontal,
|
||||
mdiArrowDown,
|
||||
mdiCircleSlice8,
|
||||
mdiArrowSplitVertical,
|
||||
mdiCurtains,
|
||||
mdiCurtainsClosed,
|
||||
mdiArrowExpandHorizontal,
|
||||
mdiArrowUp,
|
||||
} from "@mdi/js";
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
|
||||
export const coverIcon = (state?: string, stateObj?: HassEntity): string => {
|
||||
const open = state !== "closed";
|
||||
|
||||
switch (stateObj?.attributes.device_class) {
|
||||
case "garage":
|
||||
switch (state) {
|
||||
case "opening":
|
||||
return mdiArrowUpBox;
|
||||
case "closing":
|
||||
return mdiArrowDownBox;
|
||||
case "closed":
|
||||
return mdiGarage;
|
||||
default:
|
||||
return mdiGarageOpen;
|
||||
}
|
||||
case "gate":
|
||||
switch (state) {
|
||||
case "opening":
|
||||
case "closing":
|
||||
return mdiGateArrowRight;
|
||||
case "closed":
|
||||
return mdiGate;
|
||||
default:
|
||||
return mdiGateOpen;
|
||||
}
|
||||
case "door":
|
||||
return open ? mdiDoorOpen : mdiDoorClosed;
|
||||
case "damper":
|
||||
return open ? mdiCircle : mdiCircleSlice8;
|
||||
case "shutter":
|
||||
switch (state) {
|
||||
case "opening":
|
||||
return mdiArrowUpBox;
|
||||
case "closing":
|
||||
return mdiArrowDownBox;
|
||||
case "closed":
|
||||
return mdiWindowShutter;
|
||||
default:
|
||||
return mdiWindowShutterOpen;
|
||||
}
|
||||
case "curtain":
|
||||
switch (state) {
|
||||
case "opening":
|
||||
return mdiArrowSplitVertical;
|
||||
case "closing":
|
||||
return mdiArrowCollapseHorizontal;
|
||||
case "closed":
|
||||
return mdiCurtainsClosed;
|
||||
default:
|
||||
return mdiCurtains;
|
||||
}
|
||||
case "blind":
|
||||
switch (state) {
|
||||
case "opening":
|
||||
return mdiArrowUpBox;
|
||||
case "closing":
|
||||
return mdiArrowDownBox;
|
||||
case "closed":
|
||||
return mdiBlindsHorizontalClosed;
|
||||
default:
|
||||
return mdiBlindsHorizontal;
|
||||
}
|
||||
case "shade":
|
||||
switch (state) {
|
||||
case "opening":
|
||||
return mdiArrowUpBox;
|
||||
case "closing":
|
||||
return mdiArrowDownBox;
|
||||
case "closed":
|
||||
return mdiRollerShadeClosed;
|
||||
default:
|
||||
return mdiRollerShade;
|
||||
}
|
||||
case "window":
|
||||
switch (state) {
|
||||
case "opening":
|
||||
return mdiArrowUpBox;
|
||||
case "closing":
|
||||
return mdiArrowDownBox;
|
||||
case "closed":
|
||||
return mdiWindowClosed;
|
||||
default:
|
||||
return mdiWindowOpen;
|
||||
}
|
||||
}
|
||||
|
||||
switch (state) {
|
||||
case "opening":
|
||||
return mdiArrowUpBox;
|
||||
case "closing":
|
||||
return mdiArrowDownBox;
|
||||
case "closed":
|
||||
return mdiWindowClosed;
|
||||
default:
|
||||
return mdiWindowOpen;
|
||||
}
|
||||
};
|
||||
|
||||
export const computeOpenIcon = (stateObj: HassEntity): string => {
|
||||
switch (stateObj.attributes.device_class) {
|
||||
case "awning":
|
||||
|
16
src/common/entity/device_tracker_icon.ts
Normal file
16
src/common/entity/device_tracker_icon.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
|
||||
export const deviceTrackerIcon = (stateObj: HassEntity, state?: string) => {
|
||||
const compareState = state ?? stateObj.state;
|
||||
if (stateObj?.attributes.source_type === "router") {
|
||||
return compareState === "home" ? "mdi:lan-connect" : "mdi:lan-disconnect";
|
||||
}
|
||||
if (
|
||||
["bluetooth", "bluetooth_le"].includes(stateObj?.attributes.source_type)
|
||||
) {
|
||||
return compareState === "home" ? "mdi:bluetooth-connect" : "mdi:bluetooth";
|
||||
}
|
||||
return compareState === "not_home"
|
||||
? "mdi:account-arrow-right"
|
||||
: "mdi:account";
|
||||
};
|
@ -1,301 +0,0 @@
|
||||
import {
|
||||
mdiAccount,
|
||||
mdiAccountArrowRight,
|
||||
mdiAirHumidifier,
|
||||
mdiAirHumidifierOff,
|
||||
mdiAudioVideo,
|
||||
mdiAudioVideoOff,
|
||||
mdiBluetooth,
|
||||
mdiBluetoothConnect,
|
||||
mdiButtonPointer,
|
||||
mdiCalendar,
|
||||
mdiCast,
|
||||
mdiCastConnected,
|
||||
mdiCastOff,
|
||||
mdiChartSankey,
|
||||
mdiCheckCircleOutline,
|
||||
mdiClock,
|
||||
mdiCloseCircleOutline,
|
||||
mdiCrosshairsQuestion,
|
||||
mdiDoorbell,
|
||||
mdiEyeCheck,
|
||||
mdiFan,
|
||||
mdiFanOff,
|
||||
mdiGestureTapButton,
|
||||
mdiLanConnect,
|
||||
mdiLanDisconnect,
|
||||
mdiLock,
|
||||
mdiLockAlert,
|
||||
mdiLockClock,
|
||||
mdiLockOpen,
|
||||
mdiMeterGas,
|
||||
mdiMotionSensor,
|
||||
mdiPackage,
|
||||
mdiPackageDown,
|
||||
mdiPackageUp,
|
||||
mdiPipeValve,
|
||||
mdiPowerPlug,
|
||||
mdiPowerPlugOff,
|
||||
mdiRestart,
|
||||
mdiRobot,
|
||||
mdiRobotConfused,
|
||||
mdiRobotOff,
|
||||
mdiSpeaker,
|
||||
mdiSpeakerOff,
|
||||
mdiSpeakerPause,
|
||||
mdiSpeakerPlay,
|
||||
mdiSwapHorizontal,
|
||||
mdiTelevision,
|
||||
mdiTelevisionOff,
|
||||
mdiTelevisionPause,
|
||||
mdiTelevisionPlay,
|
||||
mdiToggleSwitchVariant,
|
||||
mdiToggleSwitchVariantOff,
|
||||
mdiVideo,
|
||||
mdiVideoOff,
|
||||
mdiWaterBoiler,
|
||||
mdiWaterBoilerOff,
|
||||
mdiWeatherNight,
|
||||
mdiWhiteBalanceSunny,
|
||||
} from "@mdi/js";
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { UpdateEntity, updateIsInstalling } from "../../data/update";
|
||||
import { weatherIcon } from "../../data/weather";
|
||||
/**
|
||||
* Return the icon to be used for a domain.
|
||||
*
|
||||
* Optionally pass in a state to influence the domain icon.
|
||||
*/
|
||||
import { DEFAULT_DOMAIN_ICON, FIXED_DOMAIN_ICONS } from "../const";
|
||||
import { alarmPanelIcon } from "./alarm_panel_icon";
|
||||
import { binarySensorIcon } from "./binary_sensor_icon";
|
||||
import { coverIcon } from "./cover_icon";
|
||||
import { numberIcon } from "./number_icon";
|
||||
import { sensorIcon } from "./sensor_icon";
|
||||
|
||||
export const domainIcon = (
|
||||
domain: string,
|
||||
stateObj?: HassEntity,
|
||||
state?: string
|
||||
): string => {
|
||||
const icon = domainIconWithoutDefault(domain, stateObj, state);
|
||||
if (icon) {
|
||||
return icon;
|
||||
}
|
||||
// eslint-disable-next-line
|
||||
console.warn(`Unable to find icon for domain ${domain}`);
|
||||
return DEFAULT_DOMAIN_ICON;
|
||||
};
|
||||
|
||||
export const domainIconWithoutDefault = (
|
||||
domain: string,
|
||||
stateObj?: HassEntity,
|
||||
state?: string
|
||||
): string | undefined => {
|
||||
const compareState = state !== undefined ? state : stateObj?.state;
|
||||
|
||||
switch (domain) {
|
||||
case "alarm_control_panel":
|
||||
return alarmPanelIcon(compareState);
|
||||
|
||||
case "automation":
|
||||
return compareState === "unavailable"
|
||||
? mdiRobotConfused
|
||||
: compareState === "off"
|
||||
? mdiRobotOff
|
||||
: mdiRobot;
|
||||
|
||||
case "binary_sensor":
|
||||
return binarySensorIcon(compareState, stateObj);
|
||||
|
||||
case "button":
|
||||
switch (stateObj?.attributes.device_class) {
|
||||
case "identify":
|
||||
return mdiCrosshairsQuestion;
|
||||
case "restart":
|
||||
return mdiRestart;
|
||||
case "update":
|
||||
return mdiPackageUp;
|
||||
default:
|
||||
return mdiButtonPointer;
|
||||
}
|
||||
|
||||
case "camera":
|
||||
return compareState === "off" ? mdiVideoOff : mdiVideo;
|
||||
|
||||
case "cover":
|
||||
return coverIcon(compareState, stateObj);
|
||||
|
||||
case "device_tracker":
|
||||
if (stateObj?.attributes.source_type === "router") {
|
||||
return compareState === "home" ? mdiLanConnect : mdiLanDisconnect;
|
||||
}
|
||||
if (
|
||||
["bluetooth", "bluetooth_le"].includes(stateObj?.attributes.source_type)
|
||||
) {
|
||||
return compareState === "home" ? mdiBluetoothConnect : mdiBluetooth;
|
||||
}
|
||||
return compareState === "not_home" ? mdiAccountArrowRight : mdiAccount;
|
||||
|
||||
case "event":
|
||||
switch (stateObj?.attributes.device_class) {
|
||||
case "doorbell":
|
||||
return mdiDoorbell;
|
||||
case "button":
|
||||
return mdiGestureTapButton;
|
||||
case "motion":
|
||||
return mdiMotionSensor;
|
||||
default:
|
||||
return mdiEyeCheck;
|
||||
}
|
||||
|
||||
case "fan":
|
||||
return compareState === "off" ? mdiFanOff : mdiFan;
|
||||
|
||||
case "humidifier":
|
||||
return compareState === "off" ? mdiAirHumidifierOff : mdiAirHumidifier;
|
||||
|
||||
case "input_boolean":
|
||||
return compareState === "on"
|
||||
? mdiCheckCircleOutline
|
||||
: mdiCloseCircleOutline;
|
||||
|
||||
case "input_datetime":
|
||||
if (!stateObj?.attributes.has_date) {
|
||||
return mdiClock;
|
||||
}
|
||||
if (!stateObj.attributes.has_time) {
|
||||
return mdiCalendar;
|
||||
}
|
||||
break;
|
||||
|
||||
case "lock":
|
||||
switch (compareState) {
|
||||
case "unlocked":
|
||||
return mdiLockOpen;
|
||||
case "jammed":
|
||||
return mdiLockAlert;
|
||||
case "locking":
|
||||
case "unlocking":
|
||||
return mdiLockClock;
|
||||
default:
|
||||
return mdiLock;
|
||||
}
|
||||
|
||||
case "media_player":
|
||||
switch (stateObj?.attributes.device_class) {
|
||||
case "speaker":
|
||||
switch (compareState) {
|
||||
case "playing":
|
||||
return mdiSpeakerPlay;
|
||||
case "paused":
|
||||
return mdiSpeakerPause;
|
||||
case "off":
|
||||
return mdiSpeakerOff;
|
||||
default:
|
||||
return mdiSpeaker;
|
||||
}
|
||||
case "tv":
|
||||
switch (compareState) {
|
||||
case "playing":
|
||||
return mdiTelevisionPlay;
|
||||
case "paused":
|
||||
return mdiTelevisionPause;
|
||||
case "off":
|
||||
return mdiTelevisionOff;
|
||||
default:
|
||||
return mdiTelevision;
|
||||
}
|
||||
case "receiver":
|
||||
switch (compareState) {
|
||||
case "off":
|
||||
return mdiAudioVideoOff;
|
||||
default:
|
||||
return mdiAudioVideo;
|
||||
}
|
||||
default:
|
||||
switch (compareState) {
|
||||
case "playing":
|
||||
case "paused":
|
||||
return mdiCastConnected;
|
||||
case "off":
|
||||
return mdiCastOff;
|
||||
default:
|
||||
return mdiCast;
|
||||
}
|
||||
}
|
||||
|
||||
case "number": {
|
||||
const icon = numberIcon(stateObj);
|
||||
if (icon) {
|
||||
return icon;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case "person":
|
||||
return compareState === "not_home" ? mdiAccountArrowRight : mdiAccount;
|
||||
|
||||
case "switch":
|
||||
switch (stateObj?.attributes.device_class) {
|
||||
case "outlet":
|
||||
return compareState === "on" ? mdiPowerPlug : mdiPowerPlugOff;
|
||||
case "switch":
|
||||
return compareState === "on"
|
||||
? mdiToggleSwitchVariant
|
||||
: mdiToggleSwitchVariantOff;
|
||||
default:
|
||||
return mdiToggleSwitchVariant;
|
||||
}
|
||||
|
||||
case "sensor": {
|
||||
const icon = sensorIcon(stateObj);
|
||||
if (icon) {
|
||||
return icon;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case "sun":
|
||||
return stateObj?.state === "above_horizon"
|
||||
? mdiWhiteBalanceSunny
|
||||
: mdiWeatherNight;
|
||||
|
||||
case "switch_as_x":
|
||||
return mdiSwapHorizontal;
|
||||
|
||||
case "threshold":
|
||||
return mdiChartSankey;
|
||||
|
||||
case "update":
|
||||
return compareState === "on"
|
||||
? updateIsInstalling(stateObj as UpdateEntity)
|
||||
? mdiPackageDown
|
||||
: mdiPackageUp
|
||||
: mdiPackage;
|
||||
|
||||
case "valve":
|
||||
switch (stateObj?.attributes.device_class) {
|
||||
case "water":
|
||||
return mdiPipeValve;
|
||||
case "gas":
|
||||
return mdiMeterGas;
|
||||
default:
|
||||
return mdiPipeValve;
|
||||
}
|
||||
|
||||
case "water_heater":
|
||||
return compareState === "off" ? mdiWaterBoilerOff : mdiWaterBoiler;
|
||||
|
||||
case "weather":
|
||||
return weatherIcon(stateObj?.state);
|
||||
}
|
||||
|
||||
if (domain in FIXED_DOMAIN_ICONS) {
|
||||
return FIXED_DOMAIN_ICONS[domain];
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
@ -1,13 +0,0 @@
|
||||
/** Return an icon representing a number state. */
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { FIXED_DEVICE_CLASS_ICONS } from "../const";
|
||||
|
||||
export const numberIcon = (stateObj?: HassEntity): string | undefined => {
|
||||
const dclass = stateObj?.attributes.device_class;
|
||||
|
||||
if (dclass && dclass in FIXED_DEVICE_CLASS_ICONS) {
|
||||
return FIXED_DEVICE_CLASS_ICONS[dclass];
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
@ -1,25 +0,0 @@
|
||||
/** Return an icon representing a sensor state. */
|
||||
import { mdiBattery, mdiThermometer } from "@mdi/js";
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { SENSOR_DEVICE_CLASS_BATTERY } from "../../data/sensor";
|
||||
import { FIXED_DEVICE_CLASS_ICONS, UNIT_C, UNIT_F } from "../const";
|
||||
import { batteryStateIcon } from "./battery_icon";
|
||||
|
||||
export const sensorIcon = (stateObj?: HassEntity): string | undefined => {
|
||||
const dclass = stateObj?.attributes.device_class;
|
||||
|
||||
if (dclass && dclass in FIXED_DEVICE_CLASS_ICONS) {
|
||||
return FIXED_DEVICE_CLASS_ICONS[dclass];
|
||||
}
|
||||
|
||||
if (dclass === SENSOR_DEVICE_CLASS_BATTERY) {
|
||||
return stateObj ? batteryStateIcon(stateObj) : mdiBattery;
|
||||
}
|
||||
|
||||
const unit = stateObj?.attributes.unit_of_measurement;
|
||||
if (unit === UNIT_C || unit === UNIT_F) {
|
||||
return mdiThermometer;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
42
src/common/entity/state_icon.ts
Normal file
42
src/common/entity/state_icon.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { computeStateDomain } from "./compute_state_domain";
|
||||
import { updateIcon } from "./update_icon";
|
||||
import { deviceTrackerIcon } from "./device_tracker_icon";
|
||||
import { batteryIcon } from "./battery_icon";
|
||||
|
||||
export const stateIcon = (
|
||||
stateObj: HassEntity,
|
||||
state?: string
|
||||
): string | undefined => {
|
||||
const domain = computeStateDomain(stateObj);
|
||||
const compareState = state ?? stateObj.state;
|
||||
const dc = stateObj.attributes.device_class;
|
||||
switch (domain) {
|
||||
case "update":
|
||||
return updateIcon(stateObj, compareState);
|
||||
|
||||
case "sensor":
|
||||
if (dc === "battery") {
|
||||
return batteryIcon(stateObj, compareState);
|
||||
}
|
||||
break;
|
||||
|
||||
case "device_tracker":
|
||||
return deviceTrackerIcon(stateObj, compareState);
|
||||
|
||||
case "sun":
|
||||
return compareState === "above_horizon"
|
||||
? "mdi:white-balance-sunny"
|
||||
: "mdi:weather-night";
|
||||
|
||||
case "input_datetime":
|
||||
if (!stateObj.attributes.has_date) {
|
||||
return "mdi:clock";
|
||||
}
|
||||
if (!stateObj.attributes.has_time) {
|
||||
return "mdi:calendar";
|
||||
}
|
||||
break;
|
||||
}
|
||||
return undefined;
|
||||
};
|
@ -1,12 +0,0 @@
|
||||
/** Return an icon representing a state. */
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { DEFAULT_DOMAIN_ICON } from "../const";
|
||||
import { computeDomain } from "./compute_domain";
|
||||
import { domainIcon } from "./domain_icon";
|
||||
|
||||
export const stateIconPath = (state: HassEntity | undefined) => {
|
||||
if (!state) {
|
||||
return DEFAULT_DOMAIN_ICON;
|
||||
}
|
||||
return domainIcon(computeDomain(state.entity_id), state);
|
||||
};
|
11
src/common/entity/update_icon.ts
Normal file
11
src/common/entity/update_icon.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { UpdateEntity, updateIsInstalling } from "../../data/update";
|
||||
|
||||
export const updateIcon = (stateObj: HassEntity, state?: string) => {
|
||||
const compareState = state ?? stateObj.state;
|
||||
return compareState === "on"
|
||||
? updateIsInstalling(stateObj as UpdateEntity)
|
||||
? "mdi:package-down"
|
||||
: "mdi:package-up"
|
||||
: "mdi:package";
|
||||
};
|
@ -764,10 +764,12 @@ export class HaDataTable extends LitElement {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.mdc-data-table__cell--icon:first-child ha-icon,
|
||||
.mdc-data-table__cell--icon:first-child img,
|
||||
.mdc-data-table__cell--icon:first-child ha-icon,
|
||||
.mdc-data-table__cell--icon:first-child ha-svg-icon,
|
||||
.mdc-data-table__cell--icon:first-child ha-state-icon,
|
||||
.mdc-data-table__cell--icon:first-child ha-svg-icon {
|
||||
.mdc-data-table__cell--icon:first-child ha-domain-icon,
|
||||
.mdc-data-table__cell--icon:first-child ha-service-icon {
|
||||
margin-left: 8px;
|
||||
}
|
||||
:host([dir="rtl"]) .mdc-data-table__cell--icon:first-child ha-icon,
|
||||
|
@ -1,22 +1,25 @@
|
||||
import { html, LitElement } from "lit";
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { html, LitElement, nothing } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { batteryStateIcon } from "../../common/entity/battery_icon";
|
||||
import "../ha-svg-icon";
|
||||
import { batteryLevelIcon } from "../../common/entity/battery_icon";
|
||||
import "../ha-icon";
|
||||
|
||||
@customElement("ha-battery-icon")
|
||||
export class HaBatteryIcon extends LitElement {
|
||||
@property() public batteryStateObj;
|
||||
@property({ attribute: false }) public batteryStateObj?: HassEntity;
|
||||
|
||||
@property() public batteryChargingStateObj;
|
||||
@property({ attribute: false }) public batteryChargingStateObj?: HassEntity;
|
||||
|
||||
protected render() {
|
||||
if (!this.batteryStateObj) return nothing;
|
||||
|
||||
return html`
|
||||
<ha-svg-icon
|
||||
.path=${batteryStateIcon(
|
||||
this.batteryStateObj,
|
||||
this.batteryChargingStateObj
|
||||
<ha-icon
|
||||
.icon=${batteryLevelIcon(
|
||||
this.batteryStateObj.state,
|
||||
this.batteryChargingStateObj?.state === "on"
|
||||
)}
|
||||
></ha-svg-icon>
|
||||
></ha-icon>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
84
src/components/ha-domain-icon.ts
Normal file
84
src/components/ha-domain-icon.ts
Normal file
@ -0,0 +1,84 @@
|
||||
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { until } from "lit/directives/until";
|
||||
import { DEFAULT_DOMAIN_ICON, FIXED_DOMAIN_ICONS } from "../common/const";
|
||||
import { domainIcon } from "../data/icons";
|
||||
import { HomeAssistant } from "../types";
|
||||
import { brandsUrl } from "../util/brands-url";
|
||||
import "./ha-icon";
|
||||
|
||||
@customElement("ha-domain-icon")
|
||||
export class HaDomainIcon extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property() public domain?: string;
|
||||
|
||||
@property() public deviceClass?: string;
|
||||
|
||||
@property() public icon?: string;
|
||||
|
||||
@property({ type: Boolean }) public brandFallback?: boolean;
|
||||
|
||||
protected render() {
|
||||
if (this.icon) {
|
||||
return html`<ha-icon .icon=${this.icon}></ha-icon>`;
|
||||
}
|
||||
|
||||
if (!this.domain) {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
if (!this.hass) {
|
||||
return this._renderFallback();
|
||||
}
|
||||
|
||||
const icon = domainIcon(this.hass, this.domain, this.deviceClass).then(
|
||||
(icn) => {
|
||||
if (icn) {
|
||||
return html`<ha-icon .icon=${icn}></ha-icon>`;
|
||||
}
|
||||
return this._renderFallback();
|
||||
}
|
||||
);
|
||||
|
||||
return html`${until(icon)}`;
|
||||
}
|
||||
|
||||
private _renderFallback() {
|
||||
if (this.domain! in FIXED_DOMAIN_ICONS) {
|
||||
return html`
|
||||
<ha-svg-icon .path=${FIXED_DOMAIN_ICONS[this.domain!]}></ha-svg-icon>
|
||||
`;
|
||||
}
|
||||
if (this.brandFallback) {
|
||||
const image = brandsUrl({
|
||||
domain: this.domain!,
|
||||
type: "icon",
|
||||
darkOptimized: this.hass.themes?.darkMode,
|
||||
});
|
||||
return html`
|
||||
<img
|
||||
alt=""
|
||||
src=${image}
|
||||
crossorigin="anonymous"
|
||||
referrerpolicy="no-referrer"
|
||||
/>
|
||||
`;
|
||||
}
|
||||
return html`<ha-svg-icon .path=${DEFAULT_DOMAIN_ICON}></ha-svg-icon>`;
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return css`
|
||||
img {
|
||||
width: var(--mdc-icon-size, 24px);
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-domain-icon": HaDomainIcon;
|
||||
}
|
||||
}
|
@ -1,9 +1,8 @@
|
||||
import { mdiRoomService } from "@mdi/js";
|
||||
import { html, LitElement, nothing } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { until } from "lit/directives/until";
|
||||
import { DEFAULT_SERVICE_ICON, FIXED_DOMAIN_ICONS } from "../common/const";
|
||||
import { computeDomain } from "../common/entity/compute_domain";
|
||||
import { domainIconWithoutDefault } from "../common/entity/domain_icon";
|
||||
import { serviceIcon } from "../data/icons";
|
||||
import { HomeAssistant } from "../types";
|
||||
import "./ha-icon";
|
||||
@ -41,10 +40,11 @@ export class HaServiceIcon extends LitElement {
|
||||
}
|
||||
|
||||
private _renderFallback() {
|
||||
const domain = computeDomain(this.service!);
|
||||
|
||||
return html`
|
||||
<ha-svg-icon
|
||||
.path=${domainIconWithoutDefault(computeDomain(this.service!)) ||
|
||||
mdiRoomService}
|
||||
.path=${FIXED_DOMAIN_ICONS[domain] || DEFAULT_SERVICE_ICON}
|
||||
></ha-svg-icon>
|
||||
`;
|
||||
}
|
||||
|
@ -2,7 +2,8 @@ import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { html, LitElement, nothing } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { until } from "lit/directives/until";
|
||||
import { stateIconPath } from "../common/entity/state_icon_path";
|
||||
import { DEFAULT_DOMAIN_ICON, FIXED_DOMAIN_ICONS } from "../common/const";
|
||||
import { computeStateDomain } from "../common/entity/compute_state_domain";
|
||||
import { entityIcon } from "../data/icons";
|
||||
import { HomeAssistant } from "../types";
|
||||
import "./ha-icon";
|
||||
@ -44,9 +45,13 @@ export class HaStateIcon extends LitElement {
|
||||
}
|
||||
|
||||
private _renderFallback() {
|
||||
return html`<ha-svg-icon
|
||||
.path=${stateIconPath(this.stateObj)}
|
||||
></ha-svg-icon>`;
|
||||
const domain = computeStateDomain(this.stateObj!);
|
||||
|
||||
return html`
|
||||
<ha-svg-icon
|
||||
.path=${FIXED_DOMAIN_ICONS[domain] || DEFAULT_DOMAIN_ICON}
|
||||
></ha-svg-icon>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,10 +17,11 @@ import {
|
||||
mdiRoomService,
|
||||
mdiShuffleDisabled,
|
||||
} from "@mdi/js";
|
||||
import { css, html, LitElement, PropertyValues } from "lit";
|
||||
import { LitElement, PropertyValues, css, html } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import { ensureArray } from "../../common/array/ensure-array";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import { ACTION_ICONS } from "../../data/action";
|
||||
import { Condition, Trigger } from "../../data/automation";
|
||||
import {
|
||||
Action,
|
||||
@ -45,7 +46,6 @@ import "./hat-graph-branch";
|
||||
import { BRANCH_HEIGHT, NODE_SIZE, SPACING } from "./hat-graph-const";
|
||||
import "./hat-graph-node";
|
||||
import "./hat-graph-spacer";
|
||||
import { ACTION_ICONS } from "../../data/action";
|
||||
|
||||
export interface NodeInfo {
|
||||
path: string;
|
||||
|
@ -2,6 +2,7 @@ import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { computeDomain } from "../common/entity/compute_domain";
|
||||
import { computeObjectId } from "../common/entity/compute_object_id";
|
||||
import { computeStateDomain } from "../common/entity/compute_state_domain";
|
||||
import { stateIcon } from "../common/entity/state_icon";
|
||||
import { HomeAssistant } from "../types";
|
||||
import {
|
||||
EntityRegistryDisplayEntry,
|
||||
@ -49,7 +50,7 @@ interface ComponentIcons {
|
||||
}
|
||||
|
||||
interface ServiceIcons {
|
||||
[domain: string]: Record<string, string>;
|
||||
[service: string]: string;
|
||||
}
|
||||
|
||||
export type IconCategory = "entity" | "entity_component" | "services";
|
||||
@ -127,26 +128,18 @@ export const getServiceIcons = async (
|
||||
|
||||
export const entityIcon = async (
|
||||
hass: HomeAssistant,
|
||||
state: HassEntity,
|
||||
stateValue?: string
|
||||
stateObj: HassEntity,
|
||||
state?: string
|
||||
) => {
|
||||
const entity = hass.entities?.[state.entity_id] as
|
||||
const entry = hass.entities?.[stateObj.entity_id] as
|
||||
| EntityRegistryDisplayEntry
|
||||
| undefined;
|
||||
if (entity?.icon) {
|
||||
return entity.icon;
|
||||
if (entry?.icon) {
|
||||
return entry.icon;
|
||||
}
|
||||
const domain = computeStateDomain(state);
|
||||
const deviceClass = state.attributes.device_class;
|
||||
const domain = computeStateDomain(stateObj);
|
||||
|
||||
return getEntityIcon(
|
||||
hass,
|
||||
domain,
|
||||
deviceClass,
|
||||
stateValue ?? state.state,
|
||||
entity?.platform,
|
||||
entity?.translation_key
|
||||
);
|
||||
return getEntityIcon(hass, domain, stateObj, state, entry);
|
||||
};
|
||||
|
||||
export const entryIcon = async (
|
||||
@ -157,39 +150,41 @@ export const entryIcon = async (
|
||||
return entry.icon;
|
||||
}
|
||||
const domain = computeDomain(entry.entity_id);
|
||||
return getEntityIcon(
|
||||
hass,
|
||||
domain,
|
||||
undefined,
|
||||
undefined,
|
||||
entry.platform,
|
||||
entry.translation_key
|
||||
);
|
||||
return getEntityIcon(hass, domain, undefined, undefined, entry);
|
||||
};
|
||||
|
||||
const getEntityIcon = async (
|
||||
hass: HomeAssistant,
|
||||
domain: string,
|
||||
deviceClass?: string,
|
||||
value?: string,
|
||||
platform?: string,
|
||||
translation_key?: string
|
||||
stateObj?: HassEntity,
|
||||
stateValue?: string,
|
||||
entry?: EntityRegistryEntry | EntityRegistryDisplayEntry
|
||||
) => {
|
||||
const platform = entry?.platform;
|
||||
const translation_key = entry?.translation_key;
|
||||
const device_class = stateObj?.attributes.device_class;
|
||||
const state = stateValue ?? stateObj?.state;
|
||||
|
||||
let icon: string | undefined;
|
||||
if (translation_key && platform) {
|
||||
const platformIcons = await getPlatformIcons(hass, platform);
|
||||
if (platformIcons) {
|
||||
const translations = platformIcons[domain]?.[translation_key];
|
||||
icon = (value && translations?.state?.[value]) || translations?.default;
|
||||
icon = (state && translations?.state?.[state]) || translations?.default;
|
||||
}
|
||||
}
|
||||
|
||||
if (!icon && stateObj) {
|
||||
icon = stateIcon(stateObj, state);
|
||||
}
|
||||
|
||||
if (!icon) {
|
||||
const entityComponentIcons = await getComponentIcons(hass, domain);
|
||||
if (entityComponentIcons) {
|
||||
const translations =
|
||||
(deviceClass && entityComponentIcons[deviceClass]) ||
|
||||
(device_class && entityComponentIcons[device_class]) ||
|
||||
entityComponentIcons._;
|
||||
icon = (value && translations?.state?.[value]) || translations?.default;
|
||||
icon = (state && translations?.state?.[state]) || translations?.default;
|
||||
}
|
||||
}
|
||||
return icon;
|
||||
@ -234,12 +229,34 @@ export const attributeIcon = async (
|
||||
return icon;
|
||||
};
|
||||
|
||||
export const serviceIcon = async (hass: HomeAssistant, service: string) => {
|
||||
export const serviceIcon = async (
|
||||
hass: HomeAssistant,
|
||||
service: string
|
||||
): Promise<string | undefined> => {
|
||||
let icon: string | undefined;
|
||||
const domain = computeDomain(service);
|
||||
const serviceName = computeObjectId(service);
|
||||
const serviceIcons = await getServiceIcons(hass, domain);
|
||||
if (serviceIcons) {
|
||||
return serviceIcons[serviceName];
|
||||
icon = serviceIcons[serviceName];
|
||||
}
|
||||
if (!icon) {
|
||||
icon = await domainIcon(hass, domain);
|
||||
}
|
||||
return icon;
|
||||
};
|
||||
|
||||
export const domainIcon = async (
|
||||
hass: HomeAssistant,
|
||||
domain: string,
|
||||
deviceClass?: string
|
||||
): Promise<string | undefined> => {
|
||||
const entityComponentIcons = await getComponentIcons(hass, domain);
|
||||
if (entityComponentIcons) {
|
||||
const translations =
|
||||
(deviceClass && entityComponentIcons[deviceClass]) ||
|
||||
entityComponentIcons._;
|
||||
return translations?.default;
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
@ -8,7 +8,6 @@ import {
|
||||
mdiWeatherLightning,
|
||||
mdiWeatherLightningRainy,
|
||||
mdiWeatherNight,
|
||||
mdiWeatherNightPartlyCloudy,
|
||||
mdiWeatherPartlyCloudy,
|
||||
mdiWeatherPouring,
|
||||
mdiWeatherRainy,
|
||||
@ -520,13 +519,6 @@ export const getWeatherStateIcon = (
|
||||
return undefined;
|
||||
};
|
||||
|
||||
export const weatherIcon = (state?: string, nightTime?: boolean): string =>
|
||||
!state
|
||||
? undefined
|
||||
: nightTime && state === "partlycloudy"
|
||||
? mdiWeatherNightPartlyCloudy
|
||||
: weatherIcons[state];
|
||||
|
||||
const EIGHT_HOURS = 28800000;
|
||||
const DAY_IN_MILLISECONDS = 86400000;
|
||||
|
||||
|
@ -8,7 +8,7 @@ import {
|
||||
mdiReload,
|
||||
mdiServerNetwork,
|
||||
} from "@mdi/js";
|
||||
import { LitElement, css, html, nothing } from "lit";
|
||||
import { LitElement, TemplateResult, css, html, nothing } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import { ifDefined } from "lit/directives/if-defined";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
@ -17,9 +17,7 @@ import { canShowPage } from "../../common/config/can_show_page";
|
||||
import { componentsWithService } from "../../common/config/components_with_service";
|
||||
import { isComponentLoaded } from "../../common/config/is_component_loaded";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import { computeDomain } from "../../common/entity/compute_domain";
|
||||
import { computeStateName } from "../../common/entity/compute_state_name";
|
||||
import { domainIcon } from "../../common/entity/domain_icon";
|
||||
import { navigate } from "../../common/navigate";
|
||||
import { caseInsensitiveStringCompare } from "../../common/string/compare";
|
||||
import {
|
||||
@ -27,9 +25,9 @@ import {
|
||||
fuzzyFilterSort,
|
||||
} from "../../common/string/filter/sequence-matching";
|
||||
import { debounce } from "../../common/util/debounce";
|
||||
import "../../components/ha-label";
|
||||
import "../../components/ha-circular-progress";
|
||||
import "../../components/ha-icon-button";
|
||||
import "../../components/ha-label";
|
||||
import "../../components/ha-list-item";
|
||||
import "../../components/ha-textfield";
|
||||
import { fetchHassioAddonsInfo } from "../../data/hassio/addon";
|
||||
@ -56,7 +54,7 @@ interface CommandItem extends QuickBarItem {
|
||||
|
||||
interface EntityItem extends QuickBarItem {
|
||||
altText: string;
|
||||
icon?: string;
|
||||
icon?: TemplateResult;
|
||||
}
|
||||
|
||||
const isCommandItem = (item: QuickBarItem): item is CommandItem =>
|
||||
@ -296,16 +294,14 @@ export class QuickBar extends LitElement {
|
||||
graphic="icon"
|
||||
>
|
||||
${item.iconPath
|
||||
? html`<ha-svg-icon
|
||||
.path=${item.iconPath}
|
||||
class="entity"
|
||||
slot="graphic"
|
||||
></ha-svg-icon>`
|
||||
: html`<ha-icon
|
||||
.icon=${item.icon}
|
||||
class="entity"
|
||||
slot="graphic"
|
||||
></ha-icon>`}
|
||||
? html`
|
||||
<ha-svg-icon
|
||||
.path=${item.iconPath}
|
||||
class="entity"
|
||||
slot="graphic"
|
||||
></ha-svg-icon>
|
||||
`
|
||||
: html`<span slot="graphic">${item.icon}</span>`}
|
||||
<span>${item.primaryText}</span>
|
||||
${item.altText
|
||||
? html`
|
||||
@ -476,10 +472,12 @@ export class QuickBar extends LitElement {
|
||||
const entityItem = {
|
||||
primaryText: computeStateName(entityState),
|
||||
altText: entityId,
|
||||
icon: entityState.attributes.icon,
|
||||
iconPath: entityState.attributes.icon
|
||||
? undefined
|
||||
: domainIcon(computeDomain(entityId), entityState),
|
||||
icon: html`
|
||||
<ha-state-icon
|
||||
.hass=${this.hass}
|
||||
.stateObj=${entityState}
|
||||
></ha-state-icon>
|
||||
`,
|
||||
action: () => fireEvent(this, "hass-more-info", { entityId }),
|
||||
};
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
import "@material/mwc-list/mwc-list";
|
||||
import "@material/web/divider/divider";
|
||||
import { mdiClose, mdiContentPaste, mdiPlus } from "@mdi/js";
|
||||
import Fuse, { IFuseOptions } from "fuse.js";
|
||||
import {
|
||||
@ -16,17 +17,21 @@ import { repeat } from "lit/directives/repeat";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { domainIconWithoutDefault } from "../../../common/entity/domain_icon";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { stringCompare } from "../../../common/string/compare";
|
||||
import { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import { deepEqual } from "../../../common/util/deep-equal";
|
||||
import "../../../components/ha-dialog";
|
||||
import type { HaDialog } from "../../../components/ha-dialog";
|
||||
import "../../../components/ha-dialog-header";
|
||||
import "../../../components/ha-domain-icon";
|
||||
import "../../../components/ha-icon-button";
|
||||
import "../../../components/ha-icon-button-prev";
|
||||
import "../../../components/ha-icon-next";
|
||||
import "../../../components/ha-list-new";
|
||||
import "../../../components/ha-list-item-new";
|
||||
import "../../../components/ha-list-new";
|
||||
import "../../../components/ha-service-icon";
|
||||
import "../../../components/search-input";
|
||||
import {
|
||||
ACTION_GROUPS,
|
||||
ACTION_ICONS,
|
||||
@ -36,6 +41,7 @@ import {
|
||||
} from "../../../data/action";
|
||||
import { AutomationElementGroup } from "../../../data/automation";
|
||||
import { CONDITION_GROUPS, CONDITION_ICONS } from "../../../data/condition";
|
||||
import { getServiceIcons } from "../../../data/icons";
|
||||
import {
|
||||
IntegrationManifest,
|
||||
domainToName,
|
||||
@ -45,16 +51,10 @@ import { TRIGGER_GROUPS, TRIGGER_ICONS } from "../../../data/trigger";
|
||||
import { HassDialog } from "../../../dialogs/make-dialog-manager";
|
||||
import { haStyle, haStyleDialog } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { brandsUrl } from "../../../util/brands-url";
|
||||
import {
|
||||
AddAutomationElementDialogParams,
|
||||
PASTE_VALUE,
|
||||
} from "./show-add-automation-element-dialog";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { deepEqual } from "../../../common/util/deep-equal";
|
||||
import "../../../components/search-input";
|
||||
import "@material/web/divider/divider";
|
||||
import { getServiceIcons } from "../../../data/icons";
|
||||
|
||||
const TYPES = {
|
||||
trigger: { groups: TRIGGER_GROUPS, icons: TRIGGER_ICONS },
|
||||
@ -74,7 +74,6 @@ interface ListItem {
|
||||
description: string;
|
||||
iconPath?: string;
|
||||
icon?: TemplateResult;
|
||||
image?: string;
|
||||
group: boolean;
|
||||
}
|
||||
|
||||
@ -318,17 +317,15 @@ class DialogAddAutomationElement extends LitElement implements HassDialog {
|
||||
(!domainUsed && manifest?.integration_type === "entity") ||
|
||||
!["helper", "entity"].includes(manifest?.integration_type || "")))
|
||||
) {
|
||||
const icon = domainIconWithoutDefault(domain);
|
||||
result.push({
|
||||
group: true,
|
||||
iconPath: icon,
|
||||
image: !icon
|
||||
? brandsUrl({
|
||||
domain,
|
||||
type: "icon",
|
||||
darkOptimized: this.hass.themes?.darkMode,
|
||||
})
|
||||
: undefined,
|
||||
icon: html`
|
||||
<ha-domain-icon
|
||||
.hass=${this.hass}
|
||||
.domain=${domain}
|
||||
brandFallback
|
||||
></ha-domain-icon>
|
||||
`,
|
||||
key: `${SERVICE_PREFIX}${domain}`,
|
||||
name: domainToName(localize, domain, manifest),
|
||||
description: "",
|
||||
@ -364,10 +361,12 @@ class DialogAddAutomationElement extends LitElement implements HassDialog {
|
||||
for (const service of services_keys) {
|
||||
result.push({
|
||||
group: false,
|
||||
icon: html`<ha-service-icon
|
||||
.hass=${this.hass}
|
||||
.service=${`${dmn}.${service}`}
|
||||
></ha-service-icon>`,
|
||||
icon: html`
|
||||
<ha-service-icon
|
||||
.hass=${this.hass}
|
||||
.service=${`${dmn}.${service}`}
|
||||
></ha-service-icon>
|
||||
`,
|
||||
key: `${SERVICE_PREFIX}${dmn}.${service}`,
|
||||
name: `${domain ? "" : `${domainToName(localize, dmn)}: `}${
|
||||
this.hass.localize(`component.${dmn}.services.${service}.name`) ||
|
||||
@ -578,13 +577,7 @@ class DialogAddAutomationElement extends LitElement implements HassDialog {
|
||||
slot="start"
|
||||
.path=${item.iconPath}
|
||||
></ha-svg-icon>`
|
||||
: html`<img
|
||||
alt=""
|
||||
slot="start"
|
||||
src=${item.image!}
|
||||
crossorigin="anonymous"
|
||||
referrerpolicy="no-referrer"
|
||||
/>`}
|
||||
: nothing}
|
||||
${item.group
|
||||
? html`<ha-icon-next slot="end"></ha-icon-next>`
|
||||
: html`<ha-svg-icon
|
||||
|
@ -12,11 +12,11 @@ import { classMap } from "lit/directives/class-map";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { alarmPanelIcon } from "../../../common/entity/alarm_panel_icon";
|
||||
import { stateColorCss } from "../../../common/entity/state_color";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
import "../../../components/chips/ha-assist-chip";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-state-icon";
|
||||
import "../../../components/ha-textfield";
|
||||
import type { HaTextField } from "../../../components/ha-textfield";
|
||||
import {
|
||||
@ -199,8 +199,11 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
|
||||
@click=${this._handleMoreInfo}
|
||||
.label=${stateLabel}
|
||||
>
|
||||
<ha-svg-icon slot="icon" .path=${alarmPanelIcon(stateObj.state)}>
|
||||
</ha-svg-icon>
|
||||
<ha-state-icon
|
||||
slot="icon"
|
||||
.hass=${this.hass}
|
||||
.stateObj=${stateObj}
|
||||
></ha-state-icon>
|
||||
</ha-assist-chip>
|
||||
</h1>
|
||||
<div id="armActions" class="actions">
|
||||
|
@ -23,9 +23,8 @@ import { customElement, property, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { FIXED_DEVICE_CLASS_ICONS, STATES_OFF } from "../../../common/const";
|
||||
import { STATES_OFF } from "../../../common/const";
|
||||
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
||||
import { binarySensorIcon } from "../../../common/entity/binary_sensor_icon";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { navigate } from "../../../common/navigate";
|
||||
import {
|
||||
@ -36,8 +35,9 @@ import { blankBeforeUnit } from "../../../common/translations/blank_before_unit"
|
||||
import parseAspectRatio from "../../../common/util/parse-aspect-ratio";
|
||||
import { subscribeOne } from "../../../common/util/subscribe-one";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-domain-icon";
|
||||
import "../../../components/ha-icon-button";
|
||||
import "../../../components/ha-svg-icon";
|
||||
import "../../../components/ha-state-icon";
|
||||
import {
|
||||
AreaRegistryEntry,
|
||||
subscribeAreaRegistry,
|
||||
@ -388,13 +388,16 @@ export class HuiAreaCard
|
||||
(entity) => entity.attributes.device_class === deviceClass
|
||||
)
|
||||
) {
|
||||
const icon = FIXED_DEVICE_CLASS_ICONS[deviceClass];
|
||||
sensors.push(
|
||||
html`<div class="sensor">
|
||||
${icon ? html`<ha-svg-icon .path=${icon}></ha-svg-icon>` : ""}
|
||||
sensors.push(html`
|
||||
<div class="sensor">
|
||||
<ha-domain-icon
|
||||
.hass=${this.hass}
|
||||
.domain=${domain}
|
||||
.deviceClass=${deviceClass}
|
||||
></ha-domain-icon>
|
||||
${this._average(domain, deviceClass)}
|
||||
</div> `
|
||||
);
|
||||
</div>
|
||||
`);
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -434,16 +437,18 @@ export class HuiAreaCard
|
||||
<div class="alerts">
|
||||
${ALERT_DOMAINS.map((domain) => {
|
||||
if (!(domain in entitiesByDomain)) {
|
||||
return "";
|
||||
return nothing;
|
||||
}
|
||||
return this._deviceClasses[domain].map((deviceClass) => {
|
||||
const entity = this._isOn(domain, deviceClass);
|
||||
return entity
|
||||
? html`<ha-svg-icon
|
||||
class="alert"
|
||||
.path=${DOMAIN_ICONS[domain][deviceClass] ||
|
||||
binarySensorIcon(entity.state, entity)}
|
||||
></ha-svg-icon>`
|
||||
? html`
|
||||
<ha-state-icon
|
||||
class="alert"
|
||||
.hass=${this.hass}
|
||||
.stateObj=${entity}
|
||||
></ha-state-icon>
|
||||
`
|
||||
: nothing;
|
||||
});
|
||||
})}
|
||||
@ -574,7 +579,14 @@ export class HuiAreaCard
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.alerts ha-svg-icon {
|
||||
ha-state-icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.alerts ha-state-icon {
|
||||
background: var(--accent-color);
|
||||
color: var(--text-accent-color, var(--text-primary-color));
|
||||
padding: 8px;
|
||||
|
@ -16,7 +16,7 @@ import {
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { batteryIcon } from "../../../common/entity/battery_icon";
|
||||
import { batteryLevelIcon } from "../../../common/entity/battery_icon";
|
||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-svg-icon";
|
||||
@ -252,7 +252,7 @@ class HuiPlantStatusCard extends LitElement implements LovelaceCard {
|
||||
|
||||
private computeIcon(attr: string, batLvl: number): string {
|
||||
if (attr === "battery") {
|
||||
return batteryIcon(batLvl);
|
||||
return batteryLevelIcon(batLvl);
|
||||
}
|
||||
return SENSOR_ICONS[attr];
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
import "@material/mwc-button/mwc-button";
|
||||
import "@material/mwc-linear-progress/mwc-linear-progress";
|
||||
import type { LinearProgress } from "@material/mwc-linear-progress/mwc-linear-progress";
|
||||
import "@material/mwc-list/mwc-list-item";
|
||||
import {
|
||||
mdiChevronDown,
|
||||
mdiMonitor,
|
||||
@ -12,11 +10,11 @@ import {
|
||||
mdiVolumeHigh,
|
||||
} from "@mdi/js";
|
||||
import {
|
||||
css,
|
||||
CSSResultGroup,
|
||||
html,
|
||||
LitElement,
|
||||
PropertyValues,
|
||||
css,
|
||||
html,
|
||||
nothing,
|
||||
} from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
@ -26,25 +24,29 @@ import { fireEvent } from "../../common/dom/fire_event";
|
||||
import { computeDomain } from "../../common/entity/compute_domain";
|
||||
import { computeStateDomain } from "../../common/entity/compute_state_domain";
|
||||
import { computeStateName } from "../../common/entity/compute_state_name";
|
||||
import { domainIcon } from "../../common/entity/domain_icon";
|
||||
import { supportsFeature } from "../../common/entity/supports-feature";
|
||||
import { debounce } from "../../common/util/debounce";
|
||||
import "../../components/ha-button";
|
||||
import "../../components/ha-button-menu";
|
||||
import "../../components/ha-circular-progress";
|
||||
import "../../components/ha-domain-icon";
|
||||
import "../../components/ha-icon-button";
|
||||
import "../../components/ha-list-item";
|
||||
import "../../components/ha-state-icon";
|
||||
import "../../components/ha-svg-icon";
|
||||
import { UNAVAILABLE } from "../../data/entity";
|
||||
import {
|
||||
BROWSER_PLAYER,
|
||||
cleanupMediaTitle,
|
||||
computeMediaControls,
|
||||
computeMediaDescription,
|
||||
ControlButton,
|
||||
formatMediaTime,
|
||||
getCurrentProgress,
|
||||
handleMediaControlClick,
|
||||
MediaPlayerEntity,
|
||||
MediaPlayerEntityFeature,
|
||||
MediaPlayerItem,
|
||||
cleanupMediaTitle,
|
||||
computeMediaControls,
|
||||
computeMediaDescription,
|
||||
formatMediaTime,
|
||||
getCurrentProgress,
|
||||
handleMediaControlClick,
|
||||
setMediaPlayerVolume,
|
||||
} from "../../data/media-player";
|
||||
import { ResolvedMediaSource } from "../../data/media_source";
|
||||
@ -56,7 +58,6 @@ import {
|
||||
BrowserMediaPlayer,
|
||||
ERR_UNSUPPORTED_MEDIA,
|
||||
} from "./browser-media-player";
|
||||
import { debounce } from "../../common/util/debounce";
|
||||
|
||||
declare global {
|
||||
interface HASSDomEvents {
|
||||
@ -320,22 +321,19 @@ export class BarMediaPlayer extends SubscribeMixin(LitElement) {
|
||||
: ""
|
||||
}
|
||||
|
||||
<ha-button-menu >
|
||||
<ha-button-menu>
|
||||
${
|
||||
this.narrow
|
||||
? html`
|
||||
<ha-icon-button
|
||||
slot="trigger"
|
||||
.path=${isBrowser
|
||||
? mdiMonitor
|
||||
: domainIcon(computeDomain(this.entityId), stateObj)}
|
||||
></ha-icon-button>
|
||||
<ha-icon-button slot="trigger">
|
||||
${this._renderIcon(isBrowser, stateObj)}
|
||||
</ha-icon-button>
|
||||
`
|
||||
: html`
|
||||
<ha-button
|
||||
slot="trigger"
|
||||
.label=${this.narrow
|
||||
? ""
|
||||
? nothing
|
||||
: `${
|
||||
stateObj
|
||||
? computeStateName(stateObj)
|
||||
@ -343,12 +341,9 @@ export class BarMediaPlayer extends SubscribeMixin(LitElement) {
|
||||
}
|
||||
`}
|
||||
>
|
||||
<ha-svg-icon
|
||||
slot="icon"
|
||||
.path=${isBrowser
|
||||
? mdiMonitor
|
||||
: domainIcon(computeDomain(this.entityId), stateObj)}
|
||||
></ha-svg-icon>
|
||||
<span slot="icon">
|
||||
${this._renderIcon(isBrowser, stateObj)}
|
||||
</span>
|
||||
<ha-svg-icon
|
||||
slot="trailingIcon"
|
||||
.path=${mdiChevronDown}
|
||||
@ -356,23 +351,23 @@ export class BarMediaPlayer extends SubscribeMixin(LitElement) {
|
||||
</ha-button>
|
||||
`
|
||||
}
|
||||
<mwc-list-item
|
||||
<ha-list-item
|
||||
.player=${BROWSER_PLAYER}
|
||||
?selected=${isBrowser}
|
||||
@click=${this._selectPlayer}
|
||||
>
|
||||
${this.hass.localize("ui.components.media-browser.web-browser")}
|
||||
</mwc-list-item>
|
||||
</ha-list-item>
|
||||
${this._mediaPlayerEntities.map(
|
||||
(source) => html`
|
||||
<mwc-list-item
|
||||
<ha-list-item
|
||||
?selected=${source.entity_id === this.entityId}
|
||||
.disabled=${source.state === UNAVAILABLE}
|
||||
.player=${source.entity_id}
|
||||
@click=${this._selectPlayer}
|
||||
>
|
||||
${computeStateName(source)}
|
||||
</mwc-list-item>
|
||||
</ha-list-item>
|
||||
`
|
||||
)}
|
||||
</ha-button-menu>
|
||||
@ -382,6 +377,23 @@ export class BarMediaPlayer extends SubscribeMixin(LitElement) {
|
||||
`;
|
||||
}
|
||||
|
||||
private _renderIcon(isBrowser: boolean, stateObj?: MediaPlayerEntity) {
|
||||
if (isBrowser) {
|
||||
return html`<ha-svg-icon .path=${mdiMonitor}></ha-svg-icon>`;
|
||||
}
|
||||
if (stateObj) {
|
||||
return html`
|
||||
<ha-state-icon .hass=${this.hass} .stateObj=${stateObj}></ha-state-icon>
|
||||
`;
|
||||
}
|
||||
return html`
|
||||
<ha-domain-icon
|
||||
.hass=${this.hass}
|
||||
.domain=${computeDomain(this.entityId)}
|
||||
></ha-domain-icon>
|
||||
`;
|
||||
}
|
||||
|
||||
public willUpdate(changedProps: PropertyValues) {
|
||||
super.willUpdate(changedProps);
|
||||
if (changedProps.has("entityId")) {
|
||||
@ -571,9 +583,10 @@ export class BarMediaPlayer extends SubscribeMixin(LitElement) {
|
||||
--mdc-theme-primary: var(--secondary-text-color);
|
||||
}
|
||||
|
||||
mwc-button[slot="trigger"] {
|
||||
ha-button-menu ha-button[slot="trigger"] {
|
||||
line-height: 1;
|
||||
--mdc-theme-primary: var(--primary-text-color);
|
||||
--mdc-icon-size: 36px;
|
||||
--mdc-icon-size: 16px;
|
||||
}
|
||||
|
||||
.info {
|
||||
@ -655,10 +668,6 @@ export class BarMediaPlayer extends SubscribeMixin(LitElement) {
|
||||
margin: 16px 0 16px 16px;
|
||||
}
|
||||
|
||||
ha-button-menu mwc-button {
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
:host([narrow]) {
|
||||
height: 57px;
|
||||
}
|
||||
@ -705,10 +714,15 @@ export class BarMediaPlayer extends SubscribeMixin(LitElement) {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
mwc-list-item[selected] {
|
||||
ha-list-item[selected] {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
span[slot="icon"] {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
ha-svg-icon[slot="trailingIcon"] {
|
||||
margin-inline-start: 8px !important;
|
||||
margin-inline-end: 0px !important;
|
||||
|
Loading…
x
Reference in New Issue
Block a user