mirror of
https://github.com/home-assistant/frontend.git
synced 2026-03-11 01:37:45 +00:00
Compare commits
4 Commits
ha-input
...
windows-98
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bfc5ae4a4f | ||
|
|
1b237e744f | ||
|
|
2139df49c5 | ||
|
|
892f8f605f |
412
src/components/ha-windows-98-theme.ts
Normal file
412
src/components/ha-windows-98-theme.ts
Normal file
@@ -0,0 +1,412 @@
|
||||
import type { Theme } from "../data/ws-themes";
|
||||
|
||||
export const WINDOWS_98_THEME: Theme = {
|
||||
// Sharp corners
|
||||
"ha-border-radius-sm": "0",
|
||||
"ha-border-radius-md": "0",
|
||||
"ha-border-radius-lg": "0",
|
||||
"ha-border-radius-xl": "0",
|
||||
"ha-border-radius-2xl": "0",
|
||||
"ha-border-radius-3xl": "0",
|
||||
"ha-border-radius-4xl": "0",
|
||||
"ha-border-radius-5xl": "0",
|
||||
"ha-border-radius-6xl": "0",
|
||||
"ha-border-radius-pill": "0",
|
||||
"ha-border-radius-circle": "0",
|
||||
|
||||
// Fonts
|
||||
"ha-font-family-body":
|
||||
"Tahoma, 'MS Sans Serif', 'Microsoft Sans Serif', Arial, sans-serif",
|
||||
"ha-font-family-heading":
|
||||
"Tahoma, 'MS Sans Serif', 'Microsoft Sans Serif', Arial, sans-serif",
|
||||
"ha-font-family-code": "'Courier New', Courier, monospace",
|
||||
|
||||
// No transparency
|
||||
"ha-dialog-scrim-backdrop-filter": "none",
|
||||
|
||||
// Disable animations
|
||||
"ha-animation-duration-fast": "1ms",
|
||||
"ha-animation-duration-normal": "1ms",
|
||||
"ha-animation-duration-slow": "1ms",
|
||||
|
||||
modes: {
|
||||
light: {
|
||||
"primary-color": "#000080",
|
||||
"dark-primary-color": "#00006B",
|
||||
"light-primary-color": "#4040C0",
|
||||
"accent-color": "#000080",
|
||||
"primary-text-color": "#000000",
|
||||
"secondary-text-color": "#404040",
|
||||
"text-primary-color": "#ffffff",
|
||||
"text-light-primary-color": "#000000",
|
||||
"disabled-text-color": "#808080",
|
||||
"primary-background-color": "#008080",
|
||||
"secondary-background-color": "#C0C0C0",
|
||||
"card-background-color": "#C0C0C0",
|
||||
"clear-background-color": "#C0C0C0",
|
||||
"rgb-primary-color": "0, 0, 128",
|
||||
"rgb-accent-color": "0, 0, 128",
|
||||
"rgb-primary-text-color": "0, 0, 0",
|
||||
"rgb-secondary-text-color": "64, 64, 64",
|
||||
"rgb-text-primary-color": "255, 255, 255",
|
||||
"rgb-card-background-color": "192, 192, 192",
|
||||
"divider-color": "#808080",
|
||||
"outline-color": "#808080",
|
||||
"outline-hover-color": "#404040",
|
||||
"shadow-color": "rgba(0, 0, 0, 0.5)",
|
||||
"scrollbar-thumb-color": "#808080",
|
||||
"disabled-color": "#C0C0C0",
|
||||
"ha-card-border-width": "1px",
|
||||
"ha-card-border-color": "#808080",
|
||||
"ha-card-box-shadow": "1px 1px 0 #404040, -1px -1px 0 #ffffff",
|
||||
"ha-card-border-radius": "0",
|
||||
"ha-dialog-border-radius": "0",
|
||||
"ha-dialog-surface-background": "#C0C0C0",
|
||||
"dialog-box-shadow": "1px 1px 0 #404040, -1px -1px 0 #ffffff",
|
||||
"ha-box-shadow-s": "1px 1px 0 #404040, -1px -1px 0 #ffffff",
|
||||
"ha-box-shadow-m": "1px 1px 0 #404040, -1px -1px 0 #ffffff",
|
||||
"ha-box-shadow-l": "1px 1px 0 #404040, -1px -1px 0 #ffffff",
|
||||
"sidebar-background-color": "#C0C0C0",
|
||||
"sidebar-text-color": "#000000",
|
||||
"sidebar-selected-text-color": "#ffffff",
|
||||
"sidebar-selected-icon-color": "#000080",
|
||||
"sidebar-icon-color": "#000000",
|
||||
"dark-divider-opacity": "0.3",
|
||||
"app-header-background-color": "#000080",
|
||||
"app-header-text-color": "#ffffff",
|
||||
"app-header-border-bottom": "2px outset #C0C0C0",
|
||||
"switch-checked-color": "#000080",
|
||||
"switch-checked-button-color": "#C0C0C0",
|
||||
"switch-checked-track-color": "#000080",
|
||||
"switch-unchecked-button-color": "#C0C0C0",
|
||||
"switch-unchecked-track-color": "#808080",
|
||||
"slider-color": "#000080",
|
||||
"table-row-background-color": "#C0C0C0",
|
||||
"table-row-alternative-background-color": "#D4D0C8",
|
||||
"table-header-background-color": "#D4D0C8",
|
||||
"data-table-background-color": "#C0C0C0",
|
||||
"data-table-border-width": "0",
|
||||
"label-badge-background-color": "#C0C0C0",
|
||||
"label-badge-text-color": "#000000",
|
||||
"input-fill-color": "#ffffff",
|
||||
"input-disabled-fill-color": "#C0C0C0",
|
||||
"input-ink-color": "#000000",
|
||||
"input-label-ink-color": "#000000",
|
||||
"input-disabled-ink-color": "#808080",
|
||||
"input-idle-line-color": "#808080",
|
||||
"input-hover-line-color": "#000000",
|
||||
"input-disabled-line-color": "#C0C0C0",
|
||||
"input-outlined-idle-border-color": "#808080",
|
||||
"input-outlined-hover-border-color": "#000000",
|
||||
"input-outlined-disabled-border-color": "#C0C0C0",
|
||||
"input-dropdown-icon-color": "#000000",
|
||||
"error-color": "#FF0000",
|
||||
"warning-color": "#FF8000",
|
||||
"success-color": "#008000",
|
||||
"info-color": "#000080",
|
||||
"state-icon-color": "#000080",
|
||||
"state-active-color": "#000080",
|
||||
"state-inactive-color": "#808080",
|
||||
"mdc-theme-primary": "#000080",
|
||||
"mdc-theme-secondary": "#000080",
|
||||
"mdc-theme-background": "#008080",
|
||||
"mdc-theme-surface": "#C0C0C0",
|
||||
"mdc-theme-on-primary": "#ffffff",
|
||||
"mdc-theme-on-secondary": "#ffffff",
|
||||
"mdc-theme-on-surface": "#000000",
|
||||
"mdc-theme-error": "#FF0000",
|
||||
"mdc-checkbox-unchecked-color": "#808080",
|
||||
"mdc-radio-unchecked-color": "#808080",
|
||||
"mdc-tab-text-label-color-default": "#000000",
|
||||
"mdc-button-outline-color": "#808080",
|
||||
"mdc-dialog-heading-ink-color": "#000000",
|
||||
"mdc-dialog-content-ink-color": "#000000",
|
||||
"mdc-text-field-fill-color": "#ffffff",
|
||||
"mdc-text-field-ink-color": "#000000",
|
||||
"mdc-text-field-label-ink-color": "#000000",
|
||||
"mdc-text-field-idle-line-color": "#808080",
|
||||
"mdc-text-field-hover-line-color": "#000000",
|
||||
"mdc-select-fill-color": "#ffffff",
|
||||
"mdc-select-ink-color": "#000000",
|
||||
"mdc-select-label-ink-color": "#000000",
|
||||
"mdc-select-idle-line-color": "#808080",
|
||||
"mdc-select-hover-line-color": "#000000",
|
||||
"mdc-select-dropdown-icon-color": "#000000",
|
||||
"ha-color-primary-05": "#00003A",
|
||||
"ha-color-primary-10": "#000050",
|
||||
"ha-color-primary-20": "#000066",
|
||||
"ha-color-primary-30": "#00007A",
|
||||
"ha-color-primary-40": "#000080",
|
||||
"ha-color-primary-50": "#0000AA",
|
||||
"ha-color-primary-60": "#4040C0",
|
||||
"ha-color-primary-70": "#6060D0",
|
||||
"ha-color-primary-80": "#8080E0",
|
||||
"ha-color-primary-90": "#C0C0F0",
|
||||
"ha-color-primary-95": "#E0E0FF",
|
||||
"ha-color-neutral-05": "#000000",
|
||||
"ha-color-neutral-10": "#404040",
|
||||
"ha-color-neutral-20": "#606060",
|
||||
"ha-color-neutral-30": "#808080",
|
||||
"ha-color-neutral-40": "#808080",
|
||||
"ha-color-neutral-50": "#A0A0A0",
|
||||
"ha-color-neutral-60": "#B0B0B0",
|
||||
"ha-color-neutral-70": "#C0C0C0",
|
||||
"ha-color-neutral-80": "#D4D0C8",
|
||||
"ha-color-neutral-90": "#DFDFDF",
|
||||
"ha-color-neutral-95": "#F0F0F0",
|
||||
"ha-color-text-primary": "#000000",
|
||||
"ha-color-text-secondary": "#404040",
|
||||
"ha-color-text-disabled": "#808080",
|
||||
"ha-color-text-link": "#000080",
|
||||
"ha-color-surface-default": "#C0C0C0",
|
||||
"ha-color-on-surface-default": "#000000",
|
||||
"ha-color-border-neutral-quiet": "#C0C0C0",
|
||||
"ha-color-border-neutral-normal": "#808080",
|
||||
"ha-color-border-neutral-loud": "#404040",
|
||||
"ha-color-fill-primary-quiet-resting": "#C0C0F0",
|
||||
"ha-color-fill-primary-quiet-hover": "#A0A0E0",
|
||||
"ha-color-fill-primary-quiet-active": "#8080D0",
|
||||
"ha-color-fill-primary-normal-resting": "#8080D0",
|
||||
"ha-color-fill-primary-normal-hover": "#6060C0",
|
||||
"ha-color-fill-primary-normal-active": "#4040B0",
|
||||
"ha-color-fill-primary-loud-resting": "#000080",
|
||||
"ha-color-fill-primary-loud-hover": "#00006B",
|
||||
"ha-color-fill-primary-loud-active": "#000060",
|
||||
"ha-color-fill-neutral-quiet-resting": "#D4D0C8",
|
||||
"ha-color-fill-neutral-quiet-hover": "#C0C0C0",
|
||||
"ha-color-fill-neutral-quiet-active": "#B0B0B0",
|
||||
"ha-color-fill-neutral-normal-resting": "#C0C0C0",
|
||||
"ha-color-fill-neutral-normal-hover": "#B0B0B0",
|
||||
"ha-color-fill-neutral-normal-active": "#A0A0A0",
|
||||
"ha-color-fill-neutral-loud-resting": "#808080",
|
||||
"ha-color-fill-neutral-loud-hover": "#606060",
|
||||
"ha-color-fill-neutral-loud-active": "#404040",
|
||||
"ha-color-on-primary-quiet": "#000080",
|
||||
"ha-color-on-primary-normal": "#000080",
|
||||
"ha-color-on-primary-loud": "#ffffff",
|
||||
"ha-color-on-neutral-quiet": "#808080",
|
||||
"ha-color-on-neutral-normal": "#606060",
|
||||
"ha-color-on-neutral-loud": "#ffffff",
|
||||
"ha-color-fill-danger-loud-resting": "#FF0000",
|
||||
"ha-color-fill-danger-loud-hover": "#CC0000",
|
||||
"ha-color-fill-danger-loud-active": "#AA0000",
|
||||
"ha-color-fill-warning-loud-resting": "#FF8000",
|
||||
"ha-color-fill-warning-loud-hover": "#CC6600",
|
||||
"ha-color-fill-warning-loud-active": "#AA5500",
|
||||
"ha-color-fill-success-loud-resting": "#008000",
|
||||
"ha-color-fill-success-loud-hover": "#006600",
|
||||
"ha-color-fill-success-loud-active": "#005500",
|
||||
"ha-assist-chip-filled-container-color": "#D4D0C8",
|
||||
"chip-background-color": "#D4D0C8",
|
||||
"markdown-code-background-color": "#D4D0C8",
|
||||
"codemirror-keyword": "#000080",
|
||||
"codemirror-operator": "#000000",
|
||||
"codemirror-variable": "#008080",
|
||||
"codemirror-variable-2": "#000080",
|
||||
"codemirror-variable-3": "#808000",
|
||||
"codemirror-builtin": "#800080",
|
||||
"codemirror-atom": "#008080",
|
||||
"codemirror-number": "#FF0000",
|
||||
"codemirror-def": "#000080",
|
||||
"codemirror-string": "#008000",
|
||||
"codemirror-string-2": "#808000",
|
||||
"codemirror-comment": "#808080",
|
||||
"codemirror-tag": "#800000",
|
||||
"codemirror-meta": "#000080",
|
||||
"codemirror-attribute": "#FF0000",
|
||||
"codemirror-property": "#000080",
|
||||
"codemirror-qualifier": "#808000",
|
||||
"codemirror-type": "#000080",
|
||||
},
|
||||
dark: {
|
||||
"primary-color": "#4040C0",
|
||||
"dark-primary-color": "#000080",
|
||||
"light-primary-color": "#6060D0",
|
||||
"accent-color": "#4040C0",
|
||||
"primary-text-color": "#C0C0C0",
|
||||
"secondary-text-color": "#A0A0A0",
|
||||
"text-primary-color": "#ffffff",
|
||||
"text-light-primary-color": "#C0C0C0",
|
||||
"disabled-text-color": "#606060",
|
||||
"primary-background-color": "#003030",
|
||||
"secondary-background-color": "#2A2A2A",
|
||||
"card-background-color": "#3A3A3A",
|
||||
"clear-background-color": "#2A2A2A",
|
||||
"rgb-primary-color": "64, 64, 192",
|
||||
"rgb-accent-color": "64, 64, 192",
|
||||
"rgb-primary-text-color": "192, 192, 192",
|
||||
"rgb-secondary-text-color": "160, 160, 160",
|
||||
"rgb-text-primary-color": "255, 255, 255",
|
||||
"rgb-card-background-color": "58, 58, 58",
|
||||
"divider-color": "#606060",
|
||||
"outline-color": "#606060",
|
||||
"outline-hover-color": "#808080",
|
||||
"shadow-color": "rgba(0, 0, 0, 0.7)",
|
||||
"scrollbar-thumb-color": "#606060",
|
||||
"disabled-color": "#606060",
|
||||
"ha-card-border-width": "1px",
|
||||
"ha-card-border-color": "#606060",
|
||||
"ha-card-box-shadow": "1px 1px 0 #1A1A1A, -1px -1px 0 #5A5A5A",
|
||||
"ha-card-border-radius": "0",
|
||||
"ha-dialog-border-radius": "0",
|
||||
"ha-dialog-surface-background": "#3A3A3A",
|
||||
"dialog-box-shadow": "1px 1px 0 #1A1A1A, -1px -1px 0 #5A5A5A",
|
||||
"ha-box-shadow-s": "1px 1px 0 #1A1A1A, -1px -1px 0 #5A5A5A",
|
||||
"ha-box-shadow-m": "1px 1px 0 #1A1A1A, -1px -1px 0 #5A5A5A",
|
||||
"ha-box-shadow-l": "1px 1px 0 #1A1A1A, -1px -1px 0 #5A5A5A",
|
||||
"sidebar-background-color": "#2A2A2A",
|
||||
"sidebar-text-color": "#C0C0C0",
|
||||
"sidebar-selected-text-color": "#ffffff",
|
||||
"sidebar-selected-icon-color": "#4040C0",
|
||||
"sidebar-icon-color": "#A0A0A0",
|
||||
"dark-divider-opacity": "0.3",
|
||||
"app-header-background-color": "#000060",
|
||||
"app-header-text-color": "#ffffff",
|
||||
"app-header-border-bottom": "2px outset #3A3A3A",
|
||||
"switch-checked-color": "#4040C0",
|
||||
"switch-checked-button-color": "#808080",
|
||||
"switch-checked-track-color": "#4040C0",
|
||||
"switch-unchecked-button-color": "#808080",
|
||||
"switch-unchecked-track-color": "#404040",
|
||||
"slider-color": "#4040C0",
|
||||
"table-row-background-color": "#3A3A3A",
|
||||
"table-row-alternative-background-color": "#2A2A2A",
|
||||
"table-header-background-color": "#4A4A4A",
|
||||
"data-table-background-color": "#3A3A3A",
|
||||
"data-table-border-width": "0",
|
||||
"label-badge-background-color": "#3A3A3A",
|
||||
"label-badge-text-color": "#C0C0C0",
|
||||
"input-fill-color": "#2A2A2A",
|
||||
"input-disabled-fill-color": "#3A3A3A",
|
||||
"input-ink-color": "#C0C0C0",
|
||||
"input-label-ink-color": "#A0A0A0",
|
||||
"input-disabled-ink-color": "#606060",
|
||||
"input-idle-line-color": "#606060",
|
||||
"input-hover-line-color": "#808080",
|
||||
"input-disabled-line-color": "#404040",
|
||||
"input-outlined-idle-border-color": "#606060",
|
||||
"input-outlined-hover-border-color": "#808080",
|
||||
"input-outlined-disabled-border-color": "#404040",
|
||||
"input-dropdown-icon-color": "#A0A0A0",
|
||||
"error-color": "#FF4040",
|
||||
"warning-color": "#FFA040",
|
||||
"success-color": "#40C040",
|
||||
"info-color": "#4040C0",
|
||||
"state-icon-color": "#4040C0",
|
||||
"state-active-color": "#4040C0",
|
||||
"state-inactive-color": "#606060",
|
||||
"mdc-theme-primary": "#4040C0",
|
||||
"mdc-theme-secondary": "#4040C0",
|
||||
"mdc-theme-background": "#003030",
|
||||
"mdc-theme-surface": "#3A3A3A",
|
||||
"mdc-theme-on-primary": "#ffffff",
|
||||
"mdc-theme-on-secondary": "#ffffff",
|
||||
"mdc-theme-on-surface": "#C0C0C0",
|
||||
"mdc-theme-error": "#FF4040",
|
||||
"mdc-checkbox-unchecked-color": "#606060",
|
||||
"mdc-radio-unchecked-color": "#606060",
|
||||
"mdc-tab-text-label-color-default": "#C0C0C0",
|
||||
"mdc-button-outline-color": "#606060",
|
||||
"mdc-dialog-heading-ink-color": "#C0C0C0",
|
||||
"mdc-dialog-content-ink-color": "#C0C0C0",
|
||||
"mdc-text-field-fill-color": "#2A2A2A",
|
||||
"mdc-text-field-ink-color": "#C0C0C0",
|
||||
"mdc-text-field-label-ink-color": "#A0A0A0",
|
||||
"mdc-text-field-idle-line-color": "#606060",
|
||||
"mdc-text-field-hover-line-color": "#808080",
|
||||
"mdc-select-fill-color": "#2A2A2A",
|
||||
"mdc-select-ink-color": "#C0C0C0",
|
||||
"mdc-select-label-ink-color": "#A0A0A0",
|
||||
"mdc-select-idle-line-color": "#606060",
|
||||
"mdc-select-hover-line-color": "#808080",
|
||||
"mdc-select-dropdown-icon-color": "#A0A0A0",
|
||||
"ha-color-primary-05": "#00002A",
|
||||
"ha-color-primary-10": "#000040",
|
||||
"ha-color-primary-20": "#000060",
|
||||
"ha-color-primary-30": "#000080",
|
||||
"ha-color-primary-40": "#4040C0",
|
||||
"ha-color-primary-50": "#6060D0",
|
||||
"ha-color-primary-60": "#8080E0",
|
||||
"ha-color-primary-70": "#A0A0F0",
|
||||
"ha-color-primary-80": "#C0C0FF",
|
||||
"ha-color-primary-90": "#E0E0FF",
|
||||
"ha-color-primary-95": "#F0F0FF",
|
||||
"ha-color-neutral-05": "#1A1A1A",
|
||||
"ha-color-neutral-10": "#2A2A2A",
|
||||
"ha-color-neutral-20": "#3A3A3A",
|
||||
"ha-color-neutral-30": "#4A4A4A",
|
||||
"ha-color-neutral-40": "#606060",
|
||||
"ha-color-neutral-50": "#808080",
|
||||
"ha-color-neutral-60": "#A0A0A0",
|
||||
"ha-color-neutral-70": "#B0B0B0",
|
||||
"ha-color-neutral-80": "#C0C0C0",
|
||||
"ha-color-neutral-90": "#D4D0C8",
|
||||
"ha-color-neutral-95": "#E0E0E0",
|
||||
"ha-color-text-primary": "#C0C0C0",
|
||||
"ha-color-text-secondary": "#A0A0A0",
|
||||
"ha-color-text-disabled": "#606060",
|
||||
"ha-color-text-link": "#8080E0",
|
||||
"ha-color-surface-default": "#3A3A3A",
|
||||
"ha-color-on-surface-default": "#C0C0C0",
|
||||
"ha-color-border-neutral-quiet": "#4A4A4A",
|
||||
"ha-color-border-neutral-normal": "#606060",
|
||||
"ha-color-border-neutral-loud": "#808080",
|
||||
"ha-color-fill-primary-quiet-resting": "#00002A",
|
||||
"ha-color-fill-primary-quiet-hover": "#000040",
|
||||
"ha-color-fill-primary-quiet-active": "#000060",
|
||||
"ha-color-fill-primary-normal-resting": "#000040",
|
||||
"ha-color-fill-primary-normal-hover": "#000060",
|
||||
"ha-color-fill-primary-normal-active": "#000080",
|
||||
"ha-color-fill-primary-loud-resting": "#4040C0",
|
||||
"ha-color-fill-primary-loud-hover": "#3030A0",
|
||||
"ha-color-fill-primary-loud-active": "#2020A0",
|
||||
"ha-color-fill-neutral-quiet-resting": "#2A2A2A",
|
||||
"ha-color-fill-neutral-quiet-hover": "#3A3A3A",
|
||||
"ha-color-fill-neutral-quiet-active": "#2A2A2A",
|
||||
"ha-color-fill-neutral-normal-resting": "#3A3A3A",
|
||||
"ha-color-fill-neutral-normal-hover": "#4A4A4A",
|
||||
"ha-color-fill-neutral-normal-active": "#3A3A3A",
|
||||
"ha-color-fill-neutral-loud-resting": "#606060",
|
||||
"ha-color-fill-neutral-loud-hover": "#4A4A4A",
|
||||
"ha-color-fill-neutral-loud-active": "#606060",
|
||||
"ha-color-on-primary-quiet": "#8080E0",
|
||||
"ha-color-on-primary-normal": "#6060D0",
|
||||
"ha-color-on-primary-loud": "#ffffff",
|
||||
"ha-color-on-neutral-quiet": "#A0A0A0",
|
||||
"ha-color-on-neutral-normal": "#808080",
|
||||
"ha-color-on-neutral-loud": "#ffffff",
|
||||
"ha-color-fill-danger-loud-resting": "#FF4040",
|
||||
"ha-color-fill-danger-loud-hover": "#CC3030",
|
||||
"ha-color-fill-danger-loud-active": "#AA2020",
|
||||
"ha-color-fill-warning-loud-resting": "#FFA040",
|
||||
"ha-color-fill-warning-loud-hover": "#CC8030",
|
||||
"ha-color-fill-warning-loud-active": "#AA6020",
|
||||
"ha-color-fill-success-loud-resting": "#40C040",
|
||||
"ha-color-fill-success-loud-hover": "#30A030",
|
||||
"ha-color-fill-success-loud-active": "#208020",
|
||||
"ha-assist-chip-filled-container-color": "#4A4A4A",
|
||||
"chip-background-color": "#4A4A4A",
|
||||
"markdown-code-background-color": "#2A2A2A",
|
||||
"codemirror-keyword": "#8080E0",
|
||||
"codemirror-operator": "#C0C0C0",
|
||||
"codemirror-variable": "#40C0C0",
|
||||
"codemirror-variable-2": "#8080E0",
|
||||
"codemirror-variable-3": "#C0C040",
|
||||
"codemirror-builtin": "#C040C0",
|
||||
"codemirror-atom": "#40C0C0",
|
||||
"codemirror-number": "#FF6060",
|
||||
"codemirror-def": "#8080E0",
|
||||
"codemirror-string": "#40C040",
|
||||
"codemirror-string-2": "#C0C040",
|
||||
"codemirror-comment": "#808080",
|
||||
"codemirror-tag": "#C04040",
|
||||
"codemirror-meta": "#8080E0",
|
||||
"codemirror-attribute": "#FF6060",
|
||||
"codemirror-property": "#8080E0",
|
||||
"codemirror-qualifier": "#C0C040",
|
||||
"codemirror-type": "#8080E0",
|
||||
"map-filter":
|
||||
"invert(0.9) hue-rotate(170deg) brightness(1.5) contrast(1.2) saturate(0.3)",
|
||||
},
|
||||
},
|
||||
};
|
||||
538
src/components/ha-windows-98.ts
Normal file
538
src/components/ha-windows-98.ts
Normal file
@@ -0,0 +1,538 @@
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import {
|
||||
applyThemesOnElement,
|
||||
invalidateThemeCache,
|
||||
} from "../common/dom/apply_themes_on_element";
|
||||
import type { LocalizeKeys } from "../common/translations/localize";
|
||||
import { subscribeLabFeature } from "../data/labs";
|
||||
import { SubscribeMixin } from "../mixins/subscribe-mixin";
|
||||
import type { HomeAssistant } from "../types";
|
||||
import { WINDOWS_98_THEME } from "./ha-windows-98-theme";
|
||||
|
||||
const TIP_COUNT = 25;
|
||||
|
||||
type CasitaExpression =
|
||||
| "hi"
|
||||
| "ok-nabu"
|
||||
| "heart"
|
||||
| "sleep"
|
||||
| "great-job"
|
||||
| "error";
|
||||
|
||||
const STORAGE_KEY = "windows-98-position";
|
||||
const DRAG_THRESHOLD = 5;
|
||||
const BUBBLE_TIMEOUT = 8000;
|
||||
const SLEEP_TIMEOUT = 30000;
|
||||
|
||||
@customElement("ha-windows-98")
|
||||
export class HaWindows98 extends SubscribeMixin(LitElement) {
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@property({ type: Boolean }) public narrow = false;
|
||||
|
||||
@state() private _enabled = false;
|
||||
|
||||
public hassSubscribe() {
|
||||
return [
|
||||
subscribeLabFeature(
|
||||
this.hass!.connection,
|
||||
"frontend",
|
||||
"windows_98",
|
||||
(feature) => {
|
||||
this._enabled = feature.enabled;
|
||||
}
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
@state() private _casitaVisible = true;
|
||||
|
||||
@state() private _showBubble = false;
|
||||
|
||||
@state() private _bubbleText = "";
|
||||
|
||||
@state() private _expression: CasitaExpression = "hi";
|
||||
|
||||
@state() private _position: { x: number; y: number } | null = null;
|
||||
|
||||
private _dragging = false;
|
||||
|
||||
private _dragStartX = 0;
|
||||
|
||||
private _dragStartY = 0;
|
||||
|
||||
private _dragOffsetX = 0;
|
||||
|
||||
private _dragOffsetY = 0;
|
||||
|
||||
private _dragMoved = false;
|
||||
|
||||
private _bubbleTimer?: ReturnType<typeof setTimeout>;
|
||||
|
||||
private _sleepTimer?: ReturnType<typeof setTimeout>;
|
||||
|
||||
private _boundPointerMove = this._onPointerMove.bind(this);
|
||||
|
||||
private _boundPointerUp = this._onPointerUp.bind(this);
|
||||
|
||||
private _themeApplied = false;
|
||||
|
||||
private _isApplyingTheme = false;
|
||||
|
||||
private _themeObserver?: MutationObserver;
|
||||
|
||||
connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
this._loadPosition();
|
||||
this._resetSleepTimer();
|
||||
this._applyWin98Theme();
|
||||
this._startThemeObserver();
|
||||
}
|
||||
|
||||
disconnectedCallback(): void {
|
||||
super.disconnectedCallback();
|
||||
this._clearTimers();
|
||||
this._stopThemeObserver();
|
||||
this._revertTheme();
|
||||
document.removeEventListener("pointermove", this._boundPointerMove);
|
||||
document.removeEventListener("pointerup", this._boundPointerUp);
|
||||
}
|
||||
|
||||
protected willUpdate(changedProps: Map<string, unknown>): void {
|
||||
if (changedProps.has("_enabled")) {
|
||||
if (this._enabled) {
|
||||
this.hass!.loadFragmentTranslation("windows_98");
|
||||
this._applyWin98Theme();
|
||||
this._startThemeObserver();
|
||||
} else {
|
||||
this._stopThemeObserver();
|
||||
this._revertTheme();
|
||||
}
|
||||
}
|
||||
if (changedProps.has("hass") && this._enabled) {
|
||||
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
||||
// Re-apply if darkMode changed
|
||||
if (oldHass && oldHass.themes.darkMode !== this.hass!.themes.darkMode) {
|
||||
this._themeApplied = false;
|
||||
this._applyWin98Theme();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _startThemeObserver(): void {
|
||||
if (this._themeObserver) return;
|
||||
this._themeObserver = new MutationObserver(() => {
|
||||
if (this._isApplyingTheme || !this._enabled || !this.hass) return;
|
||||
// Check if our theme was overwritten by the themes mixin
|
||||
const el = document.documentElement as HTMLElement & {
|
||||
__themes?: { cacheKey?: string };
|
||||
};
|
||||
if (!el.__themes?.cacheKey?.startsWith("Windows 98")) {
|
||||
this._themeApplied = false;
|
||||
this._applyWin98Theme();
|
||||
}
|
||||
});
|
||||
this._themeObserver.observe(document.documentElement, {
|
||||
attributes: true,
|
||||
attributeFilter: ["style"],
|
||||
});
|
||||
}
|
||||
|
||||
private _stopThemeObserver(): void {
|
||||
this._themeObserver?.disconnect();
|
||||
this._themeObserver = undefined;
|
||||
}
|
||||
|
||||
private _applyWin98Theme(): void {
|
||||
if (!this.hass || this._themeApplied) return;
|
||||
|
||||
this._isApplyingTheme = true;
|
||||
|
||||
const themes = {
|
||||
...this.hass.themes,
|
||||
themes: {
|
||||
...this.hass.themes.themes,
|
||||
"Windows 98": WINDOWS_98_THEME,
|
||||
},
|
||||
};
|
||||
|
||||
invalidateThemeCache();
|
||||
applyThemesOnElement(
|
||||
document.documentElement,
|
||||
themes,
|
||||
"Windows 98",
|
||||
{ dark: this.hass.themes.darkMode },
|
||||
true
|
||||
);
|
||||
this._themeApplied = true;
|
||||
this._isApplyingTheme = false;
|
||||
}
|
||||
|
||||
private _revertTheme(): void {
|
||||
if (!this.hass || !this._themeApplied) return;
|
||||
|
||||
this._isApplyingTheme = true;
|
||||
|
||||
invalidateThemeCache();
|
||||
applyThemesOnElement(
|
||||
document.documentElement,
|
||||
this.hass.themes,
|
||||
this.hass.selectedTheme?.theme || "default",
|
||||
{
|
||||
dark: this.hass.themes.darkMode,
|
||||
primaryColor: this.hass.selectedTheme?.primaryColor,
|
||||
accentColor: this.hass.selectedTheme?.accentColor,
|
||||
},
|
||||
true
|
||||
);
|
||||
this._themeApplied = false;
|
||||
this._isApplyingTheme = false;
|
||||
}
|
||||
|
||||
private _loadPosition(): void {
|
||||
try {
|
||||
const stored = localStorage.getItem(STORAGE_KEY);
|
||||
if (stored) {
|
||||
const pos = JSON.parse(stored);
|
||||
if (typeof pos.x === "number" && typeof pos.y === "number") {
|
||||
this._position = this._clampPosition(pos.x, pos.y);
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// Ignore invalid stored position
|
||||
}
|
||||
}
|
||||
|
||||
private _savePosition(): void {
|
||||
if (this._position) {
|
||||
try {
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(this._position));
|
||||
} catch {
|
||||
// Ignore storage errors
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _clampPosition(x: number, y: number): { x: number; y: number } {
|
||||
const size = 80;
|
||||
return {
|
||||
x: Math.max(0, Math.min(window.innerWidth - size, x)),
|
||||
y: Math.max(0, Math.min(window.innerHeight - size, y)),
|
||||
};
|
||||
}
|
||||
|
||||
private _onPointerDown(ev: PointerEvent): void {
|
||||
if (ev.button !== 0) return;
|
||||
|
||||
this._dragging = true;
|
||||
this._dragMoved = false;
|
||||
this._dragStartX = ev.clientX;
|
||||
this._dragStartY = ev.clientY;
|
||||
|
||||
const rect = (ev.currentTarget as HTMLElement).getBoundingClientRect();
|
||||
this._dragOffsetX = ev.clientX - rect.left;
|
||||
this._dragOffsetY = ev.clientY - rect.top;
|
||||
|
||||
(ev.currentTarget as HTMLElement).setPointerCapture(ev.pointerId);
|
||||
document.addEventListener("pointermove", this._boundPointerMove);
|
||||
document.addEventListener("pointerup", this._boundPointerUp);
|
||||
|
||||
ev.preventDefault();
|
||||
}
|
||||
|
||||
private _onPointerMove(ev: PointerEvent): void {
|
||||
if (!this._dragging) return;
|
||||
|
||||
const dx = ev.clientX - this._dragStartX;
|
||||
const dy = ev.clientY - this._dragStartY;
|
||||
|
||||
if (!this._dragMoved && Math.hypot(dx, dy) < DRAG_THRESHOLD) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._dragMoved = true;
|
||||
|
||||
const x = ev.clientX - this._dragOffsetX;
|
||||
const y = ev.clientY - this._dragOffsetY;
|
||||
this._position = this._clampPosition(x, y);
|
||||
}
|
||||
|
||||
private _onPointerUp(ev: PointerEvent): void {
|
||||
document.removeEventListener("pointermove", this._boundPointerMove);
|
||||
document.removeEventListener("pointerup", this._boundPointerUp);
|
||||
|
||||
this._dragging = false;
|
||||
|
||||
if (this._dragMoved) {
|
||||
this._savePosition();
|
||||
} else {
|
||||
this._toggleBubble();
|
||||
}
|
||||
|
||||
ev.preventDefault();
|
||||
}
|
||||
|
||||
private _stopPropagation(ev: Event): void {
|
||||
ev.stopPropagation();
|
||||
}
|
||||
|
||||
private _dismiss(ev: Event): void {
|
||||
ev.stopPropagation();
|
||||
this._casitaVisible = false;
|
||||
this._clearTimers();
|
||||
}
|
||||
|
||||
private _toggleBubble(): void {
|
||||
if (this._showBubble) {
|
||||
this._hideBubble();
|
||||
} else {
|
||||
this._showTip();
|
||||
}
|
||||
}
|
||||
|
||||
private _showTip(): void {
|
||||
const tipIndex = Math.floor(Math.random() * TIP_COUNT) + 1;
|
||||
this._bubbleText = this.hass!.localize(
|
||||
`ui.panel.windows_98.tip_${tipIndex}` as LocalizeKeys
|
||||
);
|
||||
this._showBubble = true;
|
||||
this._expression = "ok-nabu";
|
||||
this._resetSleepTimer();
|
||||
|
||||
if (this._bubbleTimer) {
|
||||
clearTimeout(this._bubbleTimer);
|
||||
}
|
||||
this._bubbleTimer = setTimeout(() => {
|
||||
this._hideBubble();
|
||||
}, BUBBLE_TIMEOUT);
|
||||
}
|
||||
|
||||
private _hideBubble(): void {
|
||||
this._showBubble = false;
|
||||
this._expression = "hi";
|
||||
this._resetSleepTimer();
|
||||
|
||||
if (this._bubbleTimer) {
|
||||
clearTimeout(this._bubbleTimer);
|
||||
this._bubbleTimer = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
private _closeBubble(ev: Event): void {
|
||||
ev.stopPropagation();
|
||||
this._hideBubble();
|
||||
}
|
||||
|
||||
private _resetSleepTimer(): void {
|
||||
if (this._sleepTimer) {
|
||||
clearTimeout(this._sleepTimer);
|
||||
}
|
||||
this._sleepTimer = setTimeout(() => {
|
||||
if (!this._showBubble) {
|
||||
this._expression = "sleep";
|
||||
}
|
||||
}, SLEEP_TIMEOUT);
|
||||
}
|
||||
|
||||
private _clearTimers(): void {
|
||||
if (this._bubbleTimer) {
|
||||
clearTimeout(this._bubbleTimer);
|
||||
this._bubbleTimer = undefined;
|
||||
}
|
||||
if (this._sleepTimer) {
|
||||
clearTimeout(this._sleepTimer);
|
||||
this._sleepTimer = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
protected render() {
|
||||
if (!this._enabled || !this._casitaVisible) {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
const size = 80;
|
||||
const posStyle = this._position
|
||||
? `left: ${this._position.x}px; top: ${this._position.y}px;`
|
||||
: `right: 16px; bottom: 16px;`;
|
||||
|
||||
return html`
|
||||
<div
|
||||
class="casita-container ${this._dragging ? "dragging" : ""}"
|
||||
style="width: ${size}px; ${posStyle}"
|
||||
aria-hidden="true"
|
||||
@pointerdown=${this._onPointerDown}
|
||||
>
|
||||
${this._showBubble
|
||||
? html`
|
||||
<div class="speech-bubble">
|
||||
<span class="bubble-text">${this._bubbleText}</span>
|
||||
<button
|
||||
class="bubble-close"
|
||||
@pointerdown=${this._stopPropagation}
|
||||
@click=${this._closeBubble}
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
<button
|
||||
class="bubble-dismiss"
|
||||
@pointerdown=${this._stopPropagation}
|
||||
@click=${this._dismiss}
|
||||
>
|
||||
${this.hass!.localize("ui.panel.windows_98.dismiss")}
|
||||
</button>
|
||||
<div class="bubble-arrow"></div>
|
||||
</div>
|
||||
`
|
||||
: nothing}
|
||||
<img
|
||||
class="casita-image"
|
||||
src="/static/images/voice-assistant/${this._expression}.png"
|
||||
alt="Casita"
|
||||
draggable="false"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
static readonly styles = css`
|
||||
:host {
|
||||
display: block;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.casita-container {
|
||||
position: fixed;
|
||||
pointer-events: auto;
|
||||
cursor: grab;
|
||||
user-select: none;
|
||||
touch-action: none;
|
||||
filter: drop-shadow(0 2px 8px rgba(0, 0, 0, 0.3));
|
||||
}
|
||||
|
||||
.casita-container.dragging {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
.casita-image {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
animation: bob 3s ease-in-out infinite;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.dragging .casita-image {
|
||||
animation: none;
|
||||
}
|
||||
|
||||
.speech-bubble {
|
||||
position: absolute;
|
||||
bottom: calc(100% + 8px);
|
||||
right: 0;
|
||||
background: #ffffe1;
|
||||
color: #000000;
|
||||
border-radius: 12px;
|
||||
border: 2px solid #000000;
|
||||
padding: 12px 28px 12px 12px;
|
||||
font-family: Tahoma, "MS Sans Serif", Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 1.4;
|
||||
width: 300px;
|
||||
box-sizing: border-box;
|
||||
word-wrap: break-word;
|
||||
overflow-wrap: break-word;
|
||||
box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
|
||||
animation: bubble-in 200ms ease-out;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.bubble-close {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
right: 4px;
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
color: #000000;
|
||||
font-size: 14px;
|
||||
padding: 2px 6px;
|
||||
line-height: 1;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.bubble-close:hover {
|
||||
background: #e0e0c0;
|
||||
}
|
||||
|
||||
.bubble-dismiss {
|
||||
display: block;
|
||||
margin-top: 8px;
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
color: #808080;
|
||||
font-family: Tahoma, "MS Sans Serif", Arial, sans-serif;
|
||||
font-size: 12px;
|
||||
padding: 0;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.bubble-dismiss:hover {
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.bubble-arrow {
|
||||
position: absolute;
|
||||
bottom: -8px;
|
||||
right: 32px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 8px solid transparent;
|
||||
border-right: 8px solid transparent;
|
||||
border-top: 8px solid #ffffe1;
|
||||
}
|
||||
|
||||
@keyframes bob {
|
||||
0%,
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(-4px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes bubble-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(4px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.casita-image {
|
||||
animation: none;
|
||||
}
|
||||
.speech-bubble {
|
||||
animation: none;
|
||||
}
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-windows-98": HaWindows98;
|
||||
}
|
||||
}
|
||||
@@ -52,6 +52,7 @@ export class HomeAssistantMain extends LitElement {
|
||||
|
||||
return html`
|
||||
<ha-snowflakes .hass=${this.hass} .narrow=${this.narrow}></ha-snowflakes>
|
||||
<ha-windows-98 .hass=${this.hass} .narrow=${this.narrow}></ha-windows-98>
|
||||
<ha-drawer
|
||||
.type=${sidebarNarrow ? "modal" : ""}
|
||||
.open=${sidebarNarrow ? this._drawerOpen : false}
|
||||
@@ -79,6 +80,7 @@ export class HomeAssistantMain extends LitElement {
|
||||
protected firstUpdated() {
|
||||
import(/* webpackPreload: true */ "../components/ha-sidebar");
|
||||
import("../components/ha-snowflakes");
|
||||
import("../components/ha-windows-98");
|
||||
|
||||
if (this.hass.auth.external) {
|
||||
this._externalSidebar =
|
||||
|
||||
@@ -46,11 +46,14 @@ class HaConfigLabs extends SubscribeMixin(LitElement) {
|
||||
const featuresToSort = [...features];
|
||||
|
||||
return featuresToSort.sort((a, b) => {
|
||||
// Place frontend.winter_mode at the bottom
|
||||
if (a.domain === "frontend" && a.preview_feature === "winter_mode")
|
||||
return 1;
|
||||
if (b.domain === "frontend" && b.preview_feature === "winter_mode")
|
||||
return -1;
|
||||
// Place frontend fun features at the bottom
|
||||
const funFeatures = ["winter_mode", "windows_98"];
|
||||
const aIsFun =
|
||||
a.domain === "frontend" && funFeatures.includes(a.preview_feature);
|
||||
const bIsFun =
|
||||
b.domain === "frontend" && funFeatures.includes(b.preview_feature);
|
||||
if (aIsFun && !bIsFun) return 1;
|
||||
if (bIsFun && !aIsFun) return -1;
|
||||
|
||||
// Sort everything else alphabetically
|
||||
return domainToName(localize, a.domain).localeCompare(
|
||||
|
||||
@@ -10397,6 +10397,34 @@
|
||||
"add_card": "Add current view as card",
|
||||
"add_card_error": "Unable to add card",
|
||||
"error_no_data": "You need to select some data sources first."
|
||||
},
|
||||
"windows_98": {
|
||||
"tip_1": "Try turning your house off and on again.",
|
||||
"tip_2": "If your automation doesn't work, just add more YAML.",
|
||||
"tip_3": "Talk to your devices. They won't answer, but it helps.",
|
||||
"tip_4": "The best way to secure your smart home is to go back to candles.",
|
||||
"tip_5": "Rebooting fixes everything. Everything.",
|
||||
"tip_6": "Naming your vacuum 'DJ Roomba' increases cleaning efficiency by 200%.",
|
||||
"tip_7": "Your automations run better when you're not looking.",
|
||||
"tip_8": "Every time you restart Home Assistant, a smart bulb loses its pairing.",
|
||||
"tip_9": "The cloud is just someone else's Raspberry Pi.",
|
||||
"tip_10": "You can automate your coffee machine, but you still have to drink it yourself.",
|
||||
"tip_11": "You can save energy by not having a home.",
|
||||
"tip_12": "Psst... you can drag me anywhere you want!",
|
||||
"tip_13": "Did you know? I never sleep. Well, sometimes I do. Zzz...",
|
||||
"tip_14": "Zigbee, Z-Wave, Wi-Fi, Thread... so many protocols, so little time.",
|
||||
"tip_15": "The sun can trigger your automations. Nature is the best sensor.",
|
||||
"tip_16": "It looks like you're trying to automate your home! Would you like help?",
|
||||
"tip_17": "My previous job was a paperclip. I got promoted.",
|
||||
"tip_18": "I run entirely on YAML and good vibes.",
|
||||
"tip_19": "Somewhere, a smart plug is blinking and nobody knows why.",
|
||||
"tip_20": "Home Assistant runs on a Raspberry Pi. I run on hopes and dreams.",
|
||||
"tip_21": "Behind every great home, there's someone staring at logs at 2am.",
|
||||
"tip_22": "404: Motivation not found. Try again after coffee.",
|
||||
"tip_23": "There are two types of people: those who back up, and those who will.",
|
||||
"tip_24": "My favorite color is #008080. Don't ask me why.",
|
||||
"tip_25": "Automations are just spicy if-then statements.",
|
||||
"dismiss": "Dismiss me"
|
||||
}
|
||||
},
|
||||
"tips": {
|
||||
|
||||
Reference in New Issue
Block a user