Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@

A Home Assistant Lovelace card that turns any `number` or `input_number` entity into an oversized numeric or time input with clear, easily-tappable controls.

<img width="541" height="281" alt="image" src="https://github.com/user-attachments/assets/d283229c-c190-4a1a-b5c0-1ec4c8912549" />
<img width="468" height="261" alt="image" src="https://github.com/user-attachments/assets/874364b1-dc9c-4a02-8708-1e901f1bfbb2" />


## Features

- Big, high-contrast inputs tailored for wall tablets and touch screens
- Optional step buttons that respect entity min/max/step constraints
- Time mode that splits a total-minute value into hour and minute columns with wrap-aware buttons
- **Visual enhancements in time mode**: HH/MM labels below inputs and AM/PM indicator showing active period
- Automatic clamping to entity-provided bounds with optional overrides
- Customisable width, font size and colours via CSS variables
- Supports both `number` and `input_number` domains (time mode also works with `input_datetime` entities that have time enabled)
Expand Down Expand Up @@ -55,6 +56,10 @@ show_buttons: true

When `mode: time` is enabled the card expects the entity to expose a numeric value measured in minutes. You can back this with an `input_number` storing minutes or an `input_datetime` that has time enabled (the card will call `input_datetime.set_datetime` for you). The card handles the hour/minute split, wraps minute increments across hour boundaries, and honours the entity min/max limits.

**Time mode visual features:**
- **HH/MM labels**: Clear labels appear below each time input to indicate hours and minutes
- **AM/PM indicator**: A vertical indicator displays both AM and PM, with the active period highlighted (full opacity) and inactive dimmed (30% opacity)

### Options

| Option | Type | Default | Description |
Expand Down
36 changes: 35 additions & 1 deletion large-number-input-card.js
Original file line number Diff line number Diff line change
Expand Up @@ -175,12 +175,39 @@ const registerLargeNumberInputCard = async () => {

.time-column {
display: grid;
grid-template-rows: auto auto auto;
grid-template-rows: auto auto auto auto;
align-items: center;
justify-items: center;
gap: 8px;
}

.time-label {
font-size: 0.75rem;
font-weight: 500;
color: var(--secondary-text-color);
text-transform: uppercase;
letter-spacing: 0.5px;
}

.ampm-indicator {
display: flex;
flex-direction: column;
gap: 4px;
font-size: 0.85rem;
font-weight: 600;
color: var(--primary-text-color);
align-self: center;
}

.ampm-indicator span {
opacity: 0.3;
transition: opacity 0.2s ease;
}

.ampm-indicator span.active {
opacity: 1;
}

.time-button {
width: var(--lnic-time-button-size, 48px);
height: var(--lnic-time-button-size, 48px);
Expand Down Expand Up @@ -363,11 +390,16 @@ const registerLargeNumberInputCard = async () => {
_renderTimeControls({ stateObj, disabled, value }) {
const parts = this._getTimeDisplayParts(value, stateObj);
const separator = this._config.time_separator ?? ":";
const isAM = parts.hours < 12;
return html`
<div class="time-grid">
${this._renderTimeColumn({ part: "hours", value: parts.hours, disabled, stateObj })}
<div class="time-separator" aria-hidden="true">${separator}</div>
${this._renderTimeColumn({ part: "minutes", value: parts.minutes, disabled, stateObj })}
<div class="ampm-indicator">
<span class="${isAM ? 'active' : ''}">AM</span>
<span class="${!isAM ? 'active' : ''}">PM</span>
</div>
</div>
`;
}
Expand All @@ -378,6 +410,7 @@ const registerLargeNumberInputCard = async () => {
const increaseLabel = isHours ? "Increase hours" : "Increase minutes";
const decreaseLabel = isHours ? "Decrease hours" : "Decrease minutes";
const displayValue = this._formatTimePart(value);
const label = isHours ? "HH" : "MM";

return html`
<div class="time-column">
Expand All @@ -394,6 +427,7 @@ const registerLargeNumberInputCard = async () => {
&#9650;
</button>`
: null}
<div class="time-label">${label}</div>
<input
class="time-input"
type="text"
Expand Down