Compare commits
10 Commits
0c35647203
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| f8dacd3122 | |||
| 6e1b7eab74 | |||
| f0af1eacfa | |||
| 1ee7f0c739 | |||
| 8f7bae56db | |||
| 962628912d | |||
| 0bff60aa45 | |||
| 1d6dce7b42 | |||
| 9e061b7078 | |||
| 92b68ca21a |
+10
-1
@@ -112,7 +112,16 @@ home-assistant_v2.db-wal
|
|||||||
# Dependencies and cache
|
# Dependencies and cache
|
||||||
deps/
|
deps/
|
||||||
tts/
|
tts/
|
||||||
www/
|
# www/ is HA's public static dir: HACS frontend plugins, camera snapshots and
|
||||||
|
# TTS junk all land in it, so it stays ignored — except for the small
|
||||||
|
# hand-written frontend modules we actually author and want in git.
|
||||||
|
# (git will not descend into an excluded directory, so each level has to be
|
||||||
|
# re-included before the next one can be narrowed again.)
|
||||||
|
!www/
|
||||||
|
www/*
|
||||||
|
!www/cubecraft/
|
||||||
|
www/cubecraft/*
|
||||||
|
!www/cubecraft/*.js
|
||||||
custom_components/
|
custom_components/
|
||||||
image/
|
image/
|
||||||
ms365_storage/
|
ms365_storage/
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|||||||
|
|
||||||
## What this repo is
|
## What this repo is
|
||||||
|
|
||||||
The Home Assistant configuration directory (`/config` on the live HAOS host, mirrored to this git repo). It is **configuration, not application code** — there is no build or test suite. "Running" a change means HA loads it; validation is by config-check and reload, not unit tests. The repo is also mirrored to a self-hosted Gitea at `code.cubecraftcreations.com`.
|
The Home Assistant configuration directory (`/config` on the live HAOS host, mirrored to this git repo). It is **configuration, not application code** — there is no build or test suite. "Running" a change means HA loads it; validation is by config-check and reload, not unit tests. The repo is also mirrored to a self-hosted Gitea at `code.cubecraftlabs.com` (`origin` is `https://code.cubecraftlabs.com/overseer/Home-Assistant.git`).
|
||||||
|
|
||||||
Edits here only take effect after they reach the live host and HA reloads the affected domain. There is no compile step; a malformed YAML file breaks the domain it belongs to (or all of HA if it's `configuration.yaml`).
|
Edits here only take effect after they reach the live host and HA reloads the affected domain. There is no compile step; a malformed YAML file breaks the domain it belongs to (or all of HA if it's `configuration.yaml`).
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,15 @@
|
|||||||
homeassistant:
|
homeassistant:
|
||||||
packages: !include_dir_named packages/
|
packages: !include_dir_named packages/
|
||||||
|
auth_providers:
|
||||||
|
- type: trusted_networks
|
||||||
|
trusted_networks:
|
||||||
|
- 192.168.69.0/24
|
||||||
|
- 10.60.1.0/24
|
||||||
|
trusted_users:
|
||||||
|
192.168.69.0/24: 66e8deaeb6944b65a6ed652d671599e2
|
||||||
|
10.60.1.0/24: 66e8deaeb6944b65a6ed652d671599e2
|
||||||
|
allow_bypass_login: true
|
||||||
|
- type: homeassistant
|
||||||
|
|
||||||
# Loads default set of integrations. Do not remove.
|
# Loads default set of integrations. Do not remove.
|
||||||
default_config:
|
default_config:
|
||||||
@@ -7,6 +17,12 @@ default_config:
|
|||||||
# Load frontend themes from the themes folder
|
# Load frontend themes from the themes folder
|
||||||
frontend:
|
frontend:
|
||||||
themes: !include_dir_merge_named themes
|
themes: !include_dir_merge_named themes
|
||||||
|
# Declares the Nunito @font-face document-wide for the CubeCraft display
|
||||||
|
# system. A theme can only set font-family, not load the face — see
|
||||||
|
# www/cubecraft/cubecraft-brand-font.js. Bump ?v= after editing that file to
|
||||||
|
# get past the browser cache.
|
||||||
|
extra_module_url:
|
||||||
|
- /local/cubecraft/cubecraft-brand-font.js?v=1
|
||||||
|
|
||||||
lovelace:
|
lovelace:
|
||||||
dashboards: !include dashboards/dashboards.yaml
|
dashboards: !include dashboards/dashboards.yaml
|
||||||
@@ -28,6 +44,8 @@ http:
|
|||||||
use_x_forwarded_for: true
|
use_x_forwarded_for: true
|
||||||
trusted_proxies:
|
trusted_proxies:
|
||||||
- 10.60.1.1
|
- 10.60.1.1
|
||||||
|
cors_allowed_origins:
|
||||||
|
- https://dakboard.com
|
||||||
|
|
||||||
### notify_events ###
|
### notify_events ###
|
||||||
notify_events:
|
notify_events:
|
||||||
|
|||||||
@@ -2,4 +2,4 @@ mode: yaml
|
|||||||
title: CubeOps
|
title: CubeOps
|
||||||
icon: mdi:alarm-panel
|
icon: mdi:alarm-panel
|
||||||
show_in_sidebar: true
|
show_in_sidebar: true
|
||||||
filename: dashboards/views/cubeops-dashboard.yaml
|
filename: dashboards/views/cube-ops-dashboard.yaml
|
||||||
@@ -1,4 +1,9 @@
|
|||||||
voice-alarms: !include voice-alarms.yaml
|
voice-alarms: !include voice-alarms.yaml
|
||||||
family-hub: !include family-hub.yaml
|
family-hub: !include family-hub.yaml
|
||||||
at-a-glance: !include at-a-glance.yaml
|
at-a-glance: !include at-a-glance.yaml
|
||||||
cubeops: !include cubeops.yaml
|
lunch-menus: !include lunch-menus.yaml
|
||||||
|
# Each key is the dashboard's url_path, and HA requires it to contain a hyphen
|
||||||
|
# (see homeassistant/components/lovelace: url_path validation). A hyphen-less
|
||||||
|
# key fails validation for the whole `lovelace:` block, not just its own entry,
|
||||||
|
# which takes every dashboard here down with it.
|
||||||
|
cube-ops: !include cube-ops.yaml
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
mode: yaml
|
||||||
|
title: Lunch Menus
|
||||||
|
icon: mdi:food-apple
|
||||||
|
show_in_sidebar: true
|
||||||
|
filename: dashboards/views/lunch-menus-dashboard.yaml
|
||||||
@@ -1,13 +1,33 @@
|
|||||||
|
# At-a-Glance — wall panel
|
||||||
|
#
|
||||||
|
# Styled with the CubeCraft Creations display system. The tokens live in
|
||||||
|
# themes/cubecraft.yaml, which mirrors the `:host` block of the production
|
||||||
|
# card's stylesheet (custom_components/cubecraft_production/www/
|
||||||
|
# cubecraft-production-card.js). Anything referenced here as --cc-* comes from
|
||||||
|
# that theme, so this file never hard-codes a brand hex.
|
||||||
|
#
|
||||||
|
# Three motifs carry the style, all lifted from the production card:
|
||||||
|
# .title → gradient title bar, white 800-weight type, brand radius
|
||||||
|
# .column header → uppercase 700/.05em muted section labels
|
||||||
|
# article → 8px radius, 4px brand left rule, shadow-sm on each tile
|
||||||
|
#
|
||||||
|
# Colour is deliberately restrained: brand indigo for anything informational,
|
||||||
|
# and green/amber/red kept in reserve so they still mean something when they
|
||||||
|
# show up. That is the same discipline the production card uses, where only a
|
||||||
|
# blocked order goes red.
|
||||||
title: At-a-Glance
|
title: At-a-Glance
|
||||||
theme: dakboard-dark
|
theme: cubecraft
|
||||||
views:
|
views:
|
||||||
- title: At-a-Glance
|
- title: At-a-Glance
|
||||||
path: at-a-glance
|
path: at-a-glance
|
||||||
icon: mdi:eye-outline
|
icon: mdi:eye-outline
|
||||||
theme: dakboard-dark
|
theme: cubecraft
|
||||||
type: masonry
|
type: masonry
|
||||||
cards:
|
cards:
|
||||||
# ── Header ──
|
# ── Brand title bar ──
|
||||||
|
# Mirrors `.shell.kiosk .title`: gradient ground, white type at 1.75rem,
|
||||||
|
# brand radius and the brand shadow. ha-markdown supplies its own 16px
|
||||||
|
# inset, so ha-card only tops that up to roughly the card's 20px/28px.
|
||||||
- type: markdown
|
- type: markdown
|
||||||
content: |
|
content: |
|
||||||
# {{ now().strftime("%A, %B %d, %Y") }}
|
# {{ now().strftime("%A, %B %d, %Y") }}
|
||||||
@@ -15,21 +35,28 @@ views:
|
|||||||
card_mod:
|
card_mod:
|
||||||
style: |
|
style: |
|
||||||
ha-card {
|
ha-card {
|
||||||
|
background: var(--cc-gradient);
|
||||||
|
color: #fff;
|
||||||
|
border: none;
|
||||||
|
border-radius: var(--cc-radius-brand);
|
||||||
|
box-shadow: var(--cc-shadow-brand);
|
||||||
|
padding: 6px 12px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
background: none;
|
|
||||||
box-shadow: none;
|
|
||||||
padding: 0 0 4px 0;
|
|
||||||
}
|
}
|
||||||
ha-card h1 {
|
ha-card h1 {
|
||||||
font-size: 1.2em;
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-weight: 300;
|
font-size: 1rem;
|
||||||
color: var(--secondary-text-color);
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
opacity: 0.85;
|
||||||
|
color: #fff;
|
||||||
}
|
}
|
||||||
ha-card h2 {
|
ha-card h2 {
|
||||||
font-size: 2em;
|
|
||||||
margin: 2px 0 0 0;
|
margin: 2px 0 0 0;
|
||||||
font-weight: 400;
|
font-size: 1.75rem;
|
||||||
|
font-weight: 800;
|
||||||
|
letter-spacing: -0.01em;
|
||||||
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── Weather Now ──
|
# ── Weather Now ──
|
||||||
@@ -41,127 +68,200 @@ views:
|
|||||||
round_temperature: true
|
round_temperature: true
|
||||||
|
|
||||||
# ── Indoor Climate ──
|
# ── Indoor Climate ──
|
||||||
|
# First use of the section-label treatment; the rest of the file aliases
|
||||||
|
# it as *cc_section. Selectors are listed broadly on purpose — a heading
|
||||||
|
# card's internals are not a stable API, and any selector that misses
|
||||||
|
# simply leaves that bit at the theme default rather than breaking.
|
||||||
- type: heading
|
- type: heading
|
||||||
heading: Indoor Climate
|
heading: Indoor Climate
|
||||||
heading_style: title
|
heading_style: title
|
||||||
icon: mdi:home-thermometer-outline
|
icon: mdi:home-thermometer-outline
|
||||||
|
card_mod: &cc_section
|
||||||
|
style: |
|
||||||
|
ha-card {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
box-shadow: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 4px 0 -4px 0;
|
||||||
|
}
|
||||||
|
ha-card .heading,
|
||||||
|
ha-card .content p,
|
||||||
|
ha-card p {
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 0.9375rem;
|
||||||
|
color: var(--cc-text-muted, var(--secondary-text-color));
|
||||||
|
}
|
||||||
|
ha-card ha-icon,
|
||||||
|
ha-card ha-svg-icon {
|
||||||
|
color: var(--cc-accent, var(--primary-color));
|
||||||
|
}
|
||||||
|
|
||||||
- type: grid
|
- type: grid
|
||||||
columns: 3
|
columns: 3
|
||||||
square: false
|
square: false
|
||||||
cards:
|
cards:
|
||||||
|
# First use of the `article` treatment; aliased as *cc_tile below.
|
||||||
- type: tile
|
- type: tile
|
||||||
entity: sensor.living_room_temperature
|
entity: sensor.living_room_temperature
|
||||||
name: Living Room
|
name: Living Room
|
||||||
icon: mdi:sofa
|
icon: mdi:sofa
|
||||||
color: amber
|
color: primary
|
||||||
|
card_mod: &cc_tile
|
||||||
|
style: |
|
||||||
|
ha-card {
|
||||||
|
border-radius: var(--cc-radius-md);
|
||||||
|
border-left: 4px solid var(--cc-accent);
|
||||||
|
box-shadow: var(--cc-shadow-sm);
|
||||||
|
}
|
||||||
- type: tile
|
- type: tile
|
||||||
entity: sensor.office_temperature
|
entity: sensor.office_temperature
|
||||||
name: Office
|
name: Office
|
||||||
icon: mdi:desk
|
icon: mdi:desk
|
||||||
color: teal
|
color: primary
|
||||||
|
card_mod: *cc_tile
|
||||||
- type: tile
|
- type: tile
|
||||||
entity: sensor.bedroom_temperature
|
entity: sensor.bedroom_temperature
|
||||||
name: Master Bedroom
|
name: Master Bedroom
|
||||||
icon: mdi:bed
|
icon: mdi:bed
|
||||||
color: purple
|
color: primary
|
||||||
|
card_mod: *cc_tile
|
||||||
- type: tile
|
- type: tile
|
||||||
entity: sensor.upstairs_temperature
|
entity: sensor.upstairs_temperature
|
||||||
name: Upstairs
|
name: Upstairs
|
||||||
icon: mdi:stairs
|
icon: mdi:stairs
|
||||||
color: indigo
|
color: primary
|
||||||
|
card_mod: *cc_tile
|
||||||
- type: tile
|
- type: tile
|
||||||
entity: sensor.blink_family_room_temperature
|
entity: sensor.blink_family_room_temperature
|
||||||
name: Family Room
|
name: Family Room
|
||||||
icon: mdi:television
|
icon: mdi:television
|
||||||
color: red
|
color: primary
|
||||||
|
card_mod: *cc_tile
|
||||||
- type: tile
|
- type: tile
|
||||||
entity: sensor.blink_kitchen_temperature
|
entity: sensor.blink_kitchen_temperature
|
||||||
name: Kitchen
|
name: Kitchen
|
||||||
icon: mdi:stove
|
icon: mdi:stove
|
||||||
color: deep-orange
|
color: primary
|
||||||
|
card_mod: *cc_tile
|
||||||
|
|
||||||
# ── 3D Printer Status ──
|
# ── 3D Printer Status ──
|
||||||
- type: heading
|
- type: heading
|
||||||
heading: 3D Printers
|
heading: 3D Printers
|
||||||
heading_style: title
|
heading_style: title
|
||||||
icon: mdi:printer-3d-nozzle
|
icon: mdi:printer-3d-nozzle
|
||||||
|
card_mod: *cc_section
|
||||||
|
|
||||||
- type: grid
|
- type: grid
|
||||||
columns: 2
|
columns: 2
|
||||||
square: false
|
square: false
|
||||||
cards:
|
cards:
|
||||||
|
# Online/offline is a genuine success signal, so these keep green and
|
||||||
|
# take the success-coloured left rule.
|
||||||
- type: tile
|
- type: tile
|
||||||
entity: binary_sensor.p1s_01p09c470102673_online
|
entity: binary_sensor.p1s_01p09c470102673_online
|
||||||
name: PrintsCharming
|
name: PrintsCharming
|
||||||
icon: mdi:printer-3d-nozzle
|
icon: mdi:printer-3d-nozzle
|
||||||
show_entity_picture: false
|
show_entity_picture: false
|
||||||
color: green
|
color: green
|
||||||
|
card_mod: &cc_tile_success
|
||||||
|
style: |
|
||||||
|
ha-card {
|
||||||
|
border-radius: var(--cc-radius-md);
|
||||||
|
border-left: 4px solid var(--success-color);
|
||||||
|
box-shadow: var(--cc-shadow-sm);
|
||||||
|
}
|
||||||
- type: tile
|
- type: tile
|
||||||
entity: binary_sensor.a1_03919d540806387_online
|
entity: binary_sensor.a1_03919d540806387_online
|
||||||
name: Ds-Turd-Flinger
|
name: Ds-Turd-Flinger
|
||||||
icon: mdi:printer-3d-nozzle
|
icon: mdi:printer-3d-nozzle
|
||||||
show_entity_picture: false
|
show_entity_picture: false
|
||||||
color: green
|
color: green
|
||||||
|
card_mod: *cc_tile_success
|
||||||
- type: tile
|
- type: tile
|
||||||
entity: binary_sensor.a1mini_0309ca580403653_online
|
entity: binary_sensor.a1mini_0309ca580403653_online
|
||||||
name: Polly-Pocket
|
name: Polly-Pocket
|
||||||
icon: mdi:printer-3d-nozzle
|
icon: mdi:printer-3d-nozzle
|
||||||
show_entity_picture: false
|
show_entity_picture: false
|
||||||
color: green
|
color: green
|
||||||
|
card_mod: *cc_tile_success
|
||||||
- type: tile
|
- type: tile
|
||||||
entity: binary_sensor.constipation_orion_online
|
entity: binary_sensor.constipation_orion_online
|
||||||
name: Constipation-Orion
|
name: Constipation-Orion
|
||||||
icon: mdi:printer-3d-nozzle
|
icon: mdi:printer-3d-nozzle
|
||||||
show_entity_picture: false
|
show_entity_picture: false
|
||||||
color: green
|
color: green
|
||||||
|
card_mod: *cc_tile_success
|
||||||
- type: tile
|
- type: tile
|
||||||
entity: binary_sensor.jordyns_layer_slayer_online
|
entity: binary_sensor.jordyns_layer_slayer_online
|
||||||
name: Jordyn's Layer Slayer
|
name: Jordyn's Layer Slayer
|
||||||
icon: mdi:printer-3d-nozzle
|
icon: mdi:printer-3d-nozzle
|
||||||
show_entity_picture: false
|
show_entity_picture: false
|
||||||
color: green
|
color: green
|
||||||
|
card_mod: *cc_tile_success
|
||||||
- type: tile
|
- type: tile
|
||||||
entity: binary_sensor.centauri_carbon_sdcp_status
|
entity: binary_sensor.centauri_carbon_sdcp_status
|
||||||
name: Centauri Carbon
|
name: Centauri Carbon
|
||||||
icon: mdi:printer-3d-nozzle
|
icon: mdi:printer-3d-nozzle
|
||||||
show_entity_picture: false
|
show_entity_picture: false
|
||||||
color: green
|
color: green
|
||||||
|
card_mod: *cc_tile_success
|
||||||
|
|
||||||
# ── Litter Boxes ──
|
# ── Litter Boxes ──
|
||||||
- type: heading
|
- type: heading
|
||||||
heading: Litter Boxes
|
heading: Litter Boxes
|
||||||
heading_style: title
|
heading_style: title
|
||||||
icon: mdi:cat
|
icon: mdi:cat
|
||||||
|
card_mod: *cc_section
|
||||||
|
|
||||||
- type: grid
|
- type: grid
|
||||||
columns: 2
|
columns: 2
|
||||||
square: false
|
square: false
|
||||||
cards:
|
cards:
|
||||||
|
# These are the "something needs doing" tiles — the equivalent of a
|
||||||
|
# blocked order in the production card, so they take the error rule.
|
||||||
- type: tile
|
- type: tile
|
||||||
entity: binary_sensor.cat_crapper_3000_wastebin_filled
|
entity: binary_sensor.cat_crapper_3000_wastebin_filled
|
||||||
name: Cat Crapper 3000
|
name: Cat Crapper 3000
|
||||||
icon: mdi:delete-empty
|
icon: mdi:delete-empty
|
||||||
show_entity_picture: false
|
show_entity_picture: false
|
||||||
color: red
|
color: red
|
||||||
|
card_mod: &cc_tile_alert
|
||||||
|
style: |
|
||||||
|
ha-card {
|
||||||
|
border-radius: var(--cc-radius-md);
|
||||||
|
border-left: 4px solid var(--error-color);
|
||||||
|
box-shadow: var(--cc-shadow-sm);
|
||||||
|
}
|
||||||
- type: tile
|
- type: tile
|
||||||
entity: binary_sensor.cat_crapper_3000_sand_lack
|
entity: binary_sensor.cat_crapper_3000_sand_lack
|
||||||
name: CC3000 Litter
|
name: CC3000 Litter
|
||||||
icon: mdi:grain
|
icon: mdi:grain
|
||||||
show_entity_picture: false
|
show_entity_picture: false
|
||||||
color: amber
|
color: amber
|
||||||
|
card_mod:
|
||||||
|
style: |
|
||||||
|
ha-card {
|
||||||
|
border-radius: var(--cc-radius-md);
|
||||||
|
border-left: 4px solid var(--warning-color);
|
||||||
|
box-shadow: var(--cc-shadow-sm);
|
||||||
|
}
|
||||||
- type: tile
|
- type: tile
|
||||||
entity: binary_sensor.poop_box_wastebin_filled
|
entity: binary_sensor.poop_box_wastebin_filled
|
||||||
name: Poop Box
|
name: Poop Box
|
||||||
icon: mdi:delete-empty
|
icon: mdi:delete-empty
|
||||||
show_entity_picture: false
|
show_entity_picture: false
|
||||||
color: red
|
color: red
|
||||||
|
card_mod: *cc_tile_alert
|
||||||
- type: tile
|
- type: tile
|
||||||
entity: binary_sensor.triple_threat_wastebin_filled
|
entity: binary_sensor.triple_threat_wastebin_filled
|
||||||
name: Triple Threat
|
name: Triple Threat
|
||||||
icon: mdi:delete-empty
|
icon: mdi:delete-empty
|
||||||
show_entity_picture: false
|
show_entity_picture: false
|
||||||
color: red
|
color: red
|
||||||
|
card_mod: *cc_tile_alert
|
||||||
|
|
||||||
# ── Security ──
|
# ── Security ──
|
||||||
- type: heading
|
- type: heading
|
||||||
@@ -181,6 +281,7 @@ views:
|
|||||||
- type: entity
|
- type: entity
|
||||||
entity: alarm_control_panel.blink_rear
|
entity: alarm_control_panel.blink_rear
|
||||||
name: Rear
|
name: Rear
|
||||||
|
card_mod: *cc_section
|
||||||
|
|
||||||
# ── Recent Activity ──
|
# ── Recent Activity ──
|
||||||
- type: logbook
|
- type: logbook
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
# CubeOps — Cubecraft Production workboard
|
# CubeOps — Cubecraft Production workboard
|
||||||
#
|
#
|
||||||
# Registered as the `cubeops` dashboard in dashboards/dashboards.yaml (mode:
|
# Registered as the `cube-ops` dashboard in dashboards/dashboards.yaml (mode:
|
||||||
# yaml), so this file is the source of truth. Do not edit it through HA's raw
|
# yaml), so this file is the source of truth. Do not edit it through HA's raw
|
||||||
# configuration editor — that writes to storage and cannot come back to git.
|
# configuration editor — that writes to storage and cannot come back to git.
|
||||||
#
|
#
|
||||||
# Kiosk URL: https://home.vault983.com/cubeops
|
# Kiosk URL: https://home.vault983.com/cube-ops
|
||||||
|
# (Renamed from /cubeops — HA rejects a url_path with no hyphen. Any wall
|
||||||
|
# display still pointed at the old URL needs updating.)
|
||||||
#
|
#
|
||||||
# The card polls every 30 seconds, so a display left open stays current and
|
# The card polls every 30 seconds, so a display left open stays current and
|
||||||
# picks back up when a kiosk rotation returns to it.
|
# picks back up when a kiosk rotation returns to it.
|
||||||
@@ -13,12 +15,21 @@
|
|||||||
# and registers its own Lovelace resource, so there is nothing to add under
|
# and registers its own Lovelace resource, so there is nothing to add under
|
||||||
# Settings > Dashboards > Resources.
|
# Settings > Dashboards > Resources.
|
||||||
|
|
||||||
# kiosk-mode plugin (HACS > Frontend). Without it the board still fills the
|
# kiosk-mode plugin (HACS > Frontend). NOT currently installed — there is no
|
||||||
# screen; you just keep HA's header and sidebar.
|
# lovelace-kiosk-mode under www/community — so this block is inert today.
|
||||||
|
# `theme: cubecraft` below already collapses the header via header-height, so
|
||||||
|
# installing the plugin now only buys you hide_sidebar.
|
||||||
kiosk_mode:
|
kiosk_mode:
|
||||||
hide_header: true
|
hide_header: true
|
||||||
hide_sidebar: true
|
hide_sidebar: true
|
||||||
|
|
||||||
|
# The CubeCraft display system. The card reads HA's theme variables for its
|
||||||
|
# surfaces, text and borders (see the `--cc-surface` fallbacks in
|
||||||
|
# cubecraft-production-card.js), so setting this makes the board and the rest
|
||||||
|
# of the dashboards land on exactly the same ramp instead of the card
|
||||||
|
# improvising against HA's defaults.
|
||||||
|
theme: cubecraft
|
||||||
|
|
||||||
views:
|
views:
|
||||||
- title: Production
|
- title: Production
|
||||||
# Panel mode gives the card the whole viewport with no dashboard padding.
|
# Panel mode gives the card the whole viewport with no dashboard padding.
|
||||||
@@ -1,41 +1,58 @@
|
|||||||
|
# Family Hub — wall panel
|
||||||
|
#
|
||||||
|
# Styled with the CubeCraft Creations display system; see
|
||||||
|
# dashboards/views/at-a-glance-dashboard.yaml for the motif notes and
|
||||||
|
# themes/cubecraft.yaml for the tokens. Everything brand-coloured here comes
|
||||||
|
# through --cc-* variables rather than a literal hex.
|
||||||
title: Family Hub
|
title: Family Hub
|
||||||
theme: dakboard-dark
|
theme: cubecraft
|
||||||
views:
|
views:
|
||||||
- title: Family Hub
|
- title: Family Hub
|
||||||
path: family-hub
|
path: family-hub
|
||||||
icon: mdi:home-heart
|
icon: mdi:home-heart
|
||||||
theme: dakboard-dark
|
theme: cubecraft
|
||||||
type: masonry
|
type: masonry
|
||||||
cards:
|
cards:
|
||||||
# ── Date & Greeting Header ──
|
# ── Brand greeting bar ──
|
||||||
|
# The production card's `.title` treatment, carrying the date and a
|
||||||
|
# time-of-day greeting instead of a board name.
|
||||||
- type: markdown
|
- type: markdown
|
||||||
content: |
|
content: |
|
||||||
# {{ now().strftime("%A, %B %d") }}
|
# {{ now().strftime("%A, %B %d") }}
|
||||||
{% set h = now().hour %}
|
{% set h = now().hour %}
|
||||||
{% if h < 12 %}Good morning{% elif h < 17 %}Good afternoon{% else %}Good evening{% endif %}, family!
|
## {% if h < 12 %}Good morning{% elif h < 17 %}Good afternoon{% else %}Good evening{% endif %}, family!
|
||||||
|
entity_id:
|
||||||
|
- sensor.time
|
||||||
card_mod:
|
card_mod:
|
||||||
style: |
|
style: |
|
||||||
ha-card {
|
ha-card {
|
||||||
|
background: var(--cc-gradient);
|
||||||
|
color: #fff;
|
||||||
|
border: none;
|
||||||
|
border-radius: var(--cc-radius-brand);
|
||||||
|
box-shadow: var(--cc-shadow-brand);
|
||||||
|
padding: 6px 12px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
background: none;
|
|
||||||
box-shadow: none;
|
|
||||||
padding: 0 0 8px 0;
|
|
||||||
}
|
}
|
||||||
ha-card h1 {
|
ha-card h1 {
|
||||||
font-size: 1.4em;
|
|
||||||
margin: 0 0 4px 0;
|
|
||||||
font-weight: 300;
|
|
||||||
color: var(--secondary-text-color);
|
|
||||||
}
|
|
||||||
ha-card p {
|
|
||||||
font-size: 1.1em;
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-weight: 400;
|
font-size: 1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
opacity: 0.85;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
ha-card h2 {
|
||||||
|
margin: 2px 0 0 0;
|
||||||
|
font-size: 1.75rem;
|
||||||
|
font-weight: 800;
|
||||||
|
letter-spacing: -0.01em;
|
||||||
|
color: #fff;
|
||||||
}
|
}
|
||||||
entity_id:
|
|
||||||
- sensor.time
|
|
||||||
|
|
||||||
# ── Clock ──
|
# ── Clock ──
|
||||||
|
# Left on the sunken surface rather than a card, so the gradient bar above
|
||||||
|
# stays the only heavyweight element in the column.
|
||||||
- type: clock
|
- type: clock
|
||||||
clock_size: large
|
clock_size: large
|
||||||
clock_style: analog
|
clock_style: analog
|
||||||
@@ -48,6 +65,7 @@ views:
|
|||||||
style: |
|
style: |
|
||||||
ha-card {
|
ha-card {
|
||||||
background: none;
|
background: none;
|
||||||
|
border: none;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
@@ -62,20 +80,18 @@ views:
|
|||||||
round_temperature: false
|
round_temperature: false
|
||||||
|
|
||||||
# ── Family Calendar ──
|
# ── Family Calendar ──
|
||||||
- type: calendar
|
# Daylight Calendar Card (HACS: daylight-calendar-card). Agenda mirrors
|
||||||
|
# the old stock listWeek “upcoming” feel on a wall panel.
|
||||||
|
- type: custom:daylight-calendar-card
|
||||||
title: Upcoming Events
|
title: Upcoming Events
|
||||||
initial_view: listWeek
|
default_view: agenda
|
||||||
|
color_scheme: auto
|
||||||
|
preference_storage_key: family_hub_calendar
|
||||||
entities:
|
entities:
|
||||||
- calendar.family_events
|
- calendar.family_events
|
||||||
- calendar.birthdays
|
- calendar.birthdays
|
||||||
- calendar.holidays_in_united_states
|
- calendar.holidays_in_united_states
|
||||||
- calendar.gmail_calendar
|
- calendar.gmail_calendar
|
||||||
card_mod:
|
|
||||||
style: |
|
|
||||||
ha-card {
|
|
||||||
--calendar-day-color: var(--primary-text-color);
|
|
||||||
--calendar-day-weekday-color: var(--secondary-text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
# ── Quick Glance ──
|
# ── Quick Glance ──
|
||||||
- type: heading
|
- type: heading
|
||||||
@@ -92,64 +108,104 @@ views:
|
|||||||
- type: entity
|
- type: entity
|
||||||
entity: sensor.office_temperature
|
entity: sensor.office_temperature
|
||||||
name: Office
|
name: Office
|
||||||
|
card_mod: &cc_section
|
||||||
|
style: |
|
||||||
|
ha-card {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
box-shadow: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 4px 0 -4px 0;
|
||||||
|
}
|
||||||
|
ha-card .heading,
|
||||||
|
ha-card .content p,
|
||||||
|
ha-card p {
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 0.9375rem;
|
||||||
|
color: var(--cc-text-muted, var(--secondary-text-color));
|
||||||
|
}
|
||||||
|
ha-card ha-icon,
|
||||||
|
ha-card ha-svg-icon {
|
||||||
|
color: var(--cc-accent, var(--primary-color));
|
||||||
|
}
|
||||||
|
|
||||||
- type: grid
|
- type: grid
|
||||||
columns: 3
|
columns: 3
|
||||||
square: false
|
square: false
|
||||||
cards:
|
cards:
|
||||||
# Outdoor temp
|
# Temperatures are informational, so they all take the brand rule
|
||||||
|
# rather than a colour each — see the colour note in at-a-glance.
|
||||||
- type: tile
|
- type: tile
|
||||||
entity: sensor.openweathermap_temperature
|
entity: sensor.openweathermap_temperature
|
||||||
name: Outside
|
name: Outside
|
||||||
icon: mdi:thermometer
|
icon: mdi:thermometer
|
||||||
show_entity_picture: false
|
show_entity_picture: false
|
||||||
color: blue
|
color: primary
|
||||||
# Living Room
|
card_mod: &cc_tile
|
||||||
|
style: |
|
||||||
|
ha-card {
|
||||||
|
border-radius: var(--cc-radius-md);
|
||||||
|
border-left: 4px solid var(--cc-accent);
|
||||||
|
box-shadow: var(--cc-shadow-sm);
|
||||||
|
}
|
||||||
- type: tile
|
- type: tile
|
||||||
entity: sensor.living_room_temperature
|
entity: sensor.living_room_temperature
|
||||||
name: Living Room
|
name: Living Room
|
||||||
icon: mdi:sofa
|
icon: mdi:sofa
|
||||||
show_entity_picture: false
|
show_entity_picture: false
|
||||||
color: amber
|
color: primary
|
||||||
# Office
|
card_mod: *cc_tile
|
||||||
- type: tile
|
- type: tile
|
||||||
entity: sensor.office_temperature
|
entity: sensor.office_temperature
|
||||||
name: Office
|
name: Office
|
||||||
icon: mdi:desk
|
icon: mdi:desk
|
||||||
show_entity_picture: false
|
show_entity_picture: false
|
||||||
color: teal
|
color: primary
|
||||||
# Master Bedroom
|
card_mod: *cc_tile
|
||||||
- type: tile
|
- type: tile
|
||||||
entity: sensor.bedroom_temperature
|
entity: sensor.bedroom_temperature
|
||||||
name: Master Bedroom
|
name: Master Bedroom
|
||||||
icon: mdi:bed
|
icon: mdi:bed
|
||||||
show_entity_picture: false
|
show_entity_picture: false
|
||||||
color: purple
|
color: primary
|
||||||
# Upstairs
|
card_mod: *cc_tile
|
||||||
- type: tile
|
- type: tile
|
||||||
entity: sensor.upstairs_temperature
|
entity: sensor.upstairs_temperature
|
||||||
name: Upstairs
|
name: Upstairs
|
||||||
icon: mdi:stairs
|
icon: mdi:stairs
|
||||||
show_entity_picture: false
|
show_entity_picture: false
|
||||||
color: indigo
|
color: primary
|
||||||
# Family Room (Blink)
|
card_mod: *cc_tile
|
||||||
- type: tile
|
- type: tile
|
||||||
entity: sensor.blink_family_room_temperature
|
entity: sensor.blink_family_room_temperature
|
||||||
name: Family Room
|
name: Family Room
|
||||||
icon: mdi:television
|
icon: mdi:television
|
||||||
show_entity_picture: false
|
show_entity_picture: false
|
||||||
color: red
|
color: primary
|
||||||
|
card_mod: *cc_tile
|
||||||
|
|
||||||
# ── Shopping List ──
|
# ── Shopping List ──
|
||||||
|
- type: heading
|
||||||
|
heading: Shopping List
|
||||||
|
heading_style: title
|
||||||
|
icon: mdi:cart-outline
|
||||||
|
card_mod: *cc_section
|
||||||
|
|
||||||
- type: todo-list
|
- type: todo-list
|
||||||
entity: todo.shopping_list
|
entity: todo.shopping_list
|
||||||
title: Shopping List
|
|
||||||
hide_completed: true
|
hide_completed: true
|
||||||
display_order: none
|
display_order: none
|
||||||
|
|
||||||
# ── Chore Tracker Quick View ──
|
# ── Chore Tracker Quick View ──
|
||||||
|
- type: heading
|
||||||
|
heading: Chores Today
|
||||||
|
heading_style: title
|
||||||
|
icon: mdi:check-circle-outline
|
||||||
|
card_mod: *cc_section
|
||||||
|
|
||||||
- type: entities
|
- type: entities
|
||||||
title: Chores Today
|
|
||||||
show_header_toggle: false
|
show_header_toggle: false
|
||||||
entities:
|
entities:
|
||||||
- entity: binary_sensor.cat_medication_tracker_all_cats_medicated
|
- entity: binary_sensor.cat_medication_tracker_all_cats_medicated
|
||||||
@@ -171,3 +227,4 @@ views:
|
|||||||
- type: entity
|
- type: entity
|
||||||
entity: binary_sensor.upstairs_occupancy
|
entity: binary_sensor.upstairs_occupancy
|
||||||
name: Upstairs
|
name: Upstairs
|
||||||
|
card_mod: *cc_section
|
||||||
|
|||||||
@@ -0,0 +1,177 @@
|
|||||||
|
# Lunch Menus — school cafeteria calendars (Mon–Fri each)
|
||||||
|
#
|
||||||
|
# Panel layout so the title spans the full width and the three school cards
|
||||||
|
# sit in one row. Menus come from packages/lunch_menus.yaml (stock calendar
|
||||||
|
# cards cannot limit to a school-week window).
|
||||||
|
title: Lunch Menus
|
||||||
|
theme: cubecraft
|
||||||
|
views:
|
||||||
|
- title: Lunch Menus
|
||||||
|
path: lunch-menus
|
||||||
|
icon: mdi:food-apple
|
||||||
|
theme: cubecraft
|
||||||
|
type: panel
|
||||||
|
cards:
|
||||||
|
- type: vertical-stack
|
||||||
|
cards:
|
||||||
|
- type: markdown
|
||||||
|
content: |
|
||||||
|
{% set wd = now().weekday() %}
|
||||||
|
{% if wd >= 5 %}
|
||||||
|
{% set monday = today_at() + timedelta(days=(7 - wd)) %}
|
||||||
|
{% else %}
|
||||||
|
{% set monday = today_at() - timedelta(days=wd) %}
|
||||||
|
{% endif %}
|
||||||
|
{% set friday = monday + timedelta(days=4) %}
|
||||||
|
# School Lunch Menus
|
||||||
|
## {{ monday.strftime("%b %-d") }} – {{ friday.strftime("%b %-d, %Y") }}
|
||||||
|
card_mod:
|
||||||
|
style: |
|
||||||
|
ha-card {
|
||||||
|
background: var(--cc-gradient);
|
||||||
|
color: #fff;
|
||||||
|
border: none;
|
||||||
|
border-radius: var(--cc-radius-brand);
|
||||||
|
box-shadow: var(--cc-shadow-brand);
|
||||||
|
padding: 6px 12px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
ha-card h1 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
opacity: 0.85;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
ha-card h2 {
|
||||||
|
margin: 2px 0 0 0;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: 800;
|
||||||
|
letter-spacing: -0.01em;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
- type: grid
|
||||||
|
columns: 3
|
||||||
|
square: false
|
||||||
|
cards:
|
||||||
|
- type: markdown
|
||||||
|
title: BHS Lunch Menu
|
||||||
|
entity_id: sensor.bhs_lunch_menu_week
|
||||||
|
content: |
|
||||||
|
{% set events = state_attr('sensor.bhs_lunch_menu_week', 'events') or [] %}
|
||||||
|
{% if events is string %}{% set events = [] %}{% endif %}
|
||||||
|
{% set wd = now().weekday() %}
|
||||||
|
{% if wd >= 5 %}
|
||||||
|
{% set monday = today_at() + timedelta(days=(7 - wd)) %}
|
||||||
|
{% else %}
|
||||||
|
{% set monday = today_at() - timedelta(days=wd) %}
|
||||||
|
{% endif %}
|
||||||
|
{% for offset in range(5) %}
|
||||||
|
{% set d = (monday + timedelta(days=offset)).date() %}
|
||||||
|
{% set d_str = d.isoformat() %}
|
||||||
|
{% set ns = namespace(found=false) %}
|
||||||
|
### {{ d.strftime("%A") }}
|
||||||
|
{{ d.strftime("%b %-d") }}
|
||||||
|
{% for e in events if e.start is defined and e.start[:10] == d_str %}
|
||||||
|
{% set ns.found = true %}
|
||||||
|
- {{ e.summary }}
|
||||||
|
{% endfor %}
|
||||||
|
{% if not ns.found %}
|
||||||
|
_No menu listed_
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
card_mod: &cc_menu
|
||||||
|
style: |
|
||||||
|
ha-card .card-header {
|
||||||
|
color: var(--cc-text, var(--primary-text-color));
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
ha-markdown {
|
||||||
|
padding-top: 0 !important;
|
||||||
|
}
|
||||||
|
ha-markdown h3 {
|
||||||
|
margin: 0.85rem 0 0.15rem 0;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--cc-accent, var(--primary-color));
|
||||||
|
}
|
||||||
|
ha-markdown h3:first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
ha-markdown p {
|
||||||
|
margin: 0 0 0.35rem 0;
|
||||||
|
color: var(--cc-text-muted, var(--secondary-text-color));
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
ha-markdown ul {
|
||||||
|
margin: 0 0 0.5rem 0;
|
||||||
|
padding-left: 1.1rem;
|
||||||
|
}
|
||||||
|
ha-markdown li {
|
||||||
|
margin: 0.15rem 0;
|
||||||
|
color: var(--cc-text, var(--primary-text-color));
|
||||||
|
}
|
||||||
|
ha-markdown em {
|
||||||
|
color: var(--cc-text-muted, var(--secondary-text-color));
|
||||||
|
}
|
||||||
|
|
||||||
|
- type: markdown
|
||||||
|
title: BIS School Lunches
|
||||||
|
entity_id: sensor.bis_lunch_menu_week
|
||||||
|
content: |
|
||||||
|
{% set events = state_attr('sensor.bis_lunch_menu_week', 'events') or [] %}
|
||||||
|
{% if events is string %}{% set events = [] %}{% endif %}
|
||||||
|
{% set wd = now().weekday() %}
|
||||||
|
{% if wd >= 5 %}
|
||||||
|
{% set monday = today_at() + timedelta(days=(7 - wd)) %}
|
||||||
|
{% else %}
|
||||||
|
{% set monday = today_at() - timedelta(days=wd) %}
|
||||||
|
{% endif %}
|
||||||
|
{% for offset in range(5) %}
|
||||||
|
{% set d = (monday + timedelta(days=offset)).date() %}
|
||||||
|
{% set d_str = d.isoformat() %}
|
||||||
|
{% set ns = namespace(found=false) %}
|
||||||
|
### {{ d.strftime("%A") }}
|
||||||
|
{{ d.strftime("%b %-d") }}
|
||||||
|
{% for e in events if e.start is defined and e.start[:10] == d_str %}
|
||||||
|
{% set ns.found = true %}
|
||||||
|
- {{ e.summary }}
|
||||||
|
{% endfor %}
|
||||||
|
{% if not ns.found %}
|
||||||
|
_No menu listed_
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
card_mod: *cc_menu
|
||||||
|
|
||||||
|
- type: markdown
|
||||||
|
title: HMS Lunch Menu
|
||||||
|
entity_id: sensor.hms_lunch_menu_week
|
||||||
|
content: |
|
||||||
|
{% set events = state_attr('sensor.hms_lunch_menu_week', 'events') or [] %}
|
||||||
|
{% if events is string %}{% set events = [] %}{% endif %}
|
||||||
|
{% set wd = now().weekday() %}
|
||||||
|
{% if wd >= 5 %}
|
||||||
|
{% set monday = today_at() + timedelta(days=(7 - wd)) %}
|
||||||
|
{% else %}
|
||||||
|
{% set monday = today_at() - timedelta(days=wd) %}
|
||||||
|
{% endif %}
|
||||||
|
{% for offset in range(5) %}
|
||||||
|
{% set d = (monday + timedelta(days=offset)).date() %}
|
||||||
|
{% set d_str = d.isoformat() %}
|
||||||
|
{% set ns = namespace(found=false) %}
|
||||||
|
### {{ d.strftime("%A") }}
|
||||||
|
{{ d.strftime("%b %-d") }}
|
||||||
|
{% for e in events if e.start is defined and e.start[:10] == d_str %}
|
||||||
|
{% set ns.found = true %}
|
||||||
|
- {{ e.summary }}
|
||||||
|
{% endfor %}
|
||||||
|
{% if not ns.found %}
|
||||||
|
_No menu listed_
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
card_mod: *cc_menu
|
||||||
@@ -1,23 +1,111 @@
|
|||||||
|
# Voice Alarms — satellite control panel
|
||||||
|
#
|
||||||
|
# Styled with the CubeCraft Creations display system; see
|
||||||
|
# dashboards/views/at-a-glance-dashboard.yaml for the motif notes and
|
||||||
|
# themes/cubecraft.yaml for the tokens.
|
||||||
|
#
|
||||||
|
# This one is a control panel rather than a glanceable board, so the per-tile
|
||||||
|
# left rule is dropped — the entity rows already carry their own structure and
|
||||||
|
# a rule on every card would just add noise. It keeps the gradient title bar
|
||||||
|
# and the section labels.
|
||||||
|
#
|
||||||
|
# Note that the theme collapses the HA toolbar (header-height: 0). This
|
||||||
|
# dashboard is reached by URL rather than the sidebar (show_in_sidebar: false
|
||||||
|
# in dashboards/voice-alarms.yaml), so navigate away via the sidebar.
|
||||||
title: Voice Alarms
|
title: Voice Alarms
|
||||||
|
theme: cubecraft
|
||||||
views:
|
views:
|
||||||
- title: Voice Alarms
|
- title: Voice Alarms
|
||||||
path: voice-alarms
|
path: voice-alarms
|
||||||
icon: mdi:alarm-panel
|
icon: mdi:alarm-panel
|
||||||
|
theme: cubecraft
|
||||||
type: panel
|
type: panel
|
||||||
cards:
|
cards:
|
||||||
- type: vertical-stack
|
- type: vertical-stack
|
||||||
cards:
|
cards:
|
||||||
|
# ── Brand title bar ──
|
||||||
- type: markdown
|
- type: markdown
|
||||||
content: |
|
content: |
|
||||||
# Voice Alarms
|
# Voice Alarms
|
||||||
|
## Jarvis & ReSpeaker satellites
|
||||||
|
card_mod:
|
||||||
|
style: |
|
||||||
|
ha-card {
|
||||||
|
background: var(--cc-gradient);
|
||||||
|
color: #fff;
|
||||||
|
border: none;
|
||||||
|
border-radius: var(--cc-radius-brand);
|
||||||
|
box-shadow: var(--cc-shadow-brand);
|
||||||
|
padding: 6px 12px;
|
||||||
|
}
|
||||||
|
ha-card h1 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1.75rem;
|
||||||
|
font-weight: 800;
|
||||||
|
letter-spacing: -0.01em;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
ha-card h2 {
|
||||||
|
margin: 2px 0 0 0;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
opacity: 0.85;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
These alarms are managed by Home Assistant and announced on the selected
|
- type: markdown
|
||||||
Jarvis and ReSpeaker satellites.
|
content: >
|
||||||
|
These alarms are managed by Home Assistant and announced on the
|
||||||
|
selected Jarvis and ReSpeaker satellites.
|
||||||
|
card_mod:
|
||||||
|
style: |
|
||||||
|
ha-card {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
ha-card p {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 0.9375rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: var(--cc-text-muted, var(--secondary-text-color));
|
||||||
|
}
|
||||||
|
|
||||||
|
- type: heading
|
||||||
|
heading: Satellites
|
||||||
|
heading_style: title
|
||||||
|
icon: mdi:speaker-message
|
||||||
|
card_mod:
|
||||||
|
style: |
|
||||||
|
ha-card {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
box-shadow: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 4px 0 -4px 0;
|
||||||
|
}
|
||||||
|
ha-card .heading,
|
||||||
|
ha-card .content p,
|
||||||
|
ha-card p {
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 0.9375rem;
|
||||||
|
color: var(--cc-text-muted, var(--secondary-text-color));
|
||||||
|
}
|
||||||
|
ha-card ha-icon,
|
||||||
|
ha-card ha-svg-icon {
|
||||||
|
color: var(--cc-accent, var(--primary-color));
|
||||||
|
}
|
||||||
|
|
||||||
- type: grid
|
- type: grid
|
||||||
columns: 2
|
columns: 2
|
||||||
square: false
|
square: false
|
||||||
cards:
|
cards:
|
||||||
|
# Card titles take the production card's column-header treatment:
|
||||||
|
# uppercase, 700, .05em tracking, muted. First use defines the
|
||||||
|
# anchor the other three alias.
|
||||||
- type: entities
|
- type: entities
|
||||||
title: Office Jarvis
|
title: Office Jarvis
|
||||||
show_header_toggle: false
|
show_header_toggle: false
|
||||||
@@ -30,6 +118,21 @@ views:
|
|||||||
name: Alarm time
|
name: Alarm time
|
||||||
- entity: script.test_voice_alarm_office_jarvis
|
- entity: script.test_voice_alarm_office_jarvis
|
||||||
name: Test alarm
|
name: Test alarm
|
||||||
|
card_mod: &cc_panel
|
||||||
|
style: |
|
||||||
|
ha-card {
|
||||||
|
border-radius: var(--cc-radius-brand);
|
||||||
|
box-shadow: var(--cc-shadow-md);
|
||||||
|
}
|
||||||
|
ha-card .card-header,
|
||||||
|
ha-card h1.card-header {
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 0.9375rem;
|
||||||
|
color: var(--cc-text-muted, var(--secondary-text-color));
|
||||||
|
padding-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
- type: entities
|
- type: entities
|
||||||
title: ReSpeaker Family Room
|
title: ReSpeaker Family Room
|
||||||
@@ -43,6 +146,7 @@ views:
|
|||||||
name: Alarm time
|
name: Alarm time
|
||||||
- entity: script.test_voice_alarm_respeaker_family_room
|
- entity: script.test_voice_alarm_respeaker_family_room
|
||||||
name: Test alarm
|
name: Test alarm
|
||||||
|
card_mod: *cc_panel
|
||||||
|
|
||||||
- type: entities
|
- type: entities
|
||||||
title: ReSpeaker Living Room
|
title: ReSpeaker Living Room
|
||||||
@@ -56,6 +160,7 @@ views:
|
|||||||
name: Alarm time
|
name: Alarm time
|
||||||
- entity: script.test_voice_alarm_respeaker_living_room
|
- entity: script.test_voice_alarm_respeaker_living_room
|
||||||
name: Test alarm
|
name: Test alarm
|
||||||
|
card_mod: *cc_panel
|
||||||
|
|
||||||
- type: entities
|
- type: entities
|
||||||
title: ReSpeaker Master Bedroom
|
title: ReSpeaker Master Bedroom
|
||||||
@@ -69,3 +174,4 @@ views:
|
|||||||
name: Alarm time
|
name: Alarm time
|
||||||
- entity: script.test_voice_alarm_respeaker_master_bedroom
|
- entity: script.test_voice_alarm_respeaker_master_bedroom
|
||||||
name: Test alarm
|
name: Test alarm
|
||||||
|
card_mod: *cc_panel
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
################################################################################
|
||||||
|
# lunch_menus.yaml
|
||||||
|
#
|
||||||
|
# Pulls Mon–Fri of the current school week from each lunch Google Calendar into
|
||||||
|
# template sensors. On Sat/Sun, advances to next week's Monday. The Lunch Menus
|
||||||
|
# dashboard renders those attributes — the stock calendar card has no school-
|
||||||
|
# week view.
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
template:
|
||||||
|
- trigger:
|
||||||
|
- platform: time_pattern
|
||||||
|
minutes: "/15"
|
||||||
|
- platform: homeassistant
|
||||||
|
event: start
|
||||||
|
- platform: event
|
||||||
|
event_type: event_template_reloaded
|
||||||
|
action:
|
||||||
|
- variables:
|
||||||
|
# weekday(): Mon=0 … Sun=6. Weekend → next Monday.
|
||||||
|
school_monday: >-
|
||||||
|
{% set wd = now().weekday() %}
|
||||||
|
{% if wd >= 5 %}
|
||||||
|
{{ (today_at() + timedelta(days=(7 - wd))).isoformat() }}
|
||||||
|
{% else %}
|
||||||
|
{{ (today_at() - timedelta(days=wd)).isoformat() }}
|
||||||
|
{% endif %}
|
||||||
|
- action: calendar.get_events
|
||||||
|
target:
|
||||||
|
entity_id:
|
||||||
|
- calendar.bhs_lunch_menu
|
||||||
|
- calendar.bis_school_lunches
|
||||||
|
- calendar.hms_lunch_menu
|
||||||
|
data:
|
||||||
|
start_date_time: "{{ school_monday }}"
|
||||||
|
duration:
|
||||||
|
days: 5
|
||||||
|
response_variable: agenda
|
||||||
|
sensor:
|
||||||
|
- name: "BHS Lunch Menu Week"
|
||||||
|
unique_id: bhs_lunch_menu_week
|
||||||
|
icon: mdi:food-apple
|
||||||
|
state: "{{ agenda['calendar.bhs_lunch_menu'].events | count }}"
|
||||||
|
attributes:
|
||||||
|
events: "{{ agenda['calendar.bhs_lunch_menu'].events }}"
|
||||||
|
week_start: "{{ school_monday }}"
|
||||||
|
|
||||||
|
- name: "BIS Lunch Menu Week"
|
||||||
|
unique_id: bis_lunch_menu_week
|
||||||
|
icon: mdi:food-apple
|
||||||
|
state: "{{ agenda['calendar.bis_school_lunches'].events | count }}"
|
||||||
|
attributes:
|
||||||
|
events: "{{ agenda['calendar.bis_school_lunches'].events }}"
|
||||||
|
week_start: "{{ school_monday }}"
|
||||||
|
|
||||||
|
- name: "HMS Lunch Menu Week"
|
||||||
|
unique_id: hms_lunch_menu_week
|
||||||
|
icon: mdi:food-apple
|
||||||
|
state: "{{ agenda['calendar.hms_lunch_menu'].events | count }}"
|
||||||
|
attributes:
|
||||||
|
events: "{{ agenda['calendar.hms_lunch_menu'].events }}"
|
||||||
|
week_start: "{{ school_monday }}"
|
||||||
@@ -55,6 +55,6 @@ The finish automation condition checks `| length == 36` on the stored ID.
|
|||||||
## HA Setup
|
## HA Setup
|
||||||
|
|
||||||
- HAOS on x86 server
|
- HAOS on x86 server
|
||||||
- Gitea repo at code.cubecraftcreations.com (username: overseer)
|
- Gitea repo at code.cubecraftlabs.com (username: overseer)
|
||||||
- IoT VLAN: 192.168.69.x, Main: 192.168.1.x
|
- IoT VLAN: 192.168.69.x, Main: 192.168.1.x
|
||||||
- ~150 devices, UniFi networking
|
- ~150 devices, UniFi networking
|
||||||
|
|||||||
@@ -0,0 +1,305 @@
|
|||||||
|
# CubeCraft Creations display system — Home Assistant theme
|
||||||
|
#
|
||||||
|
# Source of truth for the tokens below is the production card's stylesheet:
|
||||||
|
# custom_components/cubecraft_production/www/cubecraft-production-card.js
|
||||||
|
# Keep the two in sync. The card reads HA theme variables for its surfaces, so
|
||||||
|
# once this theme is active the CubeOps board and the rest of a dashboard end up
|
||||||
|
# on the same surfaces, borders and text colours automatically.
|
||||||
|
#
|
||||||
|
# The theme carries `modes:`, so it follows HA's light/dark setting. The brand
|
||||||
|
# gradient, type, radii and semantic colours are identical in both modes; only
|
||||||
|
# the surface and text ramps flip.
|
||||||
|
#
|
||||||
|
# TUNED FOR WALL PANELS: `header-height: 0px` near the bottom collapses the HA
|
||||||
|
# toolbar, matching what dakboard-dark did on these dashboards. If you ever want
|
||||||
|
# CubeCraft on a phone or desktop where you still need the toolbar, copy this
|
||||||
|
# file to themes/cubecraft-desktop.yaml, rename the top-level key, and delete
|
||||||
|
# that one line. (HA themes cannot inherit from each other, and this repo's YAML
|
||||||
|
# is loaded by HA's own loader, so a `<<:` merge anchor is not worth the risk of
|
||||||
|
# taking the whole themes include down.)
|
||||||
|
#
|
||||||
|
# Hiding the sidebar as well needs the kiosk-mode frontend plugin (HACS), which
|
||||||
|
# is not currently installed — see dashboards/views/cube-ops-dashboard.yaml.
|
||||||
|
|
||||||
|
cubecraft:
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
# Brand tokens — mirrors the `:host` block in cubecraft-production-card.js.
|
||||||
|
# Exposed as --cc-* so dashboard card_mod blocks can reference them by name
|
||||||
|
# instead of hard-coding hexes in a dozen places.
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
cc-blue: "#3B3AB8"
|
||||||
|
cc-purple: "#A035CC"
|
||||||
|
cc-gradient: "linear-gradient(135deg, #3B3AB8 0%, #A035CC 100%)"
|
||||||
|
|
||||||
|
cc-primary-50: "#EBEBF8"
|
||||||
|
cc-primary-500: "#3B3AB8"
|
||||||
|
cc-primary-700: "#201F7A"
|
||||||
|
|
||||||
|
cc-neutral-0: "#FFFFFF"
|
||||||
|
cc-neutral-50: "#FAFAFA"
|
||||||
|
cc-neutral-100: "#F4F4F6"
|
||||||
|
cc-neutral-150: "#EDEDF1"
|
||||||
|
cc-neutral-200: "#E4E4EA"
|
||||||
|
cc-neutral-400: "#9898A8"
|
||||||
|
cc-neutral-600: "#52525E"
|
||||||
|
cc-neutral-900: "#18181D"
|
||||||
|
|
||||||
|
cc-success: "#16A34A"
|
||||||
|
cc-warning: "#D97706"
|
||||||
|
cc-warning-bg: "#FEF3C7"
|
||||||
|
cc-error: "#DC2626"
|
||||||
|
cc-error-bg: "#FEE2E2"
|
||||||
|
|
||||||
|
# 4px spacing scale
|
||||||
|
cc-space-1: "4px"
|
||||||
|
cc-space-2: "8px"
|
||||||
|
cc-space-3: "12px"
|
||||||
|
cc-space-4: "16px"
|
||||||
|
cc-space-5: "20px"
|
||||||
|
cc-space-6: "24px"
|
||||||
|
cc-space-7: "28px"
|
||||||
|
|
||||||
|
cc-radius-sm: "6px"
|
||||||
|
cc-radius-md: "8px"
|
||||||
|
cc-radius-lg: "12px"
|
||||||
|
cc-radius-xl: "16px"
|
||||||
|
cc-radius-brand: "20px"
|
||||||
|
cc-radius-full: "9999px"
|
||||||
|
|
||||||
|
cc-shadow-sm: "0 2px 6px 0 rgba(0,0,0,.08)"
|
||||||
|
cc-shadow-md: "0 4px 12px 0 rgba(0,0,0,.10)"
|
||||||
|
cc-shadow-brand: "0 4px 20px 0 rgba(59,58,184,.25)"
|
||||||
|
|
||||||
|
cc-ease: "cubic-bezier(0,0,.2,1)"
|
||||||
|
cc-dur: "200ms"
|
||||||
|
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
# Typography — Nunito 400..800.
|
||||||
|
# The @font-face has to be declared in the document, not a shadow root; that
|
||||||
|
# is what www/cubecraft/cubecraft-brand-font.js does (wired up via
|
||||||
|
# frontend.extra_module_url in configuration.yaml). Without it everything
|
||||||
|
# below falls back to system-ui and the rest of the theme still works.
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
cc-font: "'Nunito', 'Nunito Fallback', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif"
|
||||||
|
primary-font-family: "var(--cc-font)"
|
||||||
|
ha-font-family-body: "var(--cc-font)"
|
||||||
|
ha-font-family-heading: "var(--cc-font)"
|
||||||
|
mdc-typography-font-family: "var(--cc-font)"
|
||||||
|
paper-font-common-base_-_font-family: "var(--cc-font)"
|
||||||
|
paper-font-common-nowrap_-_font-family: "var(--cc-font)"
|
||||||
|
paper-font-body1_-_font-family: "var(--cc-font)"
|
||||||
|
paper-font-subhead_-_font-family: "var(--cc-font)"
|
||||||
|
paper-font-headline_-_font-family: "var(--cc-font)"
|
||||||
|
paper-font-title_-_font-family: "var(--cc-font)"
|
||||||
|
paper-font-caption_-_font-family: "var(--cc-font)"
|
||||||
|
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
# Shape — brand radius on cards, pills on controls.
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
ha-card-border-radius: "var(--cc-radius-brand)"
|
||||||
|
ha-card-border-width: "0"
|
||||||
|
ha-dialog-border-radius: "var(--cc-radius-brand)"
|
||||||
|
ha-badge-border-radius: "var(--cc-radius-full)"
|
||||||
|
mdc-shape-small: "var(--cc-radius-full)"
|
||||||
|
mdc-shape-medium: "var(--cc-radius-lg)"
|
||||||
|
mdc-shape-large: "var(--cc-radius-xl)"
|
||||||
|
button-border-radius: "var(--cc-radius-full)"
|
||||||
|
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
# Colour — brand ramp. Surfaces/text live in the mode blocks below.
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
success-color: "var(--cc-success)"
|
||||||
|
warning-color: "var(--cc-warning)"
|
||||||
|
error-color: "var(--cc-error)"
|
||||||
|
|
||||||
|
label-badge-green: "var(--cc-success)"
|
||||||
|
label-badge-yellow: "var(--cc-warning)"
|
||||||
|
label-badge-red: "var(--cc-error)"
|
||||||
|
|
||||||
|
# Text sitting on top of primary-color (buttons, selected states). White
|
||||||
|
# clears AA against both ends of the gradient (8.5:1 on the blue, 5.4:1 on
|
||||||
|
# the purple), so it is safe wherever the gradient is used.
|
||||||
|
text-primary-color: "#FFFFFF"
|
||||||
|
app-header-text-color: "#FFFFFF"
|
||||||
|
mdc-theme-on-primary: "#FFFFFF"
|
||||||
|
|
||||||
|
# Wall-panel chrome: collapse the HA toolbar. Delete this line for a variant
|
||||||
|
# you navigate by hand (see the header comment).
|
||||||
|
header-height: "0px"
|
||||||
|
|
||||||
|
modes:
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════
|
||||||
|
# Light — the design system as authored: white surfaces, neutral sunken
|
||||||
|
# backgrounds, near-black text.
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════
|
||||||
|
light:
|
||||||
|
cc-surface: "var(--cc-neutral-0)"
|
||||||
|
cc-surface-sunken: "var(--cc-neutral-100)"
|
||||||
|
cc-text: "var(--cc-neutral-900)"
|
||||||
|
cc-text-muted: "var(--cc-neutral-600)"
|
||||||
|
cc-border: "var(--cc-neutral-150)"
|
||||||
|
cc-accent: "var(--cc-primary-500)"
|
||||||
|
cc-accent-soft: "var(--cc-primary-50)"
|
||||||
|
|
||||||
|
primary-color: "#3B3AB8"
|
||||||
|
accent-color: "#A035CC"
|
||||||
|
dark-primary-color: "#201F7A"
|
||||||
|
light-primary-color: "#EBEBF8"
|
||||||
|
info-color: "#3B3AB8"
|
||||||
|
|
||||||
|
primary-text-color: "#18181D"
|
||||||
|
secondary-text-color: "#52525E"
|
||||||
|
disabled-text-color: "#9898A8"
|
||||||
|
|
||||||
|
primary-background-color: "#F4F4F6"
|
||||||
|
secondary-background-color: "#EDEDF1"
|
||||||
|
card-background-color: "#FFFFFF"
|
||||||
|
ha-card-background: "#FFFFFF"
|
||||||
|
divider-color: "#EDEDF1"
|
||||||
|
ha-card-box-shadow: "0 4px 12px 0 rgba(0,0,0,.10)"
|
||||||
|
|
||||||
|
app-header-background-color: "#3B3AB8"
|
||||||
|
more-info-header-background: "#F4F4F6"
|
||||||
|
|
||||||
|
sidebar-background-color: "#FFFFFF"
|
||||||
|
sidebar-text-color: "#52525E"
|
||||||
|
sidebar-icon-color: "#9898A8"
|
||||||
|
sidebar-selected-text-color: "#3B3AB8"
|
||||||
|
sidebar-selected-icon-color: "#3B3AB8"
|
||||||
|
|
||||||
|
state-icon-color: "#3B3AB8"
|
||||||
|
state-icon-active-color: "#A035CC"
|
||||||
|
state-unavailable-color: "#9898A8"
|
||||||
|
paper-item-icon-color: "#9898A8"
|
||||||
|
paper-item-icon-active-color: "#3B3AB8"
|
||||||
|
|
||||||
|
switch-checked-color: "#3B3AB8"
|
||||||
|
switch-checked-track-color: "#3B3AB8"
|
||||||
|
switch-unchecked-color: "#9898A8"
|
||||||
|
switch-unchecked-track-color: "#E4E4EA"
|
||||||
|
slider-color: "#3B3AB8"
|
||||||
|
slider-bar-color: "#E4E4EA"
|
||||||
|
|
||||||
|
label-badge-blue: "#3B3AB8"
|
||||||
|
label-badge-gray: "#9898A8"
|
||||||
|
label-badge-text-color: "#18181D"
|
||||||
|
ha-label-badge-background-color: "#FFFFFF"
|
||||||
|
ha-label-badge-border-color: "#EDEDF1"
|
||||||
|
|
||||||
|
table-row-background-color: "#FFFFFF"
|
||||||
|
table-row-alternative-background-color: "#FAFAFA"
|
||||||
|
markdown-code-background-color: "#F4F4F6"
|
||||||
|
code-editor-background-color: "#FAFAFA"
|
||||||
|
|
||||||
|
paper-card-background-color: "#FFFFFF"
|
||||||
|
paper-card-header-color: "#18181D"
|
||||||
|
paper-dialog-background-color: "#FFFFFF"
|
||||||
|
paper-listbox-background-color: "#FFFFFF"
|
||||||
|
input-fill-color: "#F4F4F6"
|
||||||
|
input-ink-color: "#18181D"
|
||||||
|
input-label-ink-color: "#52525E"
|
||||||
|
iron-overlay-backdrop-background-color: "rgba(24,24,29,.32)"
|
||||||
|
|
||||||
|
mdc-theme-primary: "#3B3AB8"
|
||||||
|
mdc-theme-secondary: "#A035CC"
|
||||||
|
mdc-theme-surface: "#FFFFFF"
|
||||||
|
|
||||||
|
# Weather glyphs, kept in the brand family rather than default sky blue.
|
||||||
|
weather-icon-sun-color: "#D97706"
|
||||||
|
weather-icon-rain-color: "#3B3AB8"
|
||||||
|
weather-icon-cloud-front-color: "#9898A8"
|
||||||
|
weather-icon-cloud-back-color: "#E4E4EA"
|
||||||
|
weather-icon-moon-color: "#52525E"
|
||||||
|
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════
|
||||||
|
# Dark — violet-tinted neutrals so the brand gradient sits in the same
|
||||||
|
# family as the surfaces rather than floating on plain grey. The primary
|
||||||
|
# is lightened to #8B8AF2 (5.6:1 on the card surface); #3B3AB8 itself is
|
||||||
|
# too dark to read as an accent here, though it stays correct inside the
|
||||||
|
# gradient, which is left untouched.
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════
|
||||||
|
dark:
|
||||||
|
cc-surface: "#1C1C27"
|
||||||
|
cc-surface-sunken: "#16161F"
|
||||||
|
cc-text: "#EDEDF1"
|
||||||
|
cc-text-muted: "#9898A8"
|
||||||
|
cc-border: "#2A2A38"
|
||||||
|
cc-accent: "#8B8AF2"
|
||||||
|
cc-accent-soft: "#252438"
|
||||||
|
|
||||||
|
primary-color: "#8B8AF2"
|
||||||
|
accent-color: "#C77BEE"
|
||||||
|
dark-primary-color: "#3B3AB8"
|
||||||
|
light-primary-color: "#C9C8FA"
|
||||||
|
info-color: "#8B8AF2"
|
||||||
|
|
||||||
|
primary-text-color: "#EDEDF1"
|
||||||
|
secondary-text-color: "#9898A8"
|
||||||
|
disabled-text-color: "#6A6A7C"
|
||||||
|
|
||||||
|
primary-background-color: "#0E0E14"
|
||||||
|
secondary-background-color: "#16161F"
|
||||||
|
card-background-color: "#1C1C27"
|
||||||
|
ha-card-background: "#1C1C27"
|
||||||
|
divider-color: "#2A2A38"
|
||||||
|
ha-card-box-shadow: "0 4px 12px 0 rgba(0,0,0,.45)"
|
||||||
|
|
||||||
|
app-header-background-color: "#16161F"
|
||||||
|
more-info-header-background: "#16161F"
|
||||||
|
|
||||||
|
sidebar-background-color: "#0E0E14"
|
||||||
|
sidebar-text-color: "#9898A8"
|
||||||
|
sidebar-icon-color: "#6A6A7C"
|
||||||
|
sidebar-selected-text-color: "#8B8AF2"
|
||||||
|
sidebar-selected-icon-color: "#8B8AF2"
|
||||||
|
|
||||||
|
state-icon-color: "#8B8AF2"
|
||||||
|
state-icon-active-color: "#C77BEE"
|
||||||
|
state-unavailable-color: "#6A6A7C"
|
||||||
|
paper-item-icon-color: "#6A6A7C"
|
||||||
|
paper-item-icon-active-color: "#8B8AF2"
|
||||||
|
|
||||||
|
switch-checked-color: "#8B8AF2"
|
||||||
|
switch-checked-track-color: "#8B8AF2"
|
||||||
|
switch-unchecked-color: "#6A6A7C"
|
||||||
|
switch-unchecked-track-color: "#2A2A38"
|
||||||
|
slider-color: "#8B8AF2"
|
||||||
|
slider-bar-color: "#2A2A38"
|
||||||
|
|
||||||
|
# Semantic colours lifted for dark surfaces; the light-mode values are
|
||||||
|
# too dense to read at a distance on #1C1C27.
|
||||||
|
success-color: "#4ADE80"
|
||||||
|
warning-color: "#FBBF24"
|
||||||
|
error-color: "#F87171"
|
||||||
|
label-badge-green: "#4ADE80"
|
||||||
|
label-badge-yellow: "#FBBF24"
|
||||||
|
label-badge-red: "#F87171"
|
||||||
|
label-badge-blue: "#8B8AF2"
|
||||||
|
label-badge-gray: "#6A6A7C"
|
||||||
|
label-badge-text-color: "#EDEDF1"
|
||||||
|
ha-label-badge-background-color: "#1C1C27"
|
||||||
|
ha-label-badge-border-color: "#2A2A38"
|
||||||
|
|
||||||
|
table-row-background-color: "#1C1C27"
|
||||||
|
table-row-alternative-background-color: "#20202C"
|
||||||
|
markdown-code-background-color: "#252433"
|
||||||
|
code-editor-background-color: "#16161F"
|
||||||
|
|
||||||
|
paper-card-background-color: "#1C1C27"
|
||||||
|
paper-card-header-color: "#EDEDF1"
|
||||||
|
paper-dialog-background-color: "#1C1C27"
|
||||||
|
paper-listbox-background-color: "#1C1C27"
|
||||||
|
input-fill-color: "#252433"
|
||||||
|
input-ink-color: "#EDEDF1"
|
||||||
|
input-label-ink-color: "#9898A8"
|
||||||
|
iron-overlay-backdrop-background-color: "rgba(0,0,0,.6)"
|
||||||
|
|
||||||
|
mdc-theme-primary: "#8B8AF2"
|
||||||
|
mdc-theme-secondary: "#C77BEE"
|
||||||
|
mdc-theme-surface: "#1C1C27"
|
||||||
|
|
||||||
|
weather-icon-sun-color: "#FBBF24"
|
||||||
|
weather-icon-rain-color: "#8B8AF2"
|
||||||
|
weather-icon-cloud-front-color: "#9898A8"
|
||||||
|
weather-icon-cloud-back-color: "#3A3A4A"
|
||||||
|
weather-icon-moon-color: "#C9C8FA"
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
// CubeCraft Creations brand font loader.
|
||||||
|
//
|
||||||
|
// The `cubecraft` theme sets Nunito as the font family, but a theme is only a
|
||||||
|
// bag of CSS variables — it cannot declare an @font-face. The production card
|
||||||
|
// declares one for itself (ensureBrandFont() in cubecraft-production-card.js),
|
||||||
|
// but only on the dashboard where that card is mounted, and only inside that
|
||||||
|
// page's document. Everything else falls back to system-ui.
|
||||||
|
//
|
||||||
|
// Loading this as a frontend module puts the declaration in the document head
|
||||||
|
// on every dashboard, so the whole UI gets Nunito.
|
||||||
|
//
|
||||||
|
// The .woff2 itself is NOT vendored here. It is already shipped and served by
|
||||||
|
// the cubecraft_production integration at STATIC_URL (see const.py: DOMAIN ->
|
||||||
|
// "/cubecraft_production"), which keeps a single copy of the file and one
|
||||||
|
// version to bump. If that integration is ever removed the URL 404s, the
|
||||||
|
// font-family falls through to the stack in the theme, and nothing else breaks.
|
||||||
|
//
|
||||||
|
// Wired up by `frontend.extra_module_url` in configuration.yaml.
|
||||||
|
|
||||||
|
const FONT_STYLE_ID = "cubecraft-brand-font";
|
||||||
|
const FONT_URL = "/cubecraft_production/nunito.woff2";
|
||||||
|
|
||||||
|
// extra_module_url modules are evaluated once per page load, but the card may
|
||||||
|
// have already injected its own copy under a different id — matching on the
|
||||||
|
// family as well keeps us from stacking duplicate @font-face rules.
|
||||||
|
function injectBrandFont() {
|
||||||
|
if (document.getElementById(FONT_STYLE_ID)) return;
|
||||||
|
if (document.getElementById("cubecraft-production-font")) return;
|
||||||
|
|
||||||
|
const style = document.createElement("style");
|
||||||
|
style.id = FONT_STYLE_ID;
|
||||||
|
// Variable weight range 400..800 — the card uses 400 (body), 600/700
|
||||||
|
// (labels, summaries) and 800 (titles, order numbers).
|
||||||
|
style.textContent =
|
||||||
|
"@font-face{" +
|
||||||
|
"font-family:'Nunito';" +
|
||||||
|
`src:url('${FONT_URL}') format('woff2');` +
|
||||||
|
"font-weight:400 800;" +
|
||||||
|
"font-style:normal;" +
|
||||||
|
"font-display:swap;" +
|
||||||
|
"}";
|
||||||
|
document.head.appendChild(style);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (document.head) {
|
||||||
|
injectBrandFont();
|
||||||
|
} else {
|
||||||
|
document.addEventListener("DOMContentLoaded", injectBrandFont, { once: true });
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user