You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
185 lines
5.0 KiB
185 lines
5.0 KiB
<script lang="ts" context="module">
|
|
export const DARK_COLOR = rgb(0.5176470588235295/2, 0.5333333333333333/2, 0.5607843137254902/1.75);
|
|
export const DARK_COLOR_SELECTED = rgb(0.5176470588235295/1.5, 0.5333333333333333/1.5, 0.5607843137254902/1.25);
|
|
</script>
|
|
|
|
<script lang="ts">
|
|
import { getSelectedContext } from "$lib/contexts/SelectContext.svelte";
|
|
import type Device from "$lib/models/device";
|
|
import { SupportFlags } from "$lib/models/device";
|
|
import { rgb, type ColorRGB } from "../models/color";
|
|
import DeviceIcon from "./DeviceIcon.svelte";
|
|
|
|
export let device: Device;
|
|
export let compact: boolean = false;
|
|
|
|
const {selectedMap, toggleSelection} = getSelectedContext();
|
|
|
|
function onSelect() {
|
|
toggleSelection(device.id);
|
|
}
|
|
|
|
// Process device
|
|
let deviceTitle: string;
|
|
let iconColor: ColorRGB | null;
|
|
let barColor: ColorRGB | null;
|
|
let barFraction: number | null;
|
|
let roundboiText: string | null;
|
|
$: {
|
|
// TODO: Fix device.name on the backend
|
|
const nameAlias = device.aliases?.find(a => a.startsWith("lucifer:name:"));
|
|
if (nameAlias != null) {
|
|
deviceTitle = nameAlias.slice("lucifer:name:".length);
|
|
} else {
|
|
deviceTitle = "";
|
|
}
|
|
|
|
barFraction = null;
|
|
barColor = null;
|
|
iconColor = null;
|
|
|
|
if (device.hwState) {
|
|
const hws = device.hwState;
|
|
const sflags = hws.supportFlags;
|
|
|
|
const hasColor = !!(sflags & SupportFlags.Color);
|
|
const hasPower = !!(sflags & SupportFlags.Power)
|
|
|
|
if (deviceTitle == "") {
|
|
deviceTitle = device.hwState.internalName;
|
|
}
|
|
|
|
if (hasColor && (!hasPower || device.desiredState.power)) {
|
|
iconColor = device.desiredColorRgb;
|
|
} else {
|
|
iconColor = null;
|
|
}
|
|
|
|
if (sflags & SupportFlags.SensorPresence) {
|
|
barColor = rgb(0.5,0.5,0.5);
|
|
barFraction = Math.max(0, (300 - (device.sensors.lastMotion!=null?device.sensors.lastMotion:300))/300);
|
|
}
|
|
|
|
if (sflags & SupportFlags.Temperature) {
|
|
barColor = rgb(1.000,0.2,0.2);
|
|
barFraction = Math.min(1, Math.max(0, (device.desiredState.temperature||0) - 5) / 35) * 1;
|
|
}
|
|
|
|
if (sflags & SupportFlags.Intensity) {
|
|
if (sflags & SupportFlags.Color) {
|
|
barColor = device.desiredColorRgb;
|
|
} else {
|
|
barColor = rgb(1.000,0.671,0.355);
|
|
}
|
|
|
|
barFraction = device.desiredState?.intensity || 0;
|
|
}
|
|
|
|
if (sflags & SupportFlags.SensorTemperature && !!device.sensors.temperature) {
|
|
roundboiText = `${device.sensors.temperature.toFixed(0)}°`
|
|
}
|
|
}
|
|
}
|
|
|
|
// Make title visible
|
|
let displayTitle: string;
|
|
$: {
|
|
if (deviceTitle.length > 12) {
|
|
let last = deviceTitle.split(" ").pop() || deviceTitle;
|
|
if (last.length > 4) {
|
|
last = last.slice(-3);
|
|
}
|
|
|
|
displayTitle = `${(deviceTitle.split(" ").shift()||"").slice(0, 10 - last.length)}... ${last}`
|
|
} else {
|
|
displayTitle = deviceTitle;
|
|
}
|
|
}
|
|
|
|
let darkColor: ColorRGB;
|
|
$: darkColor = $selectedMap[device.id] ? DARK_COLOR_SELECTED : DARK_COLOR
|
|
</script>
|
|
|
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
<div class="lamp" class:compact class:selected={$selectedMap[device.id]} on:click={onSelect}>
|
|
<div class="row">
|
|
<div class="row-icon">
|
|
{#if iconColor != null}
|
|
<DeviceIcon name={device.icon||"generic_ball"} brightColor={iconColor} darkColor={darkColor} />
|
|
{:else}
|
|
<DeviceIcon name={device.icon||"generic_ball"} brightColor={darkColor} darkColor={darkColor}>
|
|
{#if !!roundboiText}
|
|
<div class="roundboi-text">{roundboiText}</div>
|
|
{/if}
|
|
</DeviceIcon>
|
|
{/if}
|
|
</div>
|
|
<div class="title">{displayTitle}</div>
|
|
</div>
|
|
<div class="flatboi">
|
|
{#if barColor != null && barFraction != null}
|
|
<div style="width: {barFraction*100}%; background-color: rgb({barColor.red*255},{barColor.green*255},{barColor.blue*255})" class="flatboi2"></div>
|
|
{/if}
|
|
</div>
|
|
</div>
|
|
|
|
<style lang="sass">
|
|
div.lamp
|
|
cursor: pointer
|
|
width: 19ch
|
|
height: 2em
|
|
margin: 0.5ch
|
|
background: #18181c
|
|
color: #84888f
|
|
border-radius: 0.5ch
|
|
border-top-right-radius: 1em
|
|
overflow: hidden
|
|
box-shadow: 1px 1px 1px #000
|
|
|
|
@media screen and (max-width: 700px)
|
|
width: 100%
|
|
|
|
&.selected
|
|
background: #282833
|
|
color: #cde
|
|
|
|
> div.row
|
|
display: flex
|
|
|
|
> div.row-icon
|
|
font-size: 1.8em
|
|
position: absolute
|
|
width: 0
|
|
height: 0
|
|
|
|
div.roundboi-text
|
|
width: 0
|
|
height: 0
|
|
left: 1.4ch
|
|
top: 0.9em
|
|
text-align: center
|
|
position: absolute
|
|
font-size: 0.333em
|
|
|
|
> div.title
|
|
font-size: 0.9em
|
|
text-align: left
|
|
margin-top: 0.4em
|
|
margin-left: 2em
|
|
margin-right: 1ch
|
|
height: 1.6em
|
|
|
|
> div.flatboi
|
|
height: 0.2em
|
|
|
|
> div.flatboi2
|
|
height: 0.2em
|
|
|
|
&.compact
|
|
width: 3ch
|
|
border-top-right-radius: 0.25em
|
|
div.row
|
|
margin-left: -0.1ch
|
|
div.title
|
|
opacity: 0
|
|
</style>
|