mirror of
https://github.com/home-assistant/frontend.git
synced 2026-11-07 21:45:16 +00:00
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e35a90543c | ||
|
|
4c9acdfd8f | ||
|
|
21515e6590 | ||
|
|
f7e236896f |
No files matched your search
@@ -16,7 +16,6 @@ runs:
|
||||
with:
|
||||
path: |
|
||||
node_modules
|
||||
packages/*/node_modules
|
||||
~/.local/share/pnpm/store
|
||||
key: >-
|
||||
${{ inputs.node-modules-cache-key }}-${{ runner.os }}-${{ runner.arch }}-${{
|
||||
@@ -36,7 +35,6 @@ runs:
|
||||
with:
|
||||
path: |
|
||||
node_modules
|
||||
packages/*/node_modules
|
||||
~/.local/share/pnpm/store
|
||||
key: >-
|
||||
${{ inputs.node-modules-cache-key }}-${{ runner.os }}-${{ runner.arch }}-${{
|
||||
|
||||
@@ -28,7 +28,6 @@ runs:
|
||||
with:
|
||||
path: |
|
||||
node_modules
|
||||
packages/*/node_modules
|
||||
~/.local/share/pnpm/store
|
||||
key: >-
|
||||
${{ inputs.node-modules-cache-key }}-${{ runner.os }}-${{ runner.arch }}-${{
|
||||
|
||||
@@ -68,42 +68,8 @@ const CONFIG_FILES = [
|
||||
path.join(__dirname, "lit-disable-dev-mode-loader.cjs"),
|
||||
path.join(__dirname, "babel-plugins", "custom-polyfill-plugin.js"),
|
||||
path.join(__dirname, "babel-plugins", "inline-constants-plugin.cjs"),
|
||||
// Its exports define the components source aliases below
|
||||
path.join(__dirname, "..", "packages", "components", "package.json"),
|
||||
];
|
||||
|
||||
// Resolve @home-assistant/components entry points to their sources, so the package
|
||||
// needs no build step during development. The entry points are read from the
|
||||
// "ha-source" export condition of the package; subpath patterns are expanded
|
||||
// for every element, i.e. every directory with a global.ts, like "card".
|
||||
const COMPONENTS_PACKAGE_DIR = path.join(
|
||||
paths.root_dir,
|
||||
"packages",
|
||||
"components"
|
||||
);
|
||||
const COMPONENTS_SRC_DIR = path.join(
|
||||
COMPONENTS_PACKAGE_DIR,
|
||||
"src",
|
||||
"components"
|
||||
);
|
||||
const componentElements = fs
|
||||
.readdirSync(COMPONENTS_SRC_DIR, { recursive: true })
|
||||
.filter((file) => path.basename(file) === "global.ts")
|
||||
.map((file) => path.dirname(file).split(path.sep).join("/"));
|
||||
const componentsSourceAliases = Object.fromEntries(
|
||||
Object.entries(require("../packages/components/package.json").exports)
|
||||
.filter(([, target]) => target["ha-source"])
|
||||
.flatMap(([subpath, target]) =>
|
||||
(subpath.includes("*") ? componentElements : [undefined]).map((name) => [
|
||||
`${path.posix.join("@home-assistant/components", name ? subpath.replaceAll("*", name) : subpath)}$`,
|
||||
path.join(
|
||||
COMPONENTS_PACKAGE_DIR,
|
||||
name ? target["ha-source"].replaceAll("*", name) : target["ha-source"]
|
||||
),
|
||||
])
|
||||
)
|
||||
);
|
||||
|
||||
// Patches change a package's files but not its version, which is all the
|
||||
// node_modules snapshot checks, so their contents go into the version too.
|
||||
const PATCHES_DIR = path.join(paths.root_dir, "patches");
|
||||
@@ -465,7 +431,6 @@ const createRspackConfig = ({
|
||||
"src/resources/polyfills/bigdecimal.ts"
|
||||
),
|
||||
}),
|
||||
...componentsSourceAliases,
|
||||
"lit/static-html$": "lit/static-html.js",
|
||||
"lit/decorators$": "lit/decorators.js",
|
||||
"lit/directive$": "lit/directive.js",
|
||||
|
||||
@@ -301,14 +301,6 @@ export default tseslint.config(
|
||||
globals: globals.node,
|
||||
},
|
||||
},
|
||||
{
|
||||
// Published as native ESM, where package subpath imports such as
|
||||
// "lit/decorators.js" need their extension.
|
||||
files: ["packages/*/src/**/*.ts"],
|
||||
rules: {
|
||||
"import-x/extensions": ["error", "ignorePackages", { ts: "never" }],
|
||||
},
|
||||
},
|
||||
{
|
||||
plugins: {
|
||||
html,
|
||||
|
||||
+4
-5
@@ -13,7 +13,7 @@
|
||||
"lint:prettier": "prettier . --cache --check",
|
||||
"format:prettier": "prettier . --cache --write",
|
||||
"lint:types": "node ./node_modules/@typescript/native/bin/tsc && node ./node_modules/@typescript/native/bin/tsc -p .github/scripts",
|
||||
"lint:lit": "lit-analyzer \"{.,*,packages/*}/src/**/*.ts\"",
|
||||
"lint:lit": "lit-analyzer \"{.,*}/src/**/*.ts\"",
|
||||
"lint:element-imports": "eslint \"**/src/**/*.{js,ts,html}\" --ignore-pattern=.gitignore --rule '{\"ha/no-unused-element-import\": \"warn\"}'",
|
||||
"lint:licenses": "node --no-deprecation script/check-licenses",
|
||||
"lint": "pnpm run lint:eslint && pnpm run lint:prettier && pnpm run lint:types && pnpm run lint:lit",
|
||||
@@ -80,7 +80,7 @@
|
||||
"@swc/helpers": "0.5.23",
|
||||
"@tsparticles/engine": "4.5.1",
|
||||
"@tsparticles/preset-links": "4.5.1",
|
||||
"@versatiles/style": "8.1.1",
|
||||
"@versatiles/style": "8.0.0",
|
||||
"@vibrant/color": "4.0.4",
|
||||
"@vvo/tzdb": "6.202.0",
|
||||
"@webcomponents/scoped-custom-element-registry": "0.0.10",
|
||||
@@ -98,7 +98,7 @@
|
||||
"echarts": "6.1.0",
|
||||
"echarts-extension-chart2music": "0.1.1",
|
||||
"element-internals-polyfill": "3.0.2",
|
||||
"fullcalendar": "7.1.4",
|
||||
"fullcalendar": "7.1.3",
|
||||
"fuse.js": "7.5.0",
|
||||
"hls.js": "1.7.4",
|
||||
"home-assistant-js-websocket": "9.8.1",
|
||||
@@ -123,7 +123,7 @@
|
||||
"sortablejs": "1.15.7",
|
||||
"stacktrace-js": "2.0.2",
|
||||
"superstruct": "2.0.2",
|
||||
"temporal-polyfill": "1.0.7",
|
||||
"temporal-polyfill": "1.0.6",
|
||||
"tinykeys": "4.0.1",
|
||||
"weekstart": "2.0.0",
|
||||
"workbox-cacheable-response": "7.4.1",
|
||||
@@ -147,7 +147,6 @@
|
||||
"@bundle-stats/plugin-webpack-filter": "4.23.1",
|
||||
"@eslint/js": "10.0.1",
|
||||
"@gfx/zopfli": "1.0.15",
|
||||
"@home-assistant/components": "workspace:*",
|
||||
"@html-eslint/eslint-plugin": "0.67.0",
|
||||
"@lokalise/node-api": "17.0.1",
|
||||
"@octokit/auth-oauth-device": "8.0.5",
|
||||
|
||||
@@ -1,156 +0,0 @@
|
||||
# @home-assistant/components
|
||||
|
||||
Home Assistant Components (`hac-*`): framework-agnostic web components built
|
||||
with [Lit](https://lit.dev).
|
||||
|
||||
> Work in progress, not published yet.
|
||||
|
||||
## Registration
|
||||
|
||||
Every element is imported on its own, in one of two ways:
|
||||
|
||||
| Import | Registers in | For |
|
||||
| --------------------------------------------- | -------------------- | ----------------------------------------------------------- |
|
||||
| `@home-assistant/components/<element>` | Global registry | Home Assistant itself |
|
||||
| `@home-assistant/components/<element>/scoped` | Your scoped registry | Custom cards and other code that runs inside Home Assistant |
|
||||
|
||||
`<element>` is the tag name without the `hac-` prefix, like `card` for
|
||||
`hac-card`.
|
||||
|
||||
Both use the copy bundled with your code. A scoped copy is isolated from the
|
||||
one Home Assistant registers globally, so a custom card keeps the version it
|
||||
was built with.
|
||||
|
||||
Global registration skips tag names that are already registered, so the first
|
||||
registration wins and nothing throws.
|
||||
|
||||
### Global
|
||||
|
||||
```ts
|
||||
import "@home-assistant/components/card";
|
||||
```
|
||||
|
||||
### Scoped
|
||||
|
||||
Pass the component's elements to `ScopedElementsMixin` for Lit, or to
|
||||
`createScopedElementRegistry` for plain custom elements. Forgetting the
|
||||
elements is a TypeScript error, and a runtime error in plain JavaScript.
|
||||
|
||||
Lit:
|
||||
|
||||
```ts
|
||||
import { LitElement, html } from "lit";
|
||||
import { ScopedElementsMixin } from "@home-assistant/components/scoped";
|
||||
import { hacCard } from "@home-assistant/components/card/scoped";
|
||||
|
||||
class MyCard extends ScopedElementsMixin(LitElement, [hacCard]) {
|
||||
render() {
|
||||
return html`<hac-card>…</hac-card>`;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Plain custom elements:
|
||||
|
||||
```js
|
||||
import {
|
||||
attachScopedShadow,
|
||||
createScopedElement,
|
||||
createScopedElementRegistry,
|
||||
} from "@home-assistant/components/scoped";
|
||||
import { hacCard } from "@home-assistant/components/card/scoped";
|
||||
|
||||
// Create the registry once, outside the class: all instances of the card share it
|
||||
const registry = createScopedElementRegistry([hacCard]);
|
||||
|
||||
class MyCard extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
const root = attachScopedShadow(this, { mode: "open" }, registry);
|
||||
root.innerHTML = "<hac-card>…</hac-card>";
|
||||
// or: root.append(createScopedElement(root, "hac-card"));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`innerHTML`, `insertAdjacentHTML` and `createScopedElement` use the scoped
|
||||
registry. `document.createElement` uses the global one, so avoid it for
|
||||
scoped elements.
|
||||
|
||||
Scoped registries need native support (Chrome 146+, Safari 26) or
|
||||
`@webcomponents/scoped-custom-element-registry`, which Home Assistant loads.
|
||||
Without either, elements are registered globally instead, and an already
|
||||
registered tag name keeps its existing class.
|
||||
|
||||
Only elements rendered inside the shadow root use the scoped registry. Light
|
||||
DOM content, such as slotted elements, uses the registry of the tree it is
|
||||
written in.
|
||||
|
||||
`lit` is a peer dependency.
|
||||
|
||||
### TypeScript
|
||||
|
||||
Each element's entry points declare its tag in `HTMLElementTagNameMap`, so
|
||||
`document.querySelector("hac-card")` and templates are typed once the element
|
||||
is imported. For the class itself, import its type from the `scoped` entry
|
||||
point; `import type` loads nothing at runtime:
|
||||
|
||||
```ts
|
||||
import type { HacCard } from "@home-assistant/components/card/scoped";
|
||||
```
|
||||
|
||||
The package has no root entry point: each element and the scoped helpers
|
||||
(`@home-assistant/components/scoped`) have their own.
|
||||
|
||||
## Theming
|
||||
|
||||
Each component exposes its own `--hac-*` custom properties, documented in its
|
||||
source, which take precedence. Next come the theme variables of the existing
|
||||
Home Assistant element it replaces, so current themes keep working: `hac-card`
|
||||
reads the variables of `ha-card` (`--ha-card-background`,
|
||||
`--card-background-color`, `--ha-card-border-radius`, …). Last come the
|
||||
semantic color tokens (`--ha-color-*`, like `--ha-color-surface-default`) and
|
||||
their light values, so the components also render outside Home Assistant.
|
||||
|
||||
The legacy theme variables are a temporary bridge for this experiment, not the
|
||||
target design. Home Assistant always defines some of them, like
|
||||
`--card-background-color`, so inside Home Assistant they currently win over
|
||||
the semantic tokens. Once themes move to the semantic tokens, the legacy
|
||||
variables will be removed from the fallbacks.
|
||||
|
||||
## Structure
|
||||
|
||||
Each element has its own directory, named like its import path:
|
||||
|
||||
```
|
||||
src/components/card/ <hac-card> -> @home-assistant/components/card
|
||||
hac-card.ts class, does not register itself
|
||||
info.ts tag name and version
|
||||
global.ts registers globally
|
||||
scoped.ts element for a scoped registry -> …/card/scoped
|
||||
```
|
||||
|
||||
Shared code lives in `src/utils/`: `registration/` for defining elements
|
||||
(global and scoped) and `element/` for helpers that components use
|
||||
themselves, like slot checks.
|
||||
|
||||
Every element has its own version in `info.ts`.
|
||||
|
||||
Entry points are mapped with subpath patterns in `package.json`, so a new
|
||||
element directory needs no `package.json` change. Only `global.ts` files have
|
||||
side effects, which `sideEffects` relies on for tree shaking.
|
||||
|
||||
## Development
|
||||
|
||||
```bash
|
||||
pnpm --filter @home-assistant/components build # ESM, type declarations and custom-elements.json to dist/
|
||||
pnpm --filter @home-assistant/components dev # rebuild on change
|
||||
```
|
||||
|
||||
Inside this repository the app uses the sources directly through
|
||||
the `ha-source` export condition, so no build is needed during development.
|
||||
The package is built with [Rslib](https://rslib.rs) in bundleless mode: every
|
||||
source file becomes its own ES module. The build then generates a
|
||||
[custom elements manifest](https://custom-elements-manifest.open-wc.org) from
|
||||
the JSDoc of each element, so document new slots, parts, CSS properties and
|
||||
events there.
|
||||
@@ -1,84 +0,0 @@
|
||||
// Generates dist/custom-elements.json from the JSDoc of the hac elements, for
|
||||
// editors and documentation tools. Only hac-*.ts files declare elements; the
|
||||
// entry points just re-export them.
|
||||
|
||||
const forEachDeclaration = (customElementsManifest, callback) => {
|
||||
for (const module of customElementsManifest.modules) {
|
||||
for (const declaration of module.declarations ?? []) {
|
||||
callback(declaration);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// The analyzer leaves the readme empty. Paths in the manifest are relative to
|
||||
// the package root, like the module paths.
|
||||
const packageReadme = () => ({
|
||||
name: "package-readme",
|
||||
packageLinkPhase({ customElementsManifest }) {
|
||||
customElementsManifest.readme = "README.md";
|
||||
},
|
||||
});
|
||||
|
||||
// Elements are documented with @summary, which the analyzer only puts into
|
||||
// `summary`. Most tools show `description`, so fall back to the summary.
|
||||
const summaryAsDescription = () => ({
|
||||
name: "summary-as-description",
|
||||
packageLinkPhase({ customElementsManifest }) {
|
||||
forEachDeclaration(customElementsManifest, (declaration) => {
|
||||
if (!declaration.description && declaration.summary) {
|
||||
declaration.description = declaration.summary;
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
// Private and protected members are internal, so keep them out of the
|
||||
// documented API.
|
||||
const publicApiOnly = () => ({
|
||||
name: "public-api-only",
|
||||
packageLinkPhase({ customElementsManifest }) {
|
||||
forEachDeclaration(customElementsManifest, (declaration) => {
|
||||
declaration.members = declaration.members?.filter(
|
||||
(member) => !member.privacy || member.privacy === "public"
|
||||
);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const distPaths = () => {
|
||||
const toDist = (value) => value.replace(/^src\/(.+)\.ts$/, "dist/$1.js");
|
||||
const rewrite = (node) => {
|
||||
if (Array.isArray(node)) {
|
||||
node.forEach(rewrite);
|
||||
return;
|
||||
}
|
||||
if (!node || typeof node !== "object") {
|
||||
return;
|
||||
}
|
||||
for (const [key, value] of Object.entries(node)) {
|
||||
if ((key === "path" || key === "module") && typeof value === "string") {
|
||||
node[key] = toDist(value);
|
||||
} else {
|
||||
rewrite(value);
|
||||
}
|
||||
}
|
||||
};
|
||||
return {
|
||||
name: "dist-paths",
|
||||
packageLinkPhase({ customElementsManifest }) {
|
||||
rewrite(customElementsManifest.modules);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default {
|
||||
globs: ["src/components/**/hac-*.ts"],
|
||||
outdir: "dist",
|
||||
litelement: true,
|
||||
plugins: [
|
||||
packageReadme(),
|
||||
summaryAsDescription(),
|
||||
publicApiOnly(),
|
||||
distPaths(),
|
||||
],
|
||||
};
|
||||
@@ -1,60 +0,0 @@
|
||||
{
|
||||
"name": "@home-assistant/components",
|
||||
"version": "0.0.0",
|
||||
"description": "Home Assistant web components (hac-* elements) built with Lit",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/home-assistant/frontend.git",
|
||||
"directory": "packages/components"
|
||||
},
|
||||
"type": "module",
|
||||
"sideEffects": [
|
||||
"./dist/components/**/global.js",
|
||||
"./src/components/**/global.ts"
|
||||
],
|
||||
"customElements": "dist/custom-elements.json",
|
||||
"exports": {
|
||||
"./scoped": {
|
||||
"ha-source": "./src/scoped.ts",
|
||||
"types": "./dist/scoped.d.ts",
|
||||
"import": "./dist/scoped.js"
|
||||
},
|
||||
"./package.json": "./package.json",
|
||||
"./*/scoped": {
|
||||
"ha-source": "./src/components/*/scoped.ts",
|
||||
"types": "./dist/components/*/scoped.d.ts",
|
||||
"import": "./dist/components/*/scoped.js"
|
||||
},
|
||||
"./*/info": {
|
||||
"ha-source": "./src/components/*/info.ts",
|
||||
"types": "./dist/components/*/info.d.ts",
|
||||
"import": "./dist/components/*/info.js"
|
||||
},
|
||||
"./*": {
|
||||
"ha-source": "./src/components/*/global.ts",
|
||||
"types": "./dist/components/*/global.d.ts",
|
||||
"import": "./dist/components/*/global.js"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "rslib build && cem analyze",
|
||||
"dev": "rslib build --watch",
|
||||
"prepublishOnly": "pnpm run build"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"lit": "^3.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@custom-elements-manifest/analyzer": "0.11.0",
|
||||
"@rslib/core": "1.0.5",
|
||||
"lit": "3.3.3",
|
||||
"typescript": "6.0.3"
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
import { defineConfig } from "@rslib/core";
|
||||
|
||||
// Bundleless build: every source file becomes its own ESM file, so consumers'
|
||||
// bundlers only include the entry points they import. Only global.ts files
|
||||
// register elements; everything else is free of side effects.
|
||||
export default defineConfig({
|
||||
source: {
|
||||
entry: { index: ["./src/**/*.ts"] },
|
||||
decorators: { version: "legacy" },
|
||||
tsconfigPath: "./tsconfig.json",
|
||||
},
|
||||
tools: {
|
||||
swc: { jsc: { transform: { decoratorMetadata: false } } },
|
||||
},
|
||||
lib: [
|
||||
{
|
||||
format: "esm",
|
||||
bundle: false,
|
||||
syntax: "es2021",
|
||||
dts: true,
|
||||
output: { target: "web", distPath: { root: "./dist" } },
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -1,8 +0,0 @@
|
||||
import { define } from "../../utils/registration/define";
|
||||
import { HacCard } from "./hac-card";
|
||||
import { TAG_NAME } from "./info";
|
||||
|
||||
// Registers <hac-card> in the global registry, as used by Home Assistant
|
||||
define(TAG_NAME, HacCard);
|
||||
|
||||
export { HacCard };
|
||||
@@ -1,165 +0,0 @@
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { property, state } from "lit/decorators.js";
|
||||
import {
|
||||
hasAssignedContent,
|
||||
hasAssignedElements,
|
||||
} from "../../utils/element/slot";
|
||||
|
||||
/**
|
||||
* @element hac-card
|
||||
*
|
||||
* @summary
|
||||
* Card that groups related content, with an optional header and footer.
|
||||
*
|
||||
* @slot header - Header of the card. Its spacing replaces the top padding of
|
||||
* the content.
|
||||
* @slot - Content of the card. Its padding is omitted when empty.
|
||||
* @slot footer - Footer of the card. Hidden when empty.
|
||||
*
|
||||
* @csspart header - Wrapper of the header slot.
|
||||
* @csspart content - Wrapper of the default slot.
|
||||
* @csspart footer - Wrapper of the footer slot.
|
||||
*
|
||||
* @cssprop --hac-card-background - Background of the card.
|
||||
* @cssprop --hac-card-color - Text color of the card.
|
||||
* @cssprop --hac-card-border-color - Border color of the card and the footer divider.
|
||||
* @cssprop --hac-card-border-width - Border width of the card.
|
||||
* @cssprop --hac-card-border-radius - Border radius of the card.
|
||||
* @cssprop --hac-card-box-shadow - Box shadow of the card.
|
||||
* @cssprop --hac-card-content-padding - Padding of the content.
|
||||
* @cssprop --hac-card-footer-padding - Padding of the footer.
|
||||
*/
|
||||
export class HacCard extends LitElement {
|
||||
/**
|
||||
* Visual style of the card. `outlined` draws a border without a shadow.
|
||||
* `raised` hides the border and lifts the card with a shadow instead.
|
||||
*/
|
||||
@property({ reflect: true }) public appearance: "outlined" | "raised" =
|
||||
"outlined";
|
||||
|
||||
@state() private _hasHeader = false;
|
||||
|
||||
@state() private _hasFooter = false;
|
||||
|
||||
@state() private _hasContent = false;
|
||||
|
||||
protected render() {
|
||||
return html`
|
||||
<div class="header" part="header" ?hidden=${!this._hasHeader}>
|
||||
<slot name="header" @slotchange=${this._headerChanged}></slot>
|
||||
</div>
|
||||
<div
|
||||
class="content ${this._hasHeader ? "below-header" : ""}"
|
||||
part="content"
|
||||
?hidden=${!this._hasContent}
|
||||
>
|
||||
<slot @slotchange=${this._contentChanged}></slot>
|
||||
</div>
|
||||
<div class="footer" part="footer" ?hidden=${!this._hasFooter}>
|
||||
<slot name="footer" @slotchange=${this._footerChanged}></slot>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
private _headerChanged(ev: Event) {
|
||||
this._hasHeader = hasAssignedElements(ev);
|
||||
}
|
||||
|
||||
private _contentChanged(ev: Event) {
|
||||
this._hasContent = hasAssignedContent(ev);
|
||||
}
|
||||
|
||||
private _footerChanged(ev: Event) {
|
||||
this._hasFooter = hasAssignedElements(ev);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fallback order: --hac-card-*, then the theme variables of ha-card
|
||||
* (--ha-card-*, --card-background-color, --divider-color,
|
||||
* --primary-text-color) so existing themes keep working, then the semantic
|
||||
* tokens and their light values for use outside Home Assistant.
|
||||
* The ha-card variables are temporary, see "Theming" in the README.
|
||||
*/
|
||||
static styles = css`
|
||||
:host {
|
||||
display: block;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
background: var(
|
||||
--hac-card-background,
|
||||
var(
|
||||
--ha-card-background,
|
||||
var(--card-background-color, var(--ha-color-surface-default, #fff))
|
||||
)
|
||||
);
|
||||
backdrop-filter: var(--ha-card-backdrop-filter, none);
|
||||
color: var(
|
||||
--hac-card-color,
|
||||
var(--primary-text-color, var(--ha-color-on-surface-default, #141414))
|
||||
);
|
||||
border: var(--hac-card-border-width, var(--ha-card-border-width, 1px))
|
||||
solid
|
||||
var(
|
||||
--hac-card-border-color,
|
||||
var(
|
||||
--ha-card-border-color,
|
||||
var(--divider-color, var(--ha-color-border-neutral-quiet, #e6e6e6))
|
||||
)
|
||||
);
|
||||
border-radius: var(
|
||||
--hac-card-border-radius,
|
||||
var(--ha-card-border-radius, var(--ha-border-radius-lg, 12px))
|
||||
);
|
||||
box-shadow: var(--hac-card-box-shadow, var(--ha-card-box-shadow, none));
|
||||
}
|
||||
|
||||
:host([appearance="raised"]) {
|
||||
border-color: transparent;
|
||||
box-shadow: var(
|
||||
--hac-card-box-shadow,
|
||||
var(
|
||||
--ha-card-box-shadow,
|
||||
var(
|
||||
--ha-box-shadow-s,
|
||||
0 1px 2px 0 rgba(0, 0, 0, 0.08),
|
||||
0 1px 3px 0 rgba(0, 0, 0, 0.12)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: var(--hac-card-content-padding, var(--ha-space-4, 16px));
|
||||
}
|
||||
|
||||
/* The header already provides the spacing above the content */
|
||||
.content.below-header {
|
||||
padding-block-start: 0;
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: var(--ha-space-2, 8px);
|
||||
padding: var(--hac-card-footer-padding, var(--ha-space-2, 8px));
|
||||
border-block-start: 1px solid
|
||||
var(
|
||||
--hac-card-border-color,
|
||||
var(--divider-color, var(--ha-color-border-neutral-quiet, #e6e6e6))
|
||||
);
|
||||
}
|
||||
|
||||
.header[hidden],
|
||||
.content[hidden],
|
||||
.footer[hidden] {
|
||||
display: none;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"hac-card": HacCard;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
/** Tag name of the element. */
|
||||
export const TAG_NAME = "hac-card";
|
||||
|
||||
/** Version of <hac-card>. */
|
||||
export const VERSION = "0.1.0";
|
||||
@@ -1,15 +0,0 @@
|
||||
import type { ElementDefinition } from "../../utils/registration/definition";
|
||||
import { HacCard } from "./hac-card";
|
||||
import { TAG_NAME } from "./info";
|
||||
|
||||
export { HacCard };
|
||||
|
||||
/**
|
||||
* The bundled <hac-card> for a scoped registry:
|
||||
* `ScopedElementsMixin(LitElement, [hacCard])` or
|
||||
* `createScopedElementRegistry([hacCard])`.
|
||||
*/
|
||||
export const hacCard: ElementDefinition<typeof HacCard> = {
|
||||
tagName: TAG_NAME,
|
||||
element: HacCard,
|
||||
};
|
||||
@@ -1,132 +0,0 @@
|
||||
import type { LitElement } from "lit";
|
||||
import { define } from "./utils/registration/define";
|
||||
import type { ElementDefinition } from "./utils/registration/definition";
|
||||
import {
|
||||
createScopedRegistry,
|
||||
scopedCreationScope,
|
||||
scopedRegistrySupport,
|
||||
scopedShadowRootInit,
|
||||
} from "./utils/registration/scoped-registry";
|
||||
|
||||
export type { ElementDefinition } from "./utils/registration/definition";
|
||||
|
||||
/**
|
||||
* Creates a registry with the given elements, for `attachScopedShadow`:
|
||||
* definitions from `scoped` entry points, e.g. `[hacCard]`.
|
||||
* Create it once, outside the class, so all instances of a card share it.
|
||||
*
|
||||
* Without scoped registry support (native or polyfill), the elements are
|
||||
* registered in the global registry instead, unless their tag name is already
|
||||
* taken there, and the global registry is returned.
|
||||
*/
|
||||
export const createScopedElementRegistry = (
|
||||
elements: readonly ElementDefinition[]
|
||||
): CustomElementRegistry => {
|
||||
// Checked as unknown: Array.isArray would narrow the list to any[]
|
||||
if (!Array.isArray(elements as unknown)) {
|
||||
throw new TypeError(
|
||||
"@home-assistant/components: pass the elements to register, e.g. [hacCard]"
|
||||
);
|
||||
}
|
||||
const registry = createScopedRegistry() ?? customElements;
|
||||
for (const { tagName, element } of elements) {
|
||||
define(tagName, element, registry);
|
||||
}
|
||||
return registry;
|
||||
};
|
||||
|
||||
const shadowRootInit = (
|
||||
init: ShadowRootInit,
|
||||
registry: CustomElementRegistry
|
||||
): ShadowRootInit =>
|
||||
registry === customElements ? init : scopedShadowRootInit(init, registry);
|
||||
|
||||
const registries = new WeakMap<ShadowRoot, CustomElementRegistry>();
|
||||
|
||||
/**
|
||||
* Attaches a shadow root that uses `registry` for custom elements in it.
|
||||
*
|
||||
* Content added with `innerHTML` or `insertAdjacentHTML` uses the registry.
|
||||
* Create single elements with `createScopedElement`; `document.createElement`
|
||||
* would use the global registry.
|
||||
*
|
||||
* Light DOM content, like slotted elements, keeps using the registry of the
|
||||
* tree it is written in.
|
||||
*/
|
||||
export const attachScopedShadow = (
|
||||
host: HTMLElement,
|
||||
init: ShadowRootInit,
|
||||
registry: CustomElementRegistry
|
||||
): ShadowRoot => {
|
||||
const root = host.attachShadow(shadowRootInit(init, registry));
|
||||
registries.set(root, registry);
|
||||
return root;
|
||||
};
|
||||
|
||||
/** Creates an element from the registry of a shadow root. */
|
||||
export const createScopedElement = <K extends keyof HTMLElementTagNameMap>(
|
||||
root: ShadowRoot,
|
||||
tagName: K
|
||||
): HTMLElementTagNameMap[K] => {
|
||||
const registry = registries.get(root);
|
||||
if (!registry || registry === customElements) {
|
||||
return document.createElement(tagName);
|
||||
}
|
||||
if (scopedRegistrySupport() === "polyfill") {
|
||||
// The polyfill adds createElement to shadow roots
|
||||
return (
|
||||
root as unknown as {
|
||||
createElement(tagName: K): HTMLElementTagNameMap[K];
|
||||
}
|
||||
).createElement(tagName);
|
||||
}
|
||||
return (
|
||||
document.createElement as (
|
||||
tagName: K,
|
||||
options: { customElementRegistry: CustomElementRegistry }
|
||||
) => HTMLElementTagNameMap[K]
|
||||
)(tagName, { customElementRegistry: registry });
|
||||
};
|
||||
|
||||
type LitElementConstructor = abstract new (...args: any[]) => LitElement;
|
||||
|
||||
/**
|
||||
* Renders a Lit element into a shadow root with its own custom element
|
||||
* registry, containing `elements`:
|
||||
*
|
||||
* ```ts
|
||||
* class MyCard extends ScopedElementsMixin(LitElement, [hacCard]) {}
|
||||
* ```
|
||||
*
|
||||
* See `createScopedElementRegistry` and `attachScopedShadow` for the details.
|
||||
*/
|
||||
export const ScopedElementsMixin = <T extends LitElementConstructor>(
|
||||
superClass: T,
|
||||
elements: readonly ElementDefinition[]
|
||||
) => {
|
||||
// Created on first use, so defining the class has no side effects
|
||||
let registry: CustomElementRegistry | undefined;
|
||||
const getRegistry = () => {
|
||||
registry ??= createScopedElementRegistry(elements);
|
||||
return registry;
|
||||
};
|
||||
|
||||
abstract class ScopedElementsHost extends superClass {
|
||||
public attachShadow(init: ShadowRootInit): ShadowRoot {
|
||||
const root = super.attachShadow(shadowRootInit(init, getRegistry()));
|
||||
registries.set(root, getRegistry());
|
||||
return root;
|
||||
}
|
||||
|
||||
protected createRenderRoot() {
|
||||
const root = super.createRenderRoot();
|
||||
const scoped = getRegistry();
|
||||
if (scoped !== customElements && root instanceof ShadowRoot) {
|
||||
this.renderOptions.creationScope = scopedCreationScope(root, scoped);
|
||||
}
|
||||
return root;
|
||||
}
|
||||
}
|
||||
// Typed as the base class: the overrides add no public API
|
||||
return ScopedElementsHost as unknown as T;
|
||||
};
|
||||
@@ -1,15 +0,0 @@
|
||||
/** Whether the slot of a `slotchange` event has elements assigned. */
|
||||
export const hasAssignedElements = (ev: Event): boolean =>
|
||||
(ev.target as HTMLSlotElement).assignedElements().length > 0;
|
||||
|
||||
/**
|
||||
* Whether the slot of a `slotchange` event has content assigned: elements or
|
||||
* text. Whitespace between tags is not content.
|
||||
*/
|
||||
export const hasAssignedContent = (ev: Event): boolean =>
|
||||
(ev.target as HTMLSlotElement)
|
||||
.assignedNodes()
|
||||
.some(
|
||||
(node) =>
|
||||
node.nodeType === Node.ELEMENT_NODE || Boolean(node.textContent?.trim())
|
||||
);
|
||||
@@ -1,17 +0,0 @@
|
||||
/**
|
||||
* Registers a custom element unless the tag name is already taken in the
|
||||
* registry.
|
||||
*
|
||||
* Home Assistant and custom cards can each ship a copy of this library, so
|
||||
* registering the same tag name twice must not throw. The first registration
|
||||
* wins.
|
||||
*/
|
||||
export const define = (
|
||||
tagName: string,
|
||||
elementClass: CustomElementConstructor,
|
||||
registry: CustomElementRegistry = customElements
|
||||
): void => {
|
||||
if (!registry.get(tagName)) {
|
||||
registry.define(tagName, elementClass);
|
||||
}
|
||||
};
|
||||
@@ -1,10 +0,0 @@
|
||||
/**
|
||||
* An element to register: its tag name and its class. The `scoped` entry
|
||||
* point of an element exports one, e.g. `hacCard`.
|
||||
*/
|
||||
export interface ElementDefinition<
|
||||
E extends CustomElementConstructor = CustomElementConstructor,
|
||||
> {
|
||||
readonly tagName: string;
|
||||
readonly element: E;
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
/**
|
||||
* Scoped custom element registries come in two flavors: the standard API
|
||||
* (Chrome 146+, Safari 26) and the older API of
|
||||
* `@webcomponents/scoped-custom-element-registry`, which Home Assistant loads
|
||||
* and which replaces the native implementation when present.
|
||||
*/
|
||||
export type ScopedRegistrySupport = "polyfill" | "native" | "none";
|
||||
|
||||
let support: ScopedRegistrySupport | undefined;
|
||||
|
||||
export const scopedRegistrySupport = (): ScopedRegistrySupport => {
|
||||
if (support) {
|
||||
return support;
|
||||
}
|
||||
if ("CustomElementRegistryPolyfill" in globalThis) {
|
||||
support = "polyfill";
|
||||
} else {
|
||||
try {
|
||||
new CustomElementRegistry();
|
||||
support = "native";
|
||||
} catch (_err) {
|
||||
support = "none";
|
||||
}
|
||||
}
|
||||
return support;
|
||||
};
|
||||
|
||||
/** A new scoped registry, or `undefined` if the browser has no support. */
|
||||
export const createScopedRegistry = (): CustomElementRegistry | undefined =>
|
||||
scopedRegistrySupport() === "none" ? undefined : new CustomElementRegistry();
|
||||
|
||||
/** Shadow root options that make the shadow root use `registry`. */
|
||||
export const scopedShadowRootInit = (
|
||||
init: ShadowRootInit,
|
||||
registry: CustomElementRegistry
|
||||
): ShadowRootInit =>
|
||||
scopedRegistrySupport() === "polyfill"
|
||||
? ({ ...init, registry } as ShadowRootInit)
|
||||
: ({ ...init, customElementRegistry: registry } as ShadowRootInit);
|
||||
|
||||
interface CreationScope {
|
||||
importNode(node: Node, deep?: boolean): Node;
|
||||
}
|
||||
|
||||
/**
|
||||
* The object Lit should create template content with, so custom elements in
|
||||
* it are created from the scoped registry (Lit's `creationScope`).
|
||||
*/
|
||||
export const scopedCreationScope = (
|
||||
root: ShadowRoot,
|
||||
registry: CustomElementRegistry
|
||||
): CreationScope => {
|
||||
if (scopedRegistrySupport() === "polyfill") {
|
||||
// The polyfill adds importNode to shadow roots
|
||||
return root as unknown as CreationScope;
|
||||
}
|
||||
// Standard API: the registry is passed to importNode
|
||||
return {
|
||||
importNode: (node, deep) =>
|
||||
(
|
||||
document.importNode as (
|
||||
node: Node,
|
||||
options: { selfOnly: boolean; customElementRegistry: unknown }
|
||||
) => Node
|
||||
)(node, { selfOnly: !deep, customElementRegistry: registry }),
|
||||
};
|
||||
};
|
||||
@@ -1,20 +0,0 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { define } from "../src/utils/registration/define";
|
||||
|
||||
// Home Assistant and custom cards can each ship a copy of the library, so a
|
||||
// second registration of the same tag must be ignored instead of throwing.
|
||||
describe("define", () => {
|
||||
it("registers an element that is not registered yet", () => {
|
||||
class First extends HTMLElement {}
|
||||
define("hac-test-first", First);
|
||||
expect(customElements.get("hac-test-first")).toBe(First);
|
||||
});
|
||||
|
||||
it("keeps the first registration of a tag name", () => {
|
||||
class Original extends HTMLElement {}
|
||||
class Duplicate extends HTMLElement {}
|
||||
define("hac-test-duplicate", Original);
|
||||
expect(() => define("hac-test-duplicate", Duplicate)).not.toThrow();
|
||||
expect(customElements.get("hac-test-duplicate")).toBe(Original);
|
||||
});
|
||||
});
|
||||
@@ -1,40 +0,0 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
hasAssignedContent,
|
||||
hasAssignedElements,
|
||||
} from "../src/utils/element/slot";
|
||||
|
||||
// Components hide wrappers of empty slots, e.g. the padding of an empty card.
|
||||
// Whitespace between tags must not count as content.
|
||||
const slotEvent = (light: string, name?: string) => {
|
||||
const host = document.createElement("div");
|
||||
host.innerHTML = light;
|
||||
const slot = document.createElement("slot");
|
||||
if (name) {
|
||||
slot.name = name;
|
||||
}
|
||||
host.attachShadow({ mode: "open" }).append(slot);
|
||||
return { target: slot } as unknown as Event;
|
||||
};
|
||||
|
||||
describe("hasAssignedContent", () => {
|
||||
it("ignores whitespace", () => {
|
||||
expect(hasAssignedContent(slotEvent("\n \n"))).toBe(false);
|
||||
});
|
||||
|
||||
it("counts text", () => {
|
||||
expect(hasAssignedContent(slotEvent(" Hello "))).toBe(true);
|
||||
});
|
||||
|
||||
it("counts elements", () => {
|
||||
expect(hasAssignedContent(slotEvent("\n <p></p>\n"))).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("hasAssignedElements", () => {
|
||||
it("only counts elements assigned to the slot", () => {
|
||||
const light = '<span slot="icon"></span> text';
|
||||
expect(hasAssignedElements(slotEvent(light, "icon"))).toBe(true);
|
||||
expect(hasAssignedElements(slotEvent(light, "actions"))).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -1,20 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2021",
|
||||
"lib": ["ES2021", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"experimentalDecorators": true,
|
||||
"useDefineForClassFields": false,
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noImplicitReturns": true,
|
||||
"isolatedModules": true,
|
||||
"skipLibCheck": true,
|
||||
"declaration": true,
|
||||
"rootDir": "src",
|
||||
"outDir": "dist"
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
Generated
+41
-700
File diff suppressed because it is too large.
Load diff
@@ -1,7 +1,3 @@
|
||||
packages:
|
||||
- "."
|
||||
- "packages/*"
|
||||
|
||||
savePrefix: ""
|
||||
autoInstallPeers: false
|
||||
|
||||
@@ -23,7 +19,6 @@ trustPolicyExclude:
|
||||
allowBuilds:
|
||||
"@tsparticles/engine": false
|
||||
core-js: false
|
||||
rs-module-lexer: false
|
||||
unrs-resolver: false
|
||||
|
||||
overrides:
|
||||
|
||||
@@ -112,6 +112,9 @@ export class HaGenericPicker extends PickerMixin(LitElement) {
|
||||
|
||||
@property({ type: Boolean, attribute: "no-sort" }) public noSort = false;
|
||||
|
||||
@property({ attribute: "pin-block" })
|
||||
public pinBlock?: "start" | "center" | "end" | "nearest";
|
||||
|
||||
// Skip the "unknown value" highlight and note for a value that is not in the
|
||||
// list but that the value renderer presents on its own.
|
||||
@property({ type: Boolean, attribute: "no-unknown-state" })
|
||||
@@ -347,6 +350,7 @@ export class HaGenericPicker extends PickerMixin(LitElement) {
|
||||
.searchKeys=${this.searchKeys}
|
||||
.customValueLabel=${this.customValueLabel}
|
||||
.noSort=${this.noSort}
|
||||
.pinBlock=${this.pinBlock}
|
||||
></ha-picker-combo-box>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
import type { RenderItemFunction } from "@lit-labs/virtualizer/virtualize";
|
||||
import type { TemplateResult } from "lit";
|
||||
import type { PropertyValues, TemplateResult } from "lit";
|
||||
import { LitElement, css, html } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { consumeLocalize } from "../common/decorators/consume-context-entry";
|
||||
import { fireEvent } from "../common/dom/fire_event";
|
||||
import { caseInsensitiveStringCompare } from "../common/string/compare";
|
||||
import type { LocalizeFunc } from "../common/translations/localize";
|
||||
import { customIcons } from "../data/custom_icons";
|
||||
import type { ValueChangedEvent } from "../types";
|
||||
import "./ha-combo-box-item";
|
||||
import "./ha-generic-picker";
|
||||
import type { HaGenericPicker } from "./ha-generic-picker";
|
||||
import "./ha-icon";
|
||||
import type { PickerComboBoxItem } from "./ha-picker-combo-box";
|
||||
|
||||
@@ -50,16 +54,17 @@ const createIconItem = (icon: IconData, prefix: string): PickerComboBoxItem => {
|
||||
const loadIcons = async () => {
|
||||
ICONS_LOADED = true;
|
||||
|
||||
const iconList = await import("../../build/mdi/iconList.json");
|
||||
ICONS = iconList.default.map((icon) => createIconItem(icon, "mdi"));
|
||||
const sortIcons = (icons: PickerComboBoxItem[]) =>
|
||||
icons.sort((a, b) => caseInsensitiveStringCompare(a.id, b.id));
|
||||
|
||||
const customIconLoads: Promise<PickerComboBoxItem[]>[] = [];
|
||||
Object.keys(customIcons).forEach((iconSet) => {
|
||||
customIconLoads.push(loadCustomIconItems(iconSet));
|
||||
});
|
||||
(await Promise.all(customIconLoads)).forEach((customIconItems) => {
|
||||
ICONS.push(...customIconItems);
|
||||
});
|
||||
const iconList = await import("../../build/mdi/iconList.json");
|
||||
const mdiIcons = iconList.default.map((icon) => createIconItem(icon, "mdi"));
|
||||
ICONS = sortIcons([...mdiIcons]);
|
||||
|
||||
const customIconItems = await Promise.all(
|
||||
Object.keys(customIcons).map(loadCustomIconItems)
|
||||
);
|
||||
ICONS = sortIcons([...mdiIcons, ...customIconItems.flat()]);
|
||||
};
|
||||
|
||||
const loadCustomIconItems = async (
|
||||
@@ -81,8 +86,8 @@ const loadCustomIconItems = async (
|
||||
|
||||
const rowRenderer: RenderItemFunction<PickerComboBoxItem> = (item) => html`
|
||||
<ha-combo-box-item>
|
||||
<ha-icon .icon=${item.id} slot="start"></ha-icon>
|
||||
${item.id}
|
||||
<ha-icon .icon=${item.icon ?? item.id} slot="start"></ha-icon>
|
||||
${item.icon ?? item.id}
|
||||
</ha-combo-box-item>
|
||||
`;
|
||||
|
||||
@@ -104,12 +109,32 @@ export class HaIconPicker extends LitElement {
|
||||
|
||||
@property({ type: Boolean }) public invalid = false;
|
||||
|
||||
private _getIconPickerItems = (): PickerComboBoxItem[] => ICONS;
|
||||
@property({ attribute: false }) public suggestedIcons?: string[];
|
||||
|
||||
@state() @consumeLocalize() private _localize!: LocalizeFunc;
|
||||
|
||||
@query("ha-generic-picker") private _picker?: HaGenericPicker;
|
||||
|
||||
private _getIconPickerItems = () =>
|
||||
this._itemsWithSuggestions(ICONS, this.suggestedIcons, this._localize);
|
||||
|
||||
protected updated(changedProps: PropertyValues) {
|
||||
super.updated(changedProps);
|
||||
if (changedProps.has("suggestedIcons") || changedProps.has("_localize")) {
|
||||
this._picker?.refreshItems();
|
||||
}
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<ha-generic-picker
|
||||
allow-custom-value
|
||||
no-sort
|
||||
.pinBlock=${
|
||||
this.value && this.suggestedIcons?.includes(this.value)
|
||||
? "end"
|
||||
: undefined
|
||||
}
|
||||
.getItems=${this._getIconPickerItems}
|
||||
.helper=${this.helper}
|
||||
.disabled=${this.disabled}
|
||||
@@ -128,15 +153,35 @@ export class HaIconPicker extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private _itemsWithSuggestions = memoizeOne(
|
||||
(
|
||||
icons: PickerComboBoxItem[],
|
||||
suggestedIcons: string[] | undefined,
|
||||
localize: LocalizeFunc
|
||||
): (PickerComboBoxItem | string)[] => {
|
||||
if (!suggestedIcons?.length) {
|
||||
return icons;
|
||||
}
|
||||
const suggested = new Set(suggestedIcons);
|
||||
return [
|
||||
localize("ui.components.icon_picker.suggested"),
|
||||
...suggestedIcons.map((icon) => ({ id: icon, primary: icon, icon })),
|
||||
localize("ui.components.icon_picker.all_icons"),
|
||||
...icons.filter((item) => !suggested.has(item.id)),
|
||||
];
|
||||
}
|
||||
);
|
||||
|
||||
// Filter can take a significant chunk of frame (up to 3-5 ms)
|
||||
private _filterIcons = memoizeOne(
|
||||
(
|
||||
filter: string,
|
||||
filteredItems: PickerComboBoxItem[],
|
||||
allItems: PickerComboBoxItem[]
|
||||
_allItems: PickerComboBoxItem[]
|
||||
): PickerComboBoxItem[] => {
|
||||
const normalizedFilter = filter.toLowerCase().replace(/\s+/g, "-");
|
||||
const iconItems = allItems?.length ? allItems : filteredItems;
|
||||
// The full list also holds the suggestions and their section titles
|
||||
const iconItems = ICONS.length ? ICONS : filteredItems;
|
||||
|
||||
if (!normalizedFilter.length) {
|
||||
return iconItems;
|
||||
@@ -175,8 +220,7 @@ export class HaIconPicker extends LitElement {
|
||||
protected firstUpdated() {
|
||||
if (!ICONS_LOADED) {
|
||||
loadIcons().then(() => {
|
||||
this._getIconPickerItems = (): PickerComboBoxItem[] => ICONS;
|
||||
this.requestUpdate();
|
||||
this._picker?.refreshItems();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,6 +201,9 @@ export class HaPickerComboBox extends ScrollableFadeMixin(LitElement) {
|
||||
|
||||
@property({ type: Boolean, attribute: "no-sort" }) public noSort = false;
|
||||
|
||||
@property({ attribute: "pin-block" })
|
||||
public pinBlock?: "start" | "center" | "end" | "nearest";
|
||||
|
||||
@query(".list") private _list?: HaListBase;
|
||||
|
||||
@query("ha-input-search") private _searchFieldElement?: HaInputSearch;
|
||||
@@ -453,6 +456,7 @@ export class HaPickerComboBox extends ScrollableFadeMixin(LitElement) {
|
||||
this.value
|
||||
)}
|
||||
.pinIndex=${this.value ? this._getInitialSelectedIndex() : undefined}
|
||||
.pinBlock=${this.pinBlock ?? "center"}
|
||||
@mousedown=${this._preventBlur}
|
||||
@focus=${this._focusList}
|
||||
@blur=${this._resetSelectedItem}
|
||||
@@ -685,6 +689,11 @@ export class HaPickerComboBox extends ScrollableFadeMixin(LitElement) {
|
||||
fireEvent(this, "index-selected", { index, item, newTab });
|
||||
}
|
||||
|
||||
// Fuse indexes every row as text when the first one is a section title
|
||||
private _searchableItems = memoizeOne((items: PickerComboBoxItem[]) =>
|
||||
items.filter((item) => typeof item !== "string")
|
||||
);
|
||||
|
||||
private _fuseIndex = memoizeOne(
|
||||
(states: PickerComboBoxItem[], searchKeys?: FuseWeightedKey[]) =>
|
||||
Fuse.createIndex(searchKeys || DEFAULT_SEARCH_KEYS, states)
|
||||
@@ -708,10 +717,11 @@ export class HaPickerComboBox extends ScrollableFadeMixin(LitElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
const index = this._fuseIndex(this._allItems, this.searchKeys);
|
||||
const searchableItems = this._searchableItems(this._allItems);
|
||||
const index = this._fuseIndex(searchableItems, this.searchKeys);
|
||||
|
||||
let filteredItems = multiTermSortedSearch<PickerComboBoxItem>(
|
||||
this._allItems,
|
||||
searchableItems,
|
||||
searchString,
|
||||
(item) => item.id,
|
||||
index
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["sitkamer", "woonkamer", "leefarea", "gesinskamer"],
|
||||
"bedroom": ["slaapkamer", "gastekamer", "hoofslaapkamer"],
|
||||
"kids_room": ["kinderkamer", "speelkamer", "babakamer"],
|
||||
"kitchen": ["kombuis"],
|
||||
"dining_room": ["eetkamer"],
|
||||
"bathroom": ["badkamer", "stort"],
|
||||
"toilet": ["toilet", "wc", "kleinhuisie"],
|
||||
"office": ["kantoor", "studeerkamer", "tuiskantoor"],
|
||||
"laundry_room": ["waskamer", "opwasplek"],
|
||||
"hallway": ["gang", "portaal", "ingang"],
|
||||
"stairs": ["trap"],
|
||||
"garage": ["motorhuis", "garage", "afdak"],
|
||||
"garden": ["tuin", "erf", "grasperk", "kweekhuis"],
|
||||
"terrace": ["stoep", "balkon", "terras", "patio", "veranda"],
|
||||
"basement": ["kelder"],
|
||||
"attic": ["solder"],
|
||||
"storage": ["stoorkamer", "pakkamer", "spens"],
|
||||
"utility_room": ["tegniese kamer"],
|
||||
"gym": ["gimnasium", "oefenkamer"],
|
||||
"pool": ["swembad"],
|
||||
"home_cinema": ["tuisteater"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["غرفة المعيشة", "الصالة", "صالة", "المجلس", "مجلس"],
|
||||
"bedroom": ["غرفة النوم", "غرفة نوم", "غرفة الضيوف"],
|
||||
"kids_room": ["غرفة الأطفال", "غرفة الاطفال", "غرفة الألعاب"],
|
||||
"kitchen": ["المطبخ", "مطبخ"],
|
||||
"dining_room": ["غرفة الطعام", "غرفة السفرة", "السفرة"],
|
||||
"bathroom": ["الحمام", "حمام", "دش"],
|
||||
"toilet": ["المرحاض", "دورة المياه", "wc"],
|
||||
"office": ["المكتب", "مكتب", "غرفة المكتب"],
|
||||
"laundry_room": ["غرفة الغسيل"],
|
||||
"hallway": ["الممر", "ممر", "المدخل", "مدخل", "الردهة"],
|
||||
"stairs": ["الدرج", "درج", "السلالم"],
|
||||
"garage": ["المرآب", "الكراج", "كراج"],
|
||||
"garden": ["الحديقة", "حديقة", "الفناء", "الحوش"],
|
||||
"terrace": ["الشرفة", "شرفة", "التراس", "البلكونة", "السطح"],
|
||||
"basement": ["القبو", "قبو", "السرداب"],
|
||||
"attic": ["العلية", "السندرة"],
|
||||
"storage": ["المخزن", "مخزن", "غرفة التخزين"],
|
||||
"utility_room": ["غرفة الغلاية", "الغرفة الفنية"],
|
||||
"gym": ["صالة الرياضة", "الجيم", "جيم"],
|
||||
"pool": ["المسبح", "مسبح"],
|
||||
"home_cinema": ["السينما المنزلية", "سينما منزلية"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["всекидневна", "хол", "дневна"],
|
||||
"bedroom": ["спалня", "стая за гости"],
|
||||
"kids_room": ["детска стая", "детска"],
|
||||
"kitchen": ["кухня"],
|
||||
"dining_room": ["трапезария"],
|
||||
"bathroom": ["баня", "душ"],
|
||||
"toilet": ["тоалетна", "wc"],
|
||||
"office": ["офис", "кабинет"],
|
||||
"laundry_room": ["перално помещение"],
|
||||
"hallway": ["коридор", "антре", "входно антре"],
|
||||
"stairs": ["стълби", "стълбище"],
|
||||
"garage": ["гараж"],
|
||||
"garden": ["градина", "двор", "морава", "оранжерия"],
|
||||
"terrace": ["тераса", "балкон", "веранда"],
|
||||
"basement": ["мазе", "сутерен"],
|
||||
"attic": ["таван", "мансарда"],
|
||||
"storage": ["килер", "склад", "барака"],
|
||||
"utility_room": ["котелно", "техническо помещение"],
|
||||
"gym": ["фитнес"],
|
||||
"pool": ["басейн"],
|
||||
"home_cinema": ["домашно кино"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["বসার ঘর", "বৈঠকখানা", "ড্রয়িং রুম"],
|
||||
"bedroom": ["শোবার ঘর", "শয়নকক্ষ", "বেডরুম", "অতিথি কক্ষ"],
|
||||
"kids_room": ["বাচ্চাদের ঘর", "শিশুদের ঘর"],
|
||||
"kitchen": ["রান্নাঘর", "কিচেন"],
|
||||
"dining_room": ["খাবার ঘর", "ডাইনিং রুম"],
|
||||
"bathroom": ["স্নানঘর", "বাথরুম", "গোসলখানা"],
|
||||
"toilet": ["শৌচাগার", "টয়লেট", "wc"],
|
||||
"office": ["অফিস", "পড়ার ঘর"],
|
||||
"laundry_room": ["লন্ড্রি"],
|
||||
"hallway": ["বারান্দা", "করিডোর", "প্রবেশপথ"],
|
||||
"stairs": ["সিঁড়ি"],
|
||||
"garage": ["গ্যারেজ"],
|
||||
"garden": ["বাগান", "উঠান", "লন"],
|
||||
"terrace": ["ছাদ", "ব্যালকনি"],
|
||||
"basement": ["বেসমেন্ট", "ভূগর্ভস্থ ঘর"],
|
||||
"attic": ["চিলেকোঠা"],
|
||||
"storage": ["ভাঁড়ার", "স্টোর রুম", "গুদাম"],
|
||||
"utility_room": ["ইউটিলিটি রুম"],
|
||||
"gym": ["জিম", "ব্যায়ামাগার"],
|
||||
"pool": ["সুইমিং পুল"],
|
||||
"home_cinema": ["হোম থিয়েটার"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["dnevni boravak", "dnevna soba"],
|
||||
"bedroom": ["spavaća soba", "soba za goste"],
|
||||
"kids_room": ["dječija soba", "igraonica"],
|
||||
"kitchen": ["kuhinja"],
|
||||
"dining_room": ["trpezarija"],
|
||||
"bathroom": ["kupatilo", "tuš"],
|
||||
"toilet": ["wc", "toalet"],
|
||||
"office": ["kancelarija", "radna soba"],
|
||||
"laundry_room": ["vešeraj"],
|
||||
"hallway": ["hodnik", "predsoblje", "ulaz"],
|
||||
"stairs": ["stepenice", "stepenište"],
|
||||
"garage": ["garaža"],
|
||||
"garden": ["bašta", "vrt", "dvorište", "travnjak", "plastenik"],
|
||||
"terrace": ["terasa", "balkon"],
|
||||
"basement": ["podrum"],
|
||||
"attic": ["tavan", "potkrovlje"],
|
||||
"storage": ["ostava", "špajz", "šupa"],
|
||||
"utility_room": ["kotlovnica"],
|
||||
"gym": ["teretana"],
|
||||
"pool": ["bazen"],
|
||||
"home_cinema": ["kućni kino"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["sala destar", "saló", "sala"],
|
||||
"bedroom": ["dormitori", "habitació", "habitació de convidats"],
|
||||
"kids_room": ["habitació dels nens", "habitació infantil", "sala de jocs"],
|
||||
"kitchen": ["cuina"],
|
||||
"dining_room": ["menjador"],
|
||||
"bathroom": ["bany", "cambra de bany", "dutxa"],
|
||||
"toilet": ["lavabo", "vàter", "wc"],
|
||||
"office": ["despatx", "oficina", "estudi"],
|
||||
"laundry_room": ["safareig", "bugaderia"],
|
||||
"hallway": ["passadís", "rebedor", "entrada", "vestíbul"],
|
||||
"stairs": ["escala", "escales"],
|
||||
"garage": ["garatge"],
|
||||
"garden": ["jardí", "pati", "gespa", "hivernacle", "hort"],
|
||||
"terrace": ["terrassa", "balcó", "porxo"],
|
||||
"basement": ["soterrani", "celler"],
|
||||
"attic": ["golfes", "àtic"],
|
||||
"storage": ["traster", "rebost", "magatzem"],
|
||||
"utility_room": ["sala tècnica", "sala de calderes"],
|
||||
"gym": ["gimnàs"],
|
||||
"pool": ["piscina"],
|
||||
"home_cinema": ["cinema a casa", "sala de cinema"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["obývák", "obývací pokoj", "obývací místnost"],
|
||||
"bedroom": ["ložnice", "pokoj pro hosty"],
|
||||
"kids_room": ["dětský pokoj", "herna"],
|
||||
"kitchen": ["kuchyně", "kuchyňský kout"],
|
||||
"dining_room": ["jídelna"],
|
||||
"bathroom": ["koupelna", "sprcha"],
|
||||
"toilet": ["toaleta", "wc", "záchod"],
|
||||
"office": ["pracovna", "kancelář"],
|
||||
"laundry_room": ["prádelna"],
|
||||
"hallway": ["chodba", "předsíň", "hala", "zádveří"],
|
||||
"stairs": ["schody", "schodiště"],
|
||||
"garage": ["garáž"],
|
||||
"garden": ["zahrada", "trávník", "skleník"],
|
||||
"terrace": ["terasa", "balkon", "veranda"],
|
||||
"basement": ["sklep", "suterén"],
|
||||
"attic": ["půda", "podkroví"],
|
||||
"storage": ["sklad", "spíž", "komora", "kůlna"],
|
||||
"utility_room": ["technická místnost", "kotelna"],
|
||||
"gym": ["posilovna", "fitness"],
|
||||
"pool": ["bazén"],
|
||||
"home_cinema": ["domácí kino"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["lolfa", "ystafell fyw", "parlwr"],
|
||||
"bedroom": ["ystafell wely", "llofft"],
|
||||
"kids_room": ["ystafell y plant", "meithrinfa"],
|
||||
"kitchen": ["cegin"],
|
||||
"dining_room": ["ystafell fwyta"],
|
||||
"bathroom": ["ystafell ymolchi", "cawod"],
|
||||
"toilet": ["toiled", "tŷ bach", "wc"],
|
||||
"office": ["swyddfa", "stydi"],
|
||||
"laundry_room": ["golchdy"],
|
||||
"hallway": ["cyntedd", "coridor", "mynedfa"],
|
||||
"stairs": ["grisiau"],
|
||||
"garage": ["garej", "modurdy"],
|
||||
"garden": ["gardd", "iard", "lawnt", "tŷ gwydr"],
|
||||
"terrace": ["teras", "balconi", "patio"],
|
||||
"basement": ["seler", "islawr"],
|
||||
"attic": ["atig", "croglofft"],
|
||||
"storage": ["storfa", "pantri", "sied"],
|
||||
"utility_room": ["ystafell beiriannau"],
|
||||
"gym": ["campfa"],
|
||||
"pool": ["pwll nofio", "pwll"],
|
||||
"home_cinema": ["sinema cartref"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["stue", "opholdsstue", "dagligstue", "alrum"],
|
||||
"bedroom": ["soveværelse", "gæsteværelse", "sovekammer"],
|
||||
"kids_room": ["børneværelse", "legeværelse"],
|
||||
"kitchen": ["køkken", "køkkenalrum"],
|
||||
"dining_room": ["spisestue"],
|
||||
"bathroom": ["badeværelse", "bad", "bruserum"],
|
||||
"toilet": ["toilet", "wc", "gæstetoilet"],
|
||||
"office": ["kontor", "arbejdsværelse", "hjemmekontor"],
|
||||
"laundry_room": ["bryggers", "vaskerum"],
|
||||
"hallway": ["gang", "entré", "entre", "hall", "gangen"],
|
||||
"stairs": ["trappe", "trappeopgang"],
|
||||
"garage": ["garage", "carport"],
|
||||
"garden": ["have", "græsplæne", "drivhus"],
|
||||
"terrace": ["terrasse", "altan", "balkon", "veranda"],
|
||||
"basement": ["kælder"],
|
||||
"attic": ["loft", "loftsrum"],
|
||||
"storage": ["depot", "skur", "viktualierum", "opbevaring"],
|
||||
"utility_room": ["teknikrum", "fyrrum"],
|
||||
"gym": ["træningsrum", "motionsrum"],
|
||||
"pool": ["pool", "svømmebassin"],
|
||||
"home_cinema": ["hjemmebiograf", "biografrum"]
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"living_room": ["wohnzimmer", "stube", "wohnbereich", "wohnraum"],
|
||||
"bedroom": ["schlafzimmer", "gästezimmer", "elternschlafzimmer"],
|
||||
"kids_room": ["kinderzimmer", "babyzimmer", "spielzimmer"],
|
||||
"kitchen": ["küche", "kochnische", "wohnküche"],
|
||||
"dining_room": ["esszimmer", "essbereich"],
|
||||
"bathroom": ["badezimmer", "bad", "dusche", "duschbad"],
|
||||
"toilet": ["toilette", "wc", "gäste wc", "klo"],
|
||||
"office": ["büro", "arbeitszimmer", "homeoffice", "home office"],
|
||||
"laundry_room": ["waschküche", "waschraum", "hauswirtschaftsraum"],
|
||||
"hallway": [
|
||||
"flur",
|
||||
"diele",
|
||||
"gang",
|
||||
"eingang",
|
||||
"eingangsbereich",
|
||||
"korridor"
|
||||
],
|
||||
"stairs": ["treppe", "treppenhaus"],
|
||||
"garage": ["garage", "carport"],
|
||||
"garden": ["garten", "rasen", "vorgarten", "gewächshaus"],
|
||||
"terrace": ["terrasse", "balkon", "veranda", "wintergarten"],
|
||||
"basement": ["keller", "untergeschoss"],
|
||||
"attic": ["dachboden", "speicher", "dachgeschoss"],
|
||||
"storage": [
|
||||
"abstellraum",
|
||||
"abstellkammer",
|
||||
"lager",
|
||||
"vorratskammer",
|
||||
"speisekammer",
|
||||
"schuppen",
|
||||
"gartenhaus"
|
||||
],
|
||||
"utility_room": ["technikraum", "heizungsraum", "heizraum", "serverraum"],
|
||||
"gym": ["fitnessraum", "fitnessstudio", "sportraum"],
|
||||
"pool": ["pool", "schwimmbad", "schwimmbecken"],
|
||||
"home_cinema": ["heimkino", "kinoraum", "fernsehzimmer"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["σαλόνι", "καθιστικό"],
|
||||
"bedroom": ["υπνοδωμάτιο", "κρεβατοκάμαρα", "ξενώνας"],
|
||||
"kids_room": ["παιδικό δωμάτιο", "παιδικό"],
|
||||
"kitchen": ["κουζίνα"],
|
||||
"dining_room": ["τραπεζαρία"],
|
||||
"bathroom": ["μπάνιο", "λουτρό", "ντους"],
|
||||
"toilet": ["τουαλέτα", "wc"],
|
||||
"office": ["γραφείο"],
|
||||
"laundry_room": ["πλυσταριό"],
|
||||
"hallway": ["διάδρομος", "χολ", "είσοδος"],
|
||||
"stairs": ["σκάλα", "σκάλες", "κλιμακοστάσιο"],
|
||||
"garage": ["γκαράζ"],
|
||||
"garden": ["κήπος", "αυλή", "γκαζόν", "θερμοκήπιο"],
|
||||
"terrace": ["ταράτσα", "βεράντα", "μπαλκόνι"],
|
||||
"basement": ["υπόγειο", "κελάρι"],
|
||||
"attic": ["σοφίτα"],
|
||||
"storage": ["αποθήκη", "αποθηκευτικός χώρος"],
|
||||
"utility_room": ["λεβητοστάσιο", "μηχανοστάσιο"],
|
||||
"gym": ["γυμναστήριο"],
|
||||
"pool": ["πισίνα"],
|
||||
"home_cinema": ["οικιακός κινηματογράφος"]
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"living_room": [
|
||||
"living room",
|
||||
"lounge",
|
||||
"family room",
|
||||
"sitting room",
|
||||
"den",
|
||||
"living"
|
||||
],
|
||||
"bedroom": [
|
||||
"bedroom",
|
||||
"guest room",
|
||||
"master bedroom",
|
||||
"master suite",
|
||||
"bed room"
|
||||
],
|
||||
"kids_room": [
|
||||
"kids room",
|
||||
"childrens room",
|
||||
"nursery",
|
||||
"playroom",
|
||||
"baby room"
|
||||
],
|
||||
"kitchen": ["kitchen", "kitchenette"],
|
||||
"dining_room": ["dining room", "dining area", "dining"],
|
||||
"bathroom": ["bathroom", "bath", "shower room", "ensuite", "washroom"],
|
||||
"toilet": ["toilet", "wc", "restroom", "powder room", "loo", "lavatory"],
|
||||
"office": ["office", "study", "home office", "workspace", "workroom"],
|
||||
"laundry_room": ["laundry", "laundry room"],
|
||||
"hallway": [
|
||||
"hallway",
|
||||
"hall",
|
||||
"corridor",
|
||||
"entrance",
|
||||
"entryway",
|
||||
"foyer",
|
||||
"mudroom"
|
||||
],
|
||||
"stairs": ["stairs", "staircase", "stairway", "stairwell", "landing"],
|
||||
"garage": ["garage", "carport"],
|
||||
"garden": ["garden", "yard", "backyard", "front yard", "lawn", "greenhouse"],
|
||||
"terrace": ["terrace", "patio", "balcony", "deck", "porch", "veranda"],
|
||||
"basement": ["basement", "cellar"],
|
||||
"attic": ["attic", "loft"],
|
||||
"storage": [
|
||||
"storage",
|
||||
"storage room",
|
||||
"pantry",
|
||||
"closet",
|
||||
"shed",
|
||||
"storeroom"
|
||||
],
|
||||
"utility_room": [
|
||||
"utility room",
|
||||
"boiler room",
|
||||
"technical room",
|
||||
"plant room",
|
||||
"server room"
|
||||
],
|
||||
"gym": ["gym", "fitness room", "workout room", "home gym"],
|
||||
"pool": ["pool", "swimming pool", "pool house"],
|
||||
"home_cinema": [
|
||||
"home cinema",
|
||||
"home theater",
|
||||
"home theatre",
|
||||
"cinema room",
|
||||
"media room",
|
||||
"tv room"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["salono", "loĝoĉambro", "loĝejo"],
|
||||
"bedroom": ["dormoĉambro", "gastoĉambro"],
|
||||
"kids_room": ["infanĉambro", "ludĉambro"],
|
||||
"kitchen": ["kuirejo"],
|
||||
"dining_room": ["manĝoĉambro", "manĝejo"],
|
||||
"bathroom": ["banĉambro", "banejo", "duŝejo"],
|
||||
"toilet": ["necesejo", "wc", "tualetejo"],
|
||||
"office": ["oficejo", "laborĉambro", "studejo"],
|
||||
"laundry_room": ["lavejo", "lavĉambro"],
|
||||
"hallway": ["koridoro", "enirejo", "vestiblo", "halo"],
|
||||
"stairs": ["ŝtuparo"],
|
||||
"garage": ["garaĝo"],
|
||||
"garden": ["ĝardeno", "korto", "gazono", "forcejo"],
|
||||
"terrace": ["teraso", "balkono", "verando"],
|
||||
"basement": ["kelo"],
|
||||
"attic": ["subtegmento"],
|
||||
"storage": ["provizejo", "deponejo", "stokejo"],
|
||||
"utility_room": ["teknika ĉambro", "hejtejo"],
|
||||
"gym": ["sportejo", "trejnejo"],
|
||||
"pool": ["naĝejo"],
|
||||
"home_cinema": ["hejma kinejo"]
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"living_room": ["salón", "sala de estar", "sala", "living"],
|
||||
"bedroom": [
|
||||
"dormitorio",
|
||||
"habitación",
|
||||
"recámara",
|
||||
"cuarto",
|
||||
"alcoba",
|
||||
"habitación de invitados"
|
||||
],
|
||||
"kids_room": [
|
||||
"habitación infantil",
|
||||
"cuarto de los niños",
|
||||
"habitación de los niños",
|
||||
"cuarto del bebé",
|
||||
"sala de juegos"
|
||||
],
|
||||
"kitchen": ["cocina"],
|
||||
"dining_room": ["comedor"],
|
||||
"bathroom": ["baño", "cuarto de baño", "ducha"],
|
||||
"toilet": ["aseo", "inodoro", "wc", "servicio", "retrete"],
|
||||
"office": ["oficina", "despacho", "estudio"],
|
||||
"laundry_room": ["lavadero", "lavandería", "cuarto de lavado"],
|
||||
"hallway": [
|
||||
"pasillo",
|
||||
"recibidor",
|
||||
"entrada",
|
||||
"vestíbulo",
|
||||
"hall",
|
||||
"distribuidor"
|
||||
],
|
||||
"stairs": ["escalera", "escaleras"],
|
||||
"garage": ["garaje", "cochera"],
|
||||
"garden": ["jardín", "patio trasero", "césped", "invernadero", "huerto"],
|
||||
"terrace": ["terraza", "balcón", "porche", "patio"],
|
||||
"basement": ["sótano", "bodega"],
|
||||
"attic": ["ático", "desván", "buhardilla"],
|
||||
"storage": ["trastero", "almacén", "despensa", "armario", "cobertizo"],
|
||||
"utility_room": [
|
||||
"sala técnica",
|
||||
"cuarto técnico",
|
||||
"sala de calderas",
|
||||
"cuarto de máquinas"
|
||||
],
|
||||
"gym": ["gimnasio", "sala de fitness"],
|
||||
"pool": ["piscina", "alberca"],
|
||||
"home_cinema": ["cine en casa", "sala de cine", "sala de tv"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["elutuba"],
|
||||
"bedroom": ["magamistuba", "külalistetuba"],
|
||||
"kids_room": ["lastetuba", "mängutuba"],
|
||||
"kitchen": ["köök"],
|
||||
"dining_room": ["söögituba"],
|
||||
"bathroom": ["vannituba", "vannitoba", "dušš", "pesuruum"],
|
||||
"toilet": ["tualett", "wc"],
|
||||
"office": ["kabinet", "kontor", "tööruum"],
|
||||
"laundry_room": ["pesuköök"],
|
||||
"hallway": ["koridor", "esik", "eeskoda"],
|
||||
"stairs": ["trepp", "trepikoda"],
|
||||
"garage": ["garaaž"],
|
||||
"garden": ["aed", "muru", "kasvuhoone"],
|
||||
"terrace": ["terrass", "rõdu", "veranda"],
|
||||
"basement": ["kelder"],
|
||||
"attic": ["pööning"],
|
||||
"storage": ["panipaik", "sahver", "kuur"],
|
||||
"utility_room": ["tehnoruum", "katlaruum"],
|
||||
"gym": ["jõusaal"],
|
||||
"pool": ["bassein"],
|
||||
"home_cinema": ["kodukino"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["egongela", "saloia"],
|
||||
"bedroom": ["logela", "gela"],
|
||||
"kids_room": ["haurren gela", "jolas gela"],
|
||||
"kitchen": ["sukaldea"],
|
||||
"dining_room": ["jangela"],
|
||||
"bathroom": ["bainugela", "dutxa"],
|
||||
"toilet": ["komuna", "wc", "komun"],
|
||||
"office": ["bulegoa", "ikasgela"],
|
||||
"laundry_room": ["garbitegia"],
|
||||
"hallway": ["korridorea", "sarrera", "ataria"],
|
||||
"stairs": ["eskailerak", "eskailera"],
|
||||
"garage": ["garajea"],
|
||||
"garden": ["lorategia", "baratza", "belardia"],
|
||||
"terrace": ["terraza", "balkoia"],
|
||||
"basement": ["sotoa", "upategia"],
|
||||
"attic": ["ganbara"],
|
||||
"storage": ["trastelekua", "biltegia", "jakitegia"],
|
||||
"utility_room": ["gela teknikoa"],
|
||||
"gym": ["gimnasioa"],
|
||||
"pool": ["igerilekua"],
|
||||
"home_cinema": ["etxeko zinema"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["پذیرایی", "نشیمن", "سالن", "اتاق نشیمن"],
|
||||
"bedroom": ["اتاق خواب", "اتاق مهمان"],
|
||||
"kids_room": ["اتاق کودک", "اتاق بچه", "اتاق بازی"],
|
||||
"kitchen": ["آشپزخانه"],
|
||||
"dining_room": ["ناهارخوری", "اتاق غذاخوری"],
|
||||
"bathroom": ["حمام", "دوش"],
|
||||
"toilet": ["دستشویی", "توالت", "سرویس بهداشتی", "wc"],
|
||||
"office": ["دفتر", "اتاق کار"],
|
||||
"laundry_room": ["رختشویخانه"],
|
||||
"hallway": ["راهرو", "ورودی", "هال"],
|
||||
"stairs": ["پله", "راه پله"],
|
||||
"garage": ["پارکینگ", "گاراژ"],
|
||||
"garden": ["باغ", "حیاط", "باغچه", "گلخانه"],
|
||||
"terrace": ["تراس", "بالکن", "ایوان"],
|
||||
"basement": ["زیرزمین"],
|
||||
"attic": ["زیرشیروانی"],
|
||||
"storage": ["انباری", "انبار"],
|
||||
"utility_room": ["موتورخانه", "اتاق فنی"],
|
||||
"gym": ["باشگاه", "اتاق ورزش"],
|
||||
"pool": ["استخر"],
|
||||
"home_cinema": ["سینمای خانگی"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["olohuone", "oleskelutila", "tupa"],
|
||||
"bedroom": ["makuuhuone", "vierashuone"],
|
||||
"kids_room": ["lastenhuone", "leikkihuone"],
|
||||
"kitchen": ["keittiö", "keittokomero"],
|
||||
"dining_room": ["ruokailuhuone", "ruokailutila"],
|
||||
"bathroom": ["kylpyhuone", "pesuhuone", "suihku"],
|
||||
"toilet": ["wc", "vessa", "käymälä"],
|
||||
"office": ["toimisto", "työhuone", "kotitoimisto"],
|
||||
"laundry_room": ["kodinhoitohuone", "pyykkihuone"],
|
||||
"hallway": ["eteinen", "käytävä", "aula"],
|
||||
"stairs": ["portaat", "porraskäytävä"],
|
||||
"garage": ["autotalli", "autokatos"],
|
||||
"garden": ["puutarha", "piha", "nurmikko", "kasvihuone"],
|
||||
"terrace": ["terassi", "parveke", "kuisti", "veranta"],
|
||||
"basement": ["kellari"],
|
||||
"attic": ["ullakko", "vintti"],
|
||||
"storage": ["varasto", "vaatehuone", "ruokakomero", "vaja"],
|
||||
"utility_room": ["tekninen tila", "lämmönjakohuone", "pannuhuone"],
|
||||
"gym": ["kuntosali", "kuntohuone"],
|
||||
"pool": ["uima allas", "allas"],
|
||||
"home_cinema": ["kotiteatteri", "elokuvahuone"]
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"living_room": [
|
||||
"salon",
|
||||
"séjour",
|
||||
"salle de séjour",
|
||||
"pièce de vie",
|
||||
"living"
|
||||
],
|
||||
"bedroom": [
|
||||
"chambre",
|
||||
"chambre parentale",
|
||||
"suite parentale",
|
||||
"chambre damis"
|
||||
],
|
||||
"kids_room": [
|
||||
"chambre denfant",
|
||||
"chambre des enfants",
|
||||
"chambre bébé",
|
||||
"salle de jeux",
|
||||
"nurserie"
|
||||
],
|
||||
"kitchen": ["cuisine", "kitchenette"],
|
||||
"dining_room": ["salle à manger", "coin repas"],
|
||||
"bathroom": ["salle de bain", "salle de bains", "salle deau", "douche"],
|
||||
"toilet": ["toilettes", "wc", "toilette", "cabinet de toilette"],
|
||||
"office": ["bureau", "cabinet de travail"],
|
||||
"laundry_room": ["buanderie", "lingerie"],
|
||||
"hallway": ["couloir", "entrée", "hall", "vestibule", "dégagement"],
|
||||
"stairs": ["escalier", "escaliers", "cage descalier", "palier"],
|
||||
"garage": ["garage", "carport"],
|
||||
"garden": ["jardin", "pelouse", "potager", "cour", "serre"],
|
||||
"terrace": ["terrasse", "balcon", "véranda", "patio", "loggia"],
|
||||
"basement": ["sous sol", "cave"],
|
||||
"attic": ["grenier", "combles", "mansarde"],
|
||||
"storage": [
|
||||
"rangement",
|
||||
"débarras",
|
||||
"cellier",
|
||||
"placard",
|
||||
"remise",
|
||||
"abri de jardin",
|
||||
"cabanon"
|
||||
],
|
||||
"utility_room": [
|
||||
"local technique",
|
||||
"chaufferie",
|
||||
"salle technique",
|
||||
"baie informatique"
|
||||
],
|
||||
"gym": ["salle de sport", "salle de fitness", "gym"],
|
||||
"pool": ["piscine", "pool house"],
|
||||
"home_cinema": ["home cinéma", "salle de cinéma", "salle télé", "salle tv"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["wenkeamer", "húskeamer"],
|
||||
"bedroom": ["sliepkeamer", "logearkeamer"],
|
||||
"kids_room": ["bernkeamer", "boarterskeamer"],
|
||||
"kitchen": ["koken"],
|
||||
"dining_room": ["itenskeamer"],
|
||||
"bathroom": ["badkeamer", "dûs"],
|
||||
"toilet": ["húske", "wc", "toilet"],
|
||||
"office": ["kantoar", "wurkkeamer"],
|
||||
"laundry_room": ["waskeamer", "bykoken"],
|
||||
"hallway": ["gong", "hal", "yngong"],
|
||||
"stairs": ["trep"],
|
||||
"garage": ["garaazje"],
|
||||
"garden": ["tún", "gers", "kas"],
|
||||
"terrace": ["terras", "balkon", "veranda"],
|
||||
"basement": ["kelder"],
|
||||
"attic": ["souder", "solder"],
|
||||
"storage": ["berging", "skuorre", "opslach"],
|
||||
"utility_room": ["technyske romte"],
|
||||
"gym": ["fitnessromte"],
|
||||
"pool": ["swimbad"],
|
||||
"home_cinema": ["thúsbioskoop"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["seomra suí", "seomra teaghlaigh", "parlús"],
|
||||
"bedroom": ["seomra codlata", "seomra leapa"],
|
||||
"kids_room": ["seomra na bpáistí", "seomra súgartha"],
|
||||
"kitchen": ["cistin"],
|
||||
"dining_room": ["seomra bia"],
|
||||
"bathroom": ["seomra folctha", "cithfholcadh"],
|
||||
"toilet": ["leithreas", "wc"],
|
||||
"office": ["oifig", "seomra staidéir"],
|
||||
"laundry_room": ["seomra níocháin"],
|
||||
"hallway": ["halla", "pasáiste", "bealach isteach"],
|
||||
"stairs": ["staighre"],
|
||||
"garage": ["garáiste"],
|
||||
"garden": ["gairdín", "clós", "faiche", "teach gloine"],
|
||||
"terrace": ["ardán", "balcóin", "póirse"],
|
||||
"basement": ["íoslach", "siléar"],
|
||||
"attic": ["áiléar"],
|
||||
"storage": ["stóras", "seomra stórais", "cúlteach"],
|
||||
"utility_room": ["seomra fóntais"],
|
||||
"gym": ["giomnáisiam"],
|
||||
"pool": ["linn snámha"],
|
||||
"home_cinema": ["pictiúrlann bhaile"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["sala de estar", "salón", "sala"],
|
||||
"bedroom": ["dormitorio", "cuarto", "habitación"],
|
||||
"kids_room": ["cuarto dos nenos", "cuarto infantil"],
|
||||
"kitchen": ["cociña"],
|
||||
"dining_room": ["comedor"],
|
||||
"bathroom": ["baño", "cuarto de baño", "ducha"],
|
||||
"toilet": ["aseo", "váter", "wc"],
|
||||
"office": ["oficina", "despacho", "estudo"],
|
||||
"laundry_room": ["lavandaría"],
|
||||
"hallway": ["corredor", "entrada", "vestíbulo"],
|
||||
"stairs": ["escaleira", "escaleiras"],
|
||||
"garage": ["garaxe"],
|
||||
"garden": ["xardín", "horta", "invernadoiro"],
|
||||
"terrace": ["terraza", "balcón"],
|
||||
"basement": ["soto", "adega"],
|
||||
"attic": ["faiado"],
|
||||
"storage": ["trasteiro", "despensa", "almacén"],
|
||||
"utility_room": ["sala técnica"],
|
||||
"gym": ["ximnasio"],
|
||||
"pool": ["piscina"],
|
||||
"home_cinema": ["cine na casa"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["stube", "wohnzimmer", "wohnstube"],
|
||||
"bedroom": ["schlafzimmer", "schlofzimmer", "gästezimmer"],
|
||||
"kids_room": ["chinderzimmer", "kinderzimmer"],
|
||||
"kitchen": ["chuchi", "küche"],
|
||||
"dining_room": ["esszimmer", "ässzimmer"],
|
||||
"bathroom": ["bad", "badzimmer", "dusche"],
|
||||
"toilet": ["wc", "toilette", "klo"],
|
||||
"office": ["büro", "arbeitszimmer"],
|
||||
"laundry_room": ["wöschchuchi", "waschküche"],
|
||||
"hallway": ["gang", "flur", "iigang", "eingang"],
|
||||
"stairs": ["stäge", "treppe"],
|
||||
"garage": ["garage", "carport"],
|
||||
"garden": ["garte", "garten", "rase", "gwächshuus"],
|
||||
"terrace": ["terrasse", "balkon", "sitzplatz", "veranda"],
|
||||
"basement": ["chäller", "keller"],
|
||||
"attic": ["estrich", "dachstock"],
|
||||
"storage": ["abstellruum", "abstellraum", "reduit", "lager", "schopf"],
|
||||
"utility_room": ["heizigsruum", "technikruum"],
|
||||
"gym": ["fitnessruum", "fitnessraum"],
|
||||
"pool": ["pool", "schwimmbad"],
|
||||
"home_cinema": ["heimkino"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["סלון", "חדר מגורים", "חדר אורחים"],
|
||||
"bedroom": ["חדר שינה", "חדר הורים"],
|
||||
"kids_room": ["חדר ילדים", "חדר משחקים"],
|
||||
"kitchen": ["מטבח"],
|
||||
"dining_room": ["פינת אוכל", "חדר אוכל"],
|
||||
"bathroom": ["חדר רחצה", "אמבטיה", "מקלחת"],
|
||||
"toilet": ["שירותים", "wc"],
|
||||
"office": ["משרד", "חדר עבודה"],
|
||||
"laundry_room": ["חדר כביסה"],
|
||||
"hallway": ["מסדרון", "כניסה", "פרוזדור"],
|
||||
"stairs": ["מדרגות", "חדר מדרגות"],
|
||||
"garage": ["חניה", "מוסך"],
|
||||
"garden": ["גינה", "חצר", "דשא", "חממה"],
|
||||
"terrace": ["מרפסת", "פטיו"],
|
||||
"basement": ["מרתף"],
|
||||
"attic": ["עליית גג"],
|
||||
"storage": ["מחסן", "מזווה"],
|
||||
"utility_room": ["חדר טכני", "חדר שרתים"],
|
||||
"gym": ["חדר כושר"],
|
||||
"pool": ["בריכה"],
|
||||
"home_cinema": ["קולנוע ביתי"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["बैठक", "बैठक कक्ष", "लिविंग रूम", "ड्राइंग रूम"],
|
||||
"bedroom": ["शयनकक्ष", "बेडरूम", "अतिथि कक्ष"],
|
||||
"kids_room": ["बच्चों का कमरा", "खेल कक्ष"],
|
||||
"kitchen": ["रसोई", "रसोईघर", "किचन"],
|
||||
"dining_room": ["भोजन कक्ष", "डाइनिंग रूम"],
|
||||
"bathroom": ["स्नानघर", "बाथरूम", "गुसलखाना"],
|
||||
"toilet": ["शौचालय", "टॉयलेट", "wc"],
|
||||
"office": ["कार्यालय", "दफ्तर", "ऑफिस", "अध्ययन कक्ष"],
|
||||
"laundry_room": ["कपड़े धोने का कमरा", "लॉन्ड्री"],
|
||||
"hallway": ["गलियारा", "प्रवेश", "बरामदा"],
|
||||
"stairs": ["सीढ़ी", "सीढ़ियाँ"],
|
||||
"garage": ["गैराज"],
|
||||
"garden": ["बगीचा", "बाग", "आंगन", "लॉन"],
|
||||
"terrace": ["छत", "बालकनी", "टैरेस"],
|
||||
"basement": ["तहखाना", "बेसमेंट"],
|
||||
"attic": ["अटारी"],
|
||||
"storage": ["भंडार", "स्टोर रूम", "गोदाम"],
|
||||
"utility_room": ["यूटिलिटी रूम"],
|
||||
"gym": ["जिम", "व्यायामशाला"],
|
||||
"pool": ["स्विमिंग पूल", "तरणताल"],
|
||||
"home_cinema": ["होम थिएटर"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["dnevni boravak", "dnevna soba"],
|
||||
"bedroom": ["spavaća soba", "soba za goste"],
|
||||
"kids_room": ["dječja soba", "igraonica"],
|
||||
"kitchen": ["kuhinja"],
|
||||
"dining_room": ["blagovaonica"],
|
||||
"bathroom": ["kupaonica", "tuš"],
|
||||
"toilet": ["wc", "zahod", "toalet"],
|
||||
"office": ["ured", "radna soba"],
|
||||
"laundry_room": ["praonica"],
|
||||
"hallway": ["hodnik", "predsoblje", "ulaz"],
|
||||
"stairs": ["stepenice", "stubište"],
|
||||
"garage": ["garaža"],
|
||||
"garden": ["vrt", "dvorište", "travnjak", "staklenik"],
|
||||
"terrace": ["terasa", "balkon", "veranda"],
|
||||
"basement": ["podrum"],
|
||||
"attic": ["tavan", "potkrovlje"],
|
||||
"storage": ["spremište", "ostava", "šupa"],
|
||||
"utility_room": ["kotlovnica", "tehnička prostorija"],
|
||||
"gym": ["teretana"],
|
||||
"pool": ["bazen"],
|
||||
"home_cinema": ["kućno kino"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["nappali"],
|
||||
"bedroom": ["hálószoba", "háló", "vendégszoba"],
|
||||
"kids_room": ["gyerekszoba", "játszószoba"],
|
||||
"kitchen": ["konyha"],
|
||||
"dining_room": ["étkező", "ebédlő"],
|
||||
"bathroom": ["fürdőszoba", "fürdő", "zuhanyzó"],
|
||||
"toilet": ["wc", "mosdó", "vécé"],
|
||||
"office": ["iroda", "dolgozószoba"],
|
||||
"laundry_room": ["mosókonyha"],
|
||||
"hallway": ["folyosó", "előszoba", "hall", "közlekedő"],
|
||||
"stairs": ["lépcső", "lépcsőház"],
|
||||
"garage": ["garázs", "autóbeálló"],
|
||||
"garden": ["kert", "udvar", "pázsit", "üvegház"],
|
||||
"terrace": ["terasz", "erkély", "veranda"],
|
||||
"basement": ["pince", "alagsor"],
|
||||
"attic": ["padlás", "tetőtér"],
|
||||
"storage": ["tároló", "kamra", "raktár", "gardrób"],
|
||||
"utility_room": ["kazánház", "gépészeti helyiség"],
|
||||
"gym": ["edzőterem", "konditerem"],
|
||||
"pool": ["medence", "uszoda"],
|
||||
"home_cinema": ["házimozi", "mozi szoba"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["հյուրասենյակ", "ընդունարան"],
|
||||
"bedroom": ["ննջասենյակ"],
|
||||
"kids_room": ["մանկական սենյակ", "մանկական"],
|
||||
"kitchen": ["խոհանոց"],
|
||||
"dining_room": ["ճաշասենյակ"],
|
||||
"bathroom": ["լոգարան", "ցնցուղ"],
|
||||
"toilet": ["զուգարան", "wc"],
|
||||
"office": ["աշխատասենյակ", "գրասենյակ"],
|
||||
"laundry_room": ["լվացքատուն"],
|
||||
"hallway": ["միջանցք", "նախասենյակ", "մուտք"],
|
||||
"stairs": ["աստիճաններ", "սանդուղք"],
|
||||
"garage": ["ավտոտնակ"],
|
||||
"garden": ["այգի", "բակ", "ջերմոց"],
|
||||
"terrace": ["տեռաս", "պատշգամբ", "պատշգամբը"],
|
||||
"basement": ["նկուղ"],
|
||||
"attic": ["ձեղնահարկ"],
|
||||
"storage": ["պահեստ", "մառան"],
|
||||
"utility_room": ["տեխնիկական սենյակ", "կաթսայատուն"],
|
||||
"gym": ["մարզասրահ"],
|
||||
"pool": ["լողավազան"],
|
||||
"home_cinema": ["տնային կինոթատրոն"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["ruang tamu", "ruang keluarga", "ruang tengah"],
|
||||
"bedroom": ["kamar tidur", "kamar", "kamar tamu"],
|
||||
"kids_room": ["kamar anak", "ruang bermain"],
|
||||
"kitchen": ["dapur"],
|
||||
"dining_room": ["ruang makan"],
|
||||
"bathroom": ["kamar mandi"],
|
||||
"toilet": ["toilet", "wc", "kakus"],
|
||||
"office": ["kantor", "ruang kerja"],
|
||||
"laundry_room": ["ruang cuci", "tempat cuci"],
|
||||
"hallway": ["lorong", "koridor", "pintu masuk"],
|
||||
"stairs": ["tangga"],
|
||||
"garage": ["garasi", "carport"],
|
||||
"garden": ["taman", "halaman", "kebun"],
|
||||
"terrace": ["teras", "balkon", "beranda"],
|
||||
"basement": ["ruang bawah tanah"],
|
||||
"attic": ["loteng"],
|
||||
"storage": ["gudang", "ruang penyimpanan"],
|
||||
"utility_room": ["ruang teknis"],
|
||||
"gym": ["ruang olahraga", "gym"],
|
||||
"pool": ["kolam renang"],
|
||||
"home_cinema": ["home teater", "ruang bioskop"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["stofa", "setustofa"],
|
||||
"bedroom": ["svefnherbergi", "gestaherbergi"],
|
||||
"kids_room": ["barnaherbergi", "leikherbergi"],
|
||||
"kitchen": ["eldhús"],
|
||||
"dining_room": ["borðstofa"],
|
||||
"bathroom": ["baðherbergi", "bað", "sturta"],
|
||||
"toilet": ["salerni", "klósett", "snyrting"],
|
||||
"office": ["skrifstofa", "vinnuherbergi"],
|
||||
"laundry_room": ["þvottahús"],
|
||||
"hallway": ["gangur", "forstofa", "anddyri"],
|
||||
"stairs": ["stigi", "stigagangur"],
|
||||
"garage": ["bílskúr"],
|
||||
"garden": ["garður", "gróðurhús"],
|
||||
"terrace": ["verönd", "svalir", "pallur"],
|
||||
"basement": ["kjallari"],
|
||||
"attic": ["háaloft", "ris"],
|
||||
"storage": ["geymsla", "búr"],
|
||||
"utility_room": ["tæknirými"],
|
||||
"gym": ["líkamsræktarherbergi"],
|
||||
"pool": ["sundlaug", "laug"],
|
||||
"home_cinema": ["heimabíó"]
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"living_room": ["soggiorno", "salotto", "sala", "living"],
|
||||
"bedroom": [
|
||||
"camera da letto",
|
||||
"camera",
|
||||
"camera matrimoniale",
|
||||
"camera degli ospiti"
|
||||
],
|
||||
"kids_room": ["cameretta", "camera dei bambini", "stanza dei giochi"],
|
||||
"kitchen": ["cucina", "angolo cottura"],
|
||||
"dining_room": ["sala da pranzo", "zona pranzo"],
|
||||
"bathroom": ["bagno", "doccia", "stanza da bagno"],
|
||||
"toilet": ["toilette", "wc", "gabinetto", "bagno di servizio"],
|
||||
"office": ["ufficio", "studio", "studiolo"],
|
||||
"laundry_room": ["lavanderia"],
|
||||
"hallway": ["corridoio", "ingresso", "disimpegno", "atrio"],
|
||||
"stairs": ["scala", "scale", "pianerottolo"],
|
||||
"garage": ["garage", "box", "autorimessa"],
|
||||
"garden": ["giardino", "prato", "orto", "serra", "cortile"],
|
||||
"terrace": ["terrazzo", "terrazza", "balcone", "veranda", "portico"],
|
||||
"basement": ["cantina", "seminterrato", "scantinato"],
|
||||
"attic": ["soffitta", "sottotetto", "mansarda"],
|
||||
"storage": ["ripostiglio", "magazzino", "dispensa", "deposito", "capanno"],
|
||||
"utility_room": ["locale tecnico", "centrale termica", "locale caldaia"],
|
||||
"gym": ["palestra"],
|
||||
"pool": ["piscina"],
|
||||
"home_cinema": ["home theater", "sala cinema", "sala tv"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["リビング", "居間", "リビングルーム", "茶の間"],
|
||||
"bedroom": ["寝室", "ベッドルーム", "客間"],
|
||||
"kids_room": ["子供部屋", "子ども部屋", "キッズルーム", "遊び部屋"],
|
||||
"kitchen": ["キッチン", "台所"],
|
||||
"dining_room": ["ダイニング", "食堂"],
|
||||
"bathroom": ["浴室", "風呂", "お風呂", "バスルーム", "洗面所", "脱衣所"],
|
||||
"toilet": ["トイレ", "お手洗い", "wc"],
|
||||
"office": ["書斎", "オフィス", "仕事部屋", "事務所"],
|
||||
"laundry_room": ["ランドリー", "洗濯室"],
|
||||
"hallway": ["廊下", "玄関", "ホール"],
|
||||
"stairs": ["階段"],
|
||||
"garage": ["ガレージ", "車庫"],
|
||||
"garden": ["庭", "ガーデン", "菜園", "温室"],
|
||||
"terrace": ["テラス", "ベランダ", "バルコニー", "ウッドデッキ"],
|
||||
"basement": ["地下室", "地下"],
|
||||
"attic": ["屋根裏", "ロフト"],
|
||||
"storage": ["物置", "納戸", "倉庫", "収納", "パントリー", "クローゼット"],
|
||||
"utility_room": ["機械室", "ボイラー室", "サーバー室"],
|
||||
"gym": ["ジム", "トレーニングルーム"],
|
||||
"pool": ["プール"],
|
||||
"home_cinema": ["ホームシアター", "シアタールーム"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["მისაღები", "მისაღები ოთახი", "სასტუმრო ოთახი"],
|
||||
"bedroom": ["საძინებელი"],
|
||||
"kids_room": ["საბავშვო", "საბავშვო ოთახი"],
|
||||
"kitchen": ["სამზარეულო"],
|
||||
"dining_room": ["სასადილო"],
|
||||
"bathroom": ["აბაზანა", "საშხაპე"],
|
||||
"toilet": ["ტუალეტი", "საპირფარეშო", "wc"],
|
||||
"office": ["ოფისი", "კაბინეტი", "სამუშაო ოთახი"],
|
||||
"laundry_room": ["სამრეცხაო"],
|
||||
"hallway": ["დერეფანი", "შესასვლელი", "ჰოლი"],
|
||||
"stairs": ["კიბე"],
|
||||
"garage": ["ავტოფარეხი", "გარაჟი"],
|
||||
"garden": ["ბაღი", "ეზო", "სათბური"],
|
||||
"terrace": ["ტერასა", "აივანი", "ვერანდა"],
|
||||
"basement": ["სარდაფი"],
|
||||
"attic": ["სხვენი", "მანსარდა"],
|
||||
"storage": ["საკუჭნაო", "საწყობი"],
|
||||
"utility_room": ["ტექნიკური ოთახი", "საქვაბე"],
|
||||
"gym": ["სპორტდარბაზი"],
|
||||
"pool": ["აუზი"],
|
||||
"home_cinema": ["სახლის კინოთეატრი"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["거실"],
|
||||
"bedroom": ["침실", "안방", "손님방"],
|
||||
"kids_room": ["아이방", "아기방", "놀이방", "어린이방"],
|
||||
"kitchen": ["주방", "부엌"],
|
||||
"dining_room": ["식당", "다이닝룸"],
|
||||
"bathroom": ["욕실", "샤워실"],
|
||||
"toilet": ["화장실"],
|
||||
"office": ["서재", "사무실", "작업실", "공부방"],
|
||||
"laundry_room": ["세탁실", "다용도실"],
|
||||
"hallway": ["복도", "현관"],
|
||||
"stairs": ["계단"],
|
||||
"garage": ["차고"],
|
||||
"garden": ["정원", "마당", "온실"],
|
||||
"terrace": ["테라스", "베란다", "발코니"],
|
||||
"basement": ["지하실", "지하"],
|
||||
"attic": ["다락방", "다락"],
|
||||
"storage": ["창고", "수납실", "드레스룸", "팬트리"],
|
||||
"utility_room": ["보일러실", "기계실"],
|
||||
"gym": ["헬스장", "운동실"],
|
||||
"pool": ["수영장"],
|
||||
"home_cinema": ["홈시어터"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["wunnzëmmer", "salon", "stuff"],
|
||||
"bedroom": ["schlofzëmmer", "gaaschtzëmmer"],
|
||||
"kids_room": ["kannerzëmmer", "spillzëmmer"],
|
||||
"kitchen": ["kichen"],
|
||||
"dining_room": ["iesszëmmer"],
|
||||
"bathroom": ["buedzëmmer", "bued", "dusch"],
|
||||
"toilet": ["toilette", "wc"],
|
||||
"office": ["büro", "aarbechtszëmmer"],
|
||||
"laundry_room": ["wäschkummer", "buanderie"],
|
||||
"hallway": ["gank", "entrée", "flouer"],
|
||||
"stairs": ["trap", "trapenhaus"],
|
||||
"garage": ["garage"],
|
||||
"garden": ["gaart", "wiss", "gewächshaus"],
|
||||
"terrace": ["terrass", "balcon", "veranda"],
|
||||
"basement": ["keller"],
|
||||
"attic": ["späicher", "speicher"],
|
||||
"storage": ["depot", "debarras", "späis"],
|
||||
"utility_room": ["technikraum", "heizungskeller"],
|
||||
"gym": ["fitnessraum"],
|
||||
"pool": ["schwämm", "pool"],
|
||||
"home_cinema": ["heemkino"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["svetainė", "gyvenamasis kambarys"],
|
||||
"bedroom": ["miegamasis", "svečių kambarys"],
|
||||
"kids_room": ["vaikų kambarys", "žaidimų kambarys"],
|
||||
"kitchen": ["virtuvė"],
|
||||
"dining_room": ["valgomasis"],
|
||||
"bathroom": ["vonios kambarys", "vonia", "dušas"],
|
||||
"toilet": ["tualetas", "wc"],
|
||||
"office": ["kabinetas", "biuras", "darbo kambarys"],
|
||||
"laundry_room": ["skalbykla"],
|
||||
"hallway": ["koridorius", "prieškambaris"],
|
||||
"stairs": ["laiptai", "laiptinė"],
|
||||
"garage": ["garažas"],
|
||||
"garden": ["sodas", "kiemas", "veja", "šiltnamis"],
|
||||
"terrace": ["terasa", "balkonas", "veranda"],
|
||||
"basement": ["rūsys"],
|
||||
"attic": ["palėpė", "mansarda"],
|
||||
"storage": ["sandėlis", "sandėliukas"],
|
||||
"utility_room": ["techninė patalpa", "katilinė"],
|
||||
"gym": ["sporto salė"],
|
||||
"pool": ["baseinas"],
|
||||
"home_cinema": ["namų kinas"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["dzīvojamā istaba", "viesistaba"],
|
||||
"bedroom": ["guļamistaba"],
|
||||
"kids_room": ["bērnu istaba", "rotaļu istaba"],
|
||||
"kitchen": ["virtuve"],
|
||||
"dining_room": ["ēdamistaba"],
|
||||
"bathroom": ["vannas istaba", "duša"],
|
||||
"toilet": ["tualete", "wc"],
|
||||
"office": ["birojs", "kabinets", "darba istaba"],
|
||||
"laundry_room": ["veļas telpa"],
|
||||
"hallway": ["gaitenis", "priekšnams", "koridors"],
|
||||
"stairs": ["kāpnes"],
|
||||
"garage": ["garāža"],
|
||||
"garden": ["dārzs", "zāliens", "siltumnīca"],
|
||||
"terrace": ["terase", "balkons", "veranda"],
|
||||
"basement": ["pagrabs"],
|
||||
"attic": ["bēniņi"],
|
||||
"storage": ["noliktava", "pieliekamais"],
|
||||
"utility_room": ["tehniskā telpa", "katlu telpa"],
|
||||
"gym": ["sporta zāle"],
|
||||
"pool": ["baseins"],
|
||||
"home_cinema": ["mājas kinozāle"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["дневна соба", "дневен престој"],
|
||||
"bedroom": ["спална соба", "соба за гости"],
|
||||
"kids_room": ["детска соба"],
|
||||
"kitchen": ["кујна"],
|
||||
"dining_room": ["трпезарија"],
|
||||
"bathroom": ["бања", "купатило", "туш"],
|
||||
"toilet": ["тоалет", "wc"],
|
||||
"office": ["канцеларија", "работна соба"],
|
||||
"laundry_room": ["перална"],
|
||||
"hallway": ["ходник", "предсобје", "влез"],
|
||||
"stairs": ["скали"],
|
||||
"garage": ["гаража"],
|
||||
"garden": ["градина", "двор", "тревник"],
|
||||
"terrace": ["тераса", "балкон"],
|
||||
"basement": ["подрум"],
|
||||
"attic": ["таван"],
|
||||
"storage": ["остава", "магацин"],
|
||||
"utility_room": ["котларница"],
|
||||
"gym": ["теретана"],
|
||||
"pool": ["базен"],
|
||||
"home_cinema": ["домашно кино"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["സ്വീകരണമുറി", "ലിവിംഗ് റൂം", "ഹാൾ"],
|
||||
"bedroom": ["കിടപ്പുമുറി", "ബെഡ്റൂം", "അതിഥി മുറി"],
|
||||
"kids_room": ["കുട്ടികളുടെ മുറി"],
|
||||
"kitchen": ["അടുക്കള"],
|
||||
"dining_room": ["ഊണുമുറി", "ഡൈനിംഗ് റൂം"],
|
||||
"bathroom": ["കുളിമുറി", "ബാത്ത്റൂം"],
|
||||
"toilet": ["ശൗചാലയം", "ടോയ്ലറ്റ്", "wc"],
|
||||
"office": ["ഓഫീസ്", "പഠനമുറി"],
|
||||
"laundry_room": ["അലക്കുമുറി"],
|
||||
"hallway": ["ഇടനാഴി", "പ്രവേശന കവാടം"],
|
||||
"stairs": ["ഗോവണി", "പടികൾ"],
|
||||
"garage": ["ഗാരേജ്", "കാർ പോർച്ച്"],
|
||||
"garden": ["പൂന്തോട്ടം", "മുറ്റം", "തോട്ടം"],
|
||||
"terrace": ["ടെറസ്", "ബാൽക്കണി", "വരാന്ത"],
|
||||
"basement": ["നിലവറ"],
|
||||
"attic": ["തട്ടിൻപുറം"],
|
||||
"storage": ["സ്റ്റോർ റൂം", "സംഭരണമുറി"],
|
||||
"utility_room": ["യൂട്ടിലിറ്റി റൂം"],
|
||||
"gym": ["ജിം", "വ്യായാമമുറി"],
|
||||
"pool": ["നീന്തൽക്കുളം"],
|
||||
"home_cinema": ["ഹോം തിയേറ്റർ"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["ruang tamu", "ruang keluarga", "bilik tamu"],
|
||||
"bedroom": ["bilik tidur", "bilik", "bilik tetamu"],
|
||||
"kids_room": ["bilik kanak kanak", "bilik anak", "bilik permainan"],
|
||||
"kitchen": ["dapur"],
|
||||
"dining_room": ["ruang makan", "bilik makan"],
|
||||
"bathroom": ["bilik mandi"],
|
||||
"toilet": ["tandas", "toilet", "wc"],
|
||||
"office": ["pejabat", "bilik kerja", "bilik belajar"],
|
||||
"laundry_room": ["bilik dobi", "ruang dobi"],
|
||||
"hallway": ["koridor", "laluan", "pintu masuk", "serambi masuk"],
|
||||
"stairs": ["tangga"],
|
||||
"garage": ["garaj", "porch kereta"],
|
||||
"garden": ["taman", "laman", "halaman", "kebun"],
|
||||
"terrace": ["teres", "balkoni", "beranda", "anjung"],
|
||||
"basement": ["bilik bawah tanah", "ruang bawah tanah"],
|
||||
"attic": ["loteng"],
|
||||
"storage": ["stor", "bilik stor", "gudang"],
|
||||
"utility_room": ["bilik utiliti", "bilik teknikal"],
|
||||
"gym": ["gim", "bilik senaman"],
|
||||
"pool": ["kolam renang"],
|
||||
"home_cinema": ["teater rumah", "pawagam rumah"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["stue", "dagligstue", "tv stue"],
|
||||
"bedroom": ["soverom", "gjesterom"],
|
||||
"kids_room": ["barnerom", "lekerom"],
|
||||
"kitchen": ["kjøkken"],
|
||||
"dining_room": ["spisestue"],
|
||||
"bathroom": ["bad", "baderom", "dusj"],
|
||||
"toilet": ["toalett", "wc", "do"],
|
||||
"office": ["kontor", "hjemmekontor", "arbeidsrom"],
|
||||
"laundry_room": ["vaskerom", "vaskekjeller"],
|
||||
"hallway": ["gang", "entré", "gangen", "hall"],
|
||||
"stairs": ["trapp", "trappegang"],
|
||||
"garage": ["garasje", "carport"],
|
||||
"garden": ["hage", "plen", "drivhus"],
|
||||
"terrace": ["terrasse", "balkong", "veranda", "platting"],
|
||||
"basement": ["kjeller"],
|
||||
"attic": ["loft"],
|
||||
"storage": ["bod", "lager", "spiskammers"],
|
||||
"utility_room": ["teknisk rom", "fyrrom"],
|
||||
"gym": ["treningsrom", "gym"],
|
||||
"pool": ["basseng"],
|
||||
"home_cinema": ["hjemmekino", "kinorom"]
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"living_room": ["woonkamer", "zitkamer", "huiskamer", "living"],
|
||||
"bedroom": ["slaapkamer", "logeerkamer", "ouderslaapkamer"],
|
||||
"kids_room": ["kinderkamer", "babykamer", "speelkamer"],
|
||||
"kitchen": ["keuken"],
|
||||
"dining_room": ["eetkamer", "eethoek"],
|
||||
"bathroom": ["badkamer", "douche", "doucheruimte"],
|
||||
"toilet": ["toilet", "wc"],
|
||||
"office": ["kantoor", "werkkamer", "studeerkamer", "thuiskantoor"],
|
||||
"laundry_room": ["wasruimte", "washok", "bijkeuken"],
|
||||
"hallway": ["hal", "gang", "entree", "inkomhal"],
|
||||
"stairs": ["trap", "trappenhuis", "overloop"],
|
||||
"garage": ["garage", "carport"],
|
||||
"garden": ["tuin", "achtertuin", "voortuin", "gazon", "kas"],
|
||||
"terrace": ["terras", "balkon", "veranda", "serre"],
|
||||
"basement": ["kelder", "souterrain"],
|
||||
"attic": ["zolder", "vliering"],
|
||||
"storage": ["berging", "opslag", "schuur", "tuinhuis", "voorraadkast"],
|
||||
"utility_room": [
|
||||
"technische ruimte",
|
||||
"stookruimte",
|
||||
"meterkast",
|
||||
"serverruimte"
|
||||
],
|
||||
"gym": ["fitnessruimte", "sportruimte", "gym"],
|
||||
"pool": ["zwembad", "pool"],
|
||||
"home_cinema": ["thuisbioscoop", "bioscoopkamer", "tv kamer"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["stove", "daglegstove"],
|
||||
"bedroom": ["soverom", "gjesterom"],
|
||||
"kids_room": ["barnerom", "leikerom"],
|
||||
"kitchen": ["kjøkken"],
|
||||
"dining_room": ["spisestove"],
|
||||
"bathroom": ["bad", "baderom", "dusj"],
|
||||
"toilet": ["toalett", "wc", "do"],
|
||||
"office": ["kontor", "heimekontor", "arbeidsrom"],
|
||||
"laundry_room": ["vaskerom"],
|
||||
"hallway": ["gang", "entré", "hall"],
|
||||
"stairs": ["trapp"],
|
||||
"garage": ["garasje"],
|
||||
"garden": ["hage", "plen", "drivhus"],
|
||||
"terrace": ["terrasse", "balkong", "veranda"],
|
||||
"basement": ["kjellar"],
|
||||
"attic": ["loft"],
|
||||
"storage": ["bod", "lager"],
|
||||
"utility_room": ["teknisk rom", "fyrrom"],
|
||||
"gym": ["treningsrom"],
|
||||
"pool": ["basseng"],
|
||||
"home_cinema": ["heimekino"]
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"living_room": ["salon", "pokój dzienny", "pokój gościnny"],
|
||||
"bedroom": ["sypialnia"],
|
||||
"kids_room": [
|
||||
"pokój dziecięcy",
|
||||
"pokój dziecka",
|
||||
"pokój dzieci",
|
||||
"pokój zabaw"
|
||||
],
|
||||
"kitchen": ["kuchnia", "aneks kuchenny"],
|
||||
"dining_room": ["jadalnia"],
|
||||
"bathroom": ["łazienka", "prysznic"],
|
||||
"toilet": ["toaleta", "wc", "ubikacja"],
|
||||
"office": ["biuro", "gabinet", "pracownia"],
|
||||
"laundry_room": ["pralnia"],
|
||||
"hallway": ["korytarz", "przedpokój", "hol", "wiatrołap", "sień"],
|
||||
"stairs": ["schody", "klatka schodowa"],
|
||||
"garage": ["garaż", "wiata"],
|
||||
"garden": ["ogród", "ogródek", "trawnik", "szklarnia"],
|
||||
"terrace": ["taras", "balkon", "weranda"],
|
||||
"basement": ["piwnica", "suterena"],
|
||||
"attic": ["strych", "poddasze"],
|
||||
"storage": ["spiżarnia", "schowek", "magazyn", "komórka", "garderoba"],
|
||||
"utility_room": ["kotłownia", "pomieszczenie techniczne", "serwerownia"],
|
||||
"gym": ["siłownia"],
|
||||
"pool": ["basen"],
|
||||
"home_cinema": ["kino domowe", "sala kinowa"]
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"living_room": ["sala de estar", "sala", "living"],
|
||||
"bedroom": ["quarto", "suíte", "dormitório", "quarto de hóspedes"],
|
||||
"kids_room": [
|
||||
"quarto das crianças",
|
||||
"quarto infantil",
|
||||
"quarto do bebê",
|
||||
"brinquedoteca"
|
||||
],
|
||||
"kitchen": ["cozinha"],
|
||||
"dining_room": ["sala de jantar", "copa"],
|
||||
"bathroom": ["banheiro", "chuveiro"],
|
||||
"toilet": ["lavabo", "toalete", "vaso sanitário"],
|
||||
"office": ["escritório", "home office"],
|
||||
"laundry_room": ["lavanderia", "área de serviço"],
|
||||
"hallway": ["corredor", "entrada", "hall", "hall de entrada"],
|
||||
"stairs": ["escada", "escadas"],
|
||||
"garage": ["garagem"],
|
||||
"garden": ["jardim", "quintal", "gramado", "estufa", "horta"],
|
||||
"terrace": ["terraço", "varanda", "sacada", "pátio", "área gourmet"],
|
||||
"basement": ["porão", "subsolo"],
|
||||
"attic": ["sótão"],
|
||||
"storage": ["depósito", "despensa", "almoxarifado", "quartinho"],
|
||||
"utility_room": ["casa de máquinas", "sala técnica"],
|
||||
"gym": ["academia"],
|
||||
"pool": ["piscina"],
|
||||
"home_cinema": ["home theater", "sala de cinema", "sala de tv"]
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"living_room": ["sala de estar", "sala", "salão"],
|
||||
"bedroom": ["quarto", "quarto de dormir", "suíte", "quarto de hóspedes"],
|
||||
"kids_room": [
|
||||
"quarto das crianças",
|
||||
"quarto infantil",
|
||||
"quarto do bebé",
|
||||
"sala de brincar"
|
||||
],
|
||||
"kitchen": ["cozinha", "kitchenette"],
|
||||
"dining_room": ["sala de jantar"],
|
||||
"bathroom": ["casa de banho", "banheira", "duche"],
|
||||
"toilet": ["wc", "sanita", "lavabo"],
|
||||
"office": ["escritório", "gabinete"],
|
||||
"laundry_room": ["lavandaria"],
|
||||
"hallway": ["corredor", "entrada", "hall", "vestíbulo"],
|
||||
"stairs": ["escada", "escadas"],
|
||||
"garage": ["garagem"],
|
||||
"garden": ["jardim", "quintal", "relvado", "estufa", "horta"],
|
||||
"terrace": ["terraço", "varanda", "alpendre", "pátio"],
|
||||
"basement": ["cave", "cave de arrumos"],
|
||||
"attic": ["sótão", "águas furtadas"],
|
||||
"storage": ["arrecadação", "despensa", "armazém", "arrumos"],
|
||||
"utility_room": ["sala técnica", "casa das máquinas"],
|
||||
"gym": ["ginásio"],
|
||||
"pool": ["piscina"],
|
||||
"home_cinema": ["cinema em casa", "sala de cinema", "sala de tv"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["sufragerie", "living", "cameră de zi"],
|
||||
"bedroom": ["dormitor", "dormitorul", "cameră de oaspeți"],
|
||||
"kids_room": ["camera copiilor", "camera copilului", "cameră de joacă"],
|
||||
"kitchen": ["bucătărie", "bucătăria"],
|
||||
"dining_room": ["sala de mese", "dining"],
|
||||
"bathroom": ["baie", "baia", "duș"],
|
||||
"toilet": ["toaletă", "wc"],
|
||||
"office": ["birou", "birou acasă"],
|
||||
"laundry_room": ["spălătorie"],
|
||||
"hallway": ["hol", "hol de intrare", "coridor", "intrare"],
|
||||
"stairs": ["scări", "scara"],
|
||||
"garage": ["garaj"],
|
||||
"garden": ["grădină", "curte", "gazon", "seră"],
|
||||
"terrace": ["terasă", "balcon", "verandă"],
|
||||
"basement": ["subsol", "pivniță"],
|
||||
"attic": ["pod", "mansardă"],
|
||||
"storage": ["debara", "cămară", "depozit", "magazie"],
|
||||
"utility_room": ["centrală termică", "cameră tehnică"],
|
||||
"gym": ["sală de sport", "sala de fitness"],
|
||||
"pool": ["piscină"],
|
||||
"home_cinema": ["cinematograf acasă", "home cinema"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["гостиная", "зал", "общая комната"],
|
||||
"bedroom": ["спальня", "гостевая"],
|
||||
"kids_room": ["детская", "игровая"],
|
||||
"kitchen": ["кухня"],
|
||||
"dining_room": ["столовая"],
|
||||
"bathroom": ["ванная", "ванная комната", "душевая", "санузел"],
|
||||
"toilet": ["туалет", "уборная", "wc"],
|
||||
"office": ["кабинет", "офис"],
|
||||
"laundry_room": ["прачечная", "постирочная"],
|
||||
"hallway": ["прихожая", "коридор", "холл", "тамбур"],
|
||||
"stairs": ["лестница"],
|
||||
"garage": ["гараж", "навес"],
|
||||
"garden": ["сад", "двор", "огород", "газон", "теплица"],
|
||||
"terrace": ["терраса", "балкон", "веранда", "лоджия"],
|
||||
"basement": ["подвал", "погреб", "цокольный этаж"],
|
||||
"attic": ["чердак", "мансарда"],
|
||||
"storage": ["кладовая", "кладовка", "гардеробная", "сарай"],
|
||||
"utility_room": ["котельная", "техническое помещение", "серверная"],
|
||||
"gym": ["спортзал", "тренажерный зал"],
|
||||
"pool": ["бассейн"],
|
||||
"home_cinema": ["домашний кинотеатр", "кинозал"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["obývačka", "obývacia izba"],
|
||||
"bedroom": ["spálňa", "izba pre hostí"],
|
||||
"kids_room": ["detská izba", "herňa"],
|
||||
"kitchen": ["kuchyňa"],
|
||||
"dining_room": ["jedáleň"],
|
||||
"bathroom": ["kúpeľňa", "sprcha"],
|
||||
"toilet": ["toaleta", "wc", "záchod"],
|
||||
"office": ["pracovňa", "kancelária"],
|
||||
"laundry_room": ["práčovňa"],
|
||||
"hallway": ["chodba", "predsieň", "hala"],
|
||||
"stairs": ["schody", "schodisko"],
|
||||
"garage": ["garáž"],
|
||||
"garden": ["záhrada", "trávnik", "skleník"],
|
||||
"terrace": ["terasa", "balkón", "veranda"],
|
||||
"basement": ["pivnica", "suterén"],
|
||||
"attic": ["povala", "podkrovie"],
|
||||
"storage": ["sklad", "špajza", "komora"],
|
||||
"utility_room": ["technická miestnosť", "kotolňa"],
|
||||
"gym": ["posilňovňa", "fitness"],
|
||||
"pool": ["bazén"],
|
||||
"home_cinema": ["domáce kino"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["dnevna soba", "dnevni prostor"],
|
||||
"bedroom": ["spalnica", "soba za goste"],
|
||||
"kids_room": ["otroška soba", "igralnica"],
|
||||
"kitchen": ["kuhinja"],
|
||||
"dining_room": ["jedilnica"],
|
||||
"bathroom": ["kopalnica", "tuš"],
|
||||
"toilet": ["stranišče", "wc"],
|
||||
"office": ["pisarna", "delovna soba"],
|
||||
"laundry_room": ["pralnica"],
|
||||
"hallway": ["hodnik", "predsoba", "vhod"],
|
||||
"stairs": ["stopnice", "stopnišče"],
|
||||
"garage": ["garaža"],
|
||||
"garden": ["vrt", "trata", "rastlinjak"],
|
||||
"terrace": ["terasa", "balkon", "veranda"],
|
||||
"basement": ["klet"],
|
||||
"attic": ["podstrešje"],
|
||||
"storage": ["shramba", "skladišče", "lopa"],
|
||||
"utility_room": ["tehnični prostor", "kotlovnica"],
|
||||
"gym": ["fitnes"],
|
||||
"pool": ["bazen"],
|
||||
"home_cinema": ["domači kino"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["dhoma e ndenjes", "sallon", "ndenjja"],
|
||||
"bedroom": ["dhoma e gjumit", "dhoma e mysafirëve"],
|
||||
"kids_room": ["dhoma e fëmijëve", "dhoma e lojërave"],
|
||||
"kitchen": ["kuzhina", "kuzhinë"],
|
||||
"dining_room": ["dhoma e ngrënies"],
|
||||
"bathroom": ["banjo", "banja", "dush"],
|
||||
"toilet": ["tualet", "wc"],
|
||||
"office": ["zyra", "zyrë", "studio"],
|
||||
"laundry_room": ["lavanderi"],
|
||||
"hallway": ["korridor", "hyrje", "holl"],
|
||||
"stairs": ["shkallë", "shkallët"],
|
||||
"garage": ["garazh"],
|
||||
"garden": ["kopsht", "oborr", "serrë"],
|
||||
"terrace": ["tarracë", "ballkon", "verandë"],
|
||||
"basement": ["bodrum", "qilar"],
|
||||
"attic": ["papafingo"],
|
||||
"storage": ["depo", "magazinë", "qilar ushqimesh"],
|
||||
"utility_room": ["dhoma teknike"],
|
||||
"gym": ["palestër"],
|
||||
"pool": ["pishinë"],
|
||||
"home_cinema": ["kinema shtëpiake"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["dnevna soba", "dnevni boravak"],
|
||||
"bedroom": ["spavaća soba", "soba za goste"],
|
||||
"kids_room": ["dečja soba", "igraonica"],
|
||||
"kitchen": ["kuhinja"],
|
||||
"dining_room": ["trpezarija"],
|
||||
"bathroom": ["kupatilo", "tuš"],
|
||||
"toilet": ["wc", "toalet"],
|
||||
"office": ["kancelarija", "radna soba"],
|
||||
"laundry_room": ["vešernica"],
|
||||
"hallway": ["hodnik", "predsoblje", "ulaz"],
|
||||
"stairs": ["stepenice", "stepenište"],
|
||||
"garage": ["garaža"],
|
||||
"garden": ["bašta", "dvorište", "travnjak", "staklenik"],
|
||||
"terrace": ["terasa", "balkon"],
|
||||
"basement": ["podrum"],
|
||||
"attic": ["tavan", "potkrovlje"],
|
||||
"storage": ["ostava", "špajz", "šupa"],
|
||||
"utility_room": ["kotlarnica"],
|
||||
"gym": ["teretana"],
|
||||
"pool": ["bazen"],
|
||||
"home_cinema": ["kućni bioskop"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["дневна соба", "дневни боравак"],
|
||||
"bedroom": ["спаваћа соба", "соба за госте"],
|
||||
"kids_room": ["дечја соба", "играоница"],
|
||||
"kitchen": ["кухиња"],
|
||||
"dining_room": ["трпезарија"],
|
||||
"bathroom": ["купатило", "туш"],
|
||||
"toilet": ["тоалет", "wc"],
|
||||
"office": ["канцеларија", "радна соба"],
|
||||
"laundry_room": ["вешерница"],
|
||||
"hallway": ["ходник", "предсобље", "улаз"],
|
||||
"stairs": ["степенице", "степениште"],
|
||||
"garage": ["гаража"],
|
||||
"garden": ["башта", "двориште", "травњак", "стакленик"],
|
||||
"terrace": ["тераса", "балкон"],
|
||||
"basement": ["подрум"],
|
||||
"attic": ["таван", "поткровље"],
|
||||
"storage": ["остава", "шпајз", "шупа"],
|
||||
"utility_room": ["котларница"],
|
||||
"gym": ["теретана"],
|
||||
"pool": ["базен"],
|
||||
"home_cinema": ["кућни биоскоп"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["vardagsrum", "allrum", "sällskapsrum"],
|
||||
"bedroom": ["sovrum", "gästrum", "master bedroom"],
|
||||
"kids_room": ["barnrum", "lekrum"],
|
||||
"kitchen": ["kök"],
|
||||
"dining_room": ["matsal", "matrum"],
|
||||
"bathroom": ["badrum", "dusch", "duschrum"],
|
||||
"toilet": ["toalett", "wc", "gästtoalett"],
|
||||
"office": ["kontor", "arbetsrum", "hemmakontor"],
|
||||
"laundry_room": ["tvättstuga", "tvättrum"],
|
||||
"hallway": ["hall", "hallen", "korridor", "entré", "tambur"],
|
||||
"stairs": ["trappa", "trapphus"],
|
||||
"garage": ["garage", "carport"],
|
||||
"garden": ["trädgård", "gräsmatta", "växthus", "tomt"],
|
||||
"terrace": ["terrass", "altan", "balkong", "veranda", "uteplats"],
|
||||
"basement": ["källare"],
|
||||
"attic": ["vind", "vindsförråd"],
|
||||
"storage": ["förråd", "skafferi", "klädkammare", "bod"],
|
||||
"utility_room": ["pannrum", "teknikrum", "serverrum"],
|
||||
"gym": ["gym", "träningsrum"],
|
||||
"pool": ["pool", "simbassäng"],
|
||||
"home_cinema": ["hemmabio", "biorum", "tv rum"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["வரவேற்பறை", "ஹால்", "லிவிங் ரூம்"],
|
||||
"bedroom": ["படுக்கையறை", "விருந்தினர் அறை"],
|
||||
"kids_room": ["குழந்தைகள் அறை"],
|
||||
"kitchen": ["சமையலறை"],
|
||||
"dining_room": ["சாப்பாட்டு அறை"],
|
||||
"bathroom": ["குளியலறை"],
|
||||
"toilet": ["கழிப்பறை", "wc"],
|
||||
"office": ["அலுவலகம்", "படிப்பறை"],
|
||||
"laundry_room": ["சலவை அறை"],
|
||||
"hallway": ["நடைபாதை", "நுழைவாயில்"],
|
||||
"stairs": ["படிக்கட்டு"],
|
||||
"garage": ["கேரேஜ்", "வாகன நிறுத்தம்"],
|
||||
"garden": ["தோட்டம்", "முற்றம்"],
|
||||
"terrace": ["மொட்டை மாடி", "பால்கனி"],
|
||||
"basement": ["அடித்தளம்"],
|
||||
"attic": ["பரண்"],
|
||||
"storage": ["சேமிப்பு அறை", "கிடங்கு"],
|
||||
"utility_room": ["பயன்பாட்டு அறை"],
|
||||
"gym": ["உடற்பயிற்சி அறை", "ஜிம்"],
|
||||
"pool": ["நீச்சல் குளம்"],
|
||||
"home_cinema": ["ஹோம் தியேட்டர்"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["హాల్", "లివింగ్ రూమ్", "కూర్చునే గది"],
|
||||
"bedroom": ["పడకగది", "బెడ్ రూమ్", "అతిథి గది"],
|
||||
"kids_room": ["పిల్లల గది"],
|
||||
"kitchen": ["వంటగది", "కిచెన్"],
|
||||
"dining_room": ["భోజనాల గది", "డైనింగ్ రూమ్"],
|
||||
"bathroom": ["స్నానాల గది", "బాత్రూమ్"],
|
||||
"toilet": ["మరుగుదొడ్డి", "టాయిలెట్", "wc"],
|
||||
"office": ["ఆఫీసు", "కార్యాలయం", "చదువుకునే గది"],
|
||||
"laundry_room": ["లాండ్రీ"],
|
||||
"hallway": ["వరండా", "కారిడార్", "ప్రవేశ ద్వారం"],
|
||||
"stairs": ["మెట్లు"],
|
||||
"garage": ["గ్యారేజ్"],
|
||||
"garden": ["తోట", "పెరడు"],
|
||||
"terrace": ["డాబా", "బాల్కనీ", "టెర్రస్"],
|
||||
"basement": ["నేలమాళిగ", "బేస్మెంట్"],
|
||||
"attic": ["అటక"],
|
||||
"storage": ["స్టోర్ రూమ్", "గోదాము"],
|
||||
"utility_room": ["యుటిలిటీ రూమ్"],
|
||||
"gym": ["వ్యాయామశాల", "జిమ్"],
|
||||
"pool": ["ఈత కొలను", "స్విమ్మింగ్ పూల్"],
|
||||
"home_cinema": ["హోమ్ థియేటర్"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["ห้องนั่งเล่น", "ห้องรับแขก"],
|
||||
"bedroom": ["ห้องนอน", "ห้องนอนแขก"],
|
||||
"kids_room": ["ห้องเด็ก", "ห้องนอนเด็ก", "ห้องเล่น"],
|
||||
"kitchen": ["ห้องครัว", "ครัว"],
|
||||
"dining_room": ["ห้องทานข้าว", "ห้องอาหาร"],
|
||||
"bathroom": ["ห้องน้ำ", "ห้องอาบน้ำ"],
|
||||
"toilet": ["ห้องส้วม", "สุขา"],
|
||||
"office": ["ห้องทำงาน", "ออฟฟิศ"],
|
||||
"laundry_room": ["ห้องซักผ้า"],
|
||||
"hallway": ["ทางเดิน", "โถงทางเดิน", "ทางเข้า"],
|
||||
"stairs": ["บันได"],
|
||||
"garage": ["โรงรถ", "ที่จอดรถ"],
|
||||
"garden": ["สวน", "สนามหญ้า", "ลานบ้าน"],
|
||||
"terrace": ["ระเบียง", "ชาน", "เฉลียง"],
|
||||
"basement": ["ชั้นใต้ดิน"],
|
||||
"attic": ["ห้องใต้หลังคา"],
|
||||
"storage": ["ห้องเก็บของ", "โกดัง"],
|
||||
"utility_room": ["ห้องเครื่อง"],
|
||||
"gym": ["ห้องออกกำลังกาย", "ยิม"],
|
||||
"pool": ["สระว่ายน้ำ", "สระน้ำ"],
|
||||
"home_cinema": ["โฮมเธียเตอร์", "ห้องดูหนัง"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["oturma odası", "salon"],
|
||||
"bedroom": ["yatak odası", "misafir odası"],
|
||||
"kids_room": ["çocuk odası", "oyun odası"],
|
||||
"kitchen": ["mutfak"],
|
||||
"dining_room": ["yemek odası"],
|
||||
"bathroom": ["banyo", "duş"],
|
||||
"toilet": ["tuvalet", "wc"],
|
||||
"office": ["ofis", "çalışma odası"],
|
||||
"laundry_room": ["çamaşır odası"],
|
||||
"hallway": ["koridor", "hol", "antre", "giriş"],
|
||||
"stairs": ["merdiven"],
|
||||
"garage": ["garaj"],
|
||||
"garden": ["bahçe", "çim", "sera"],
|
||||
"terrace": ["teras", "balkon", "veranda"],
|
||||
"basement": ["bodrum", "mahzen"],
|
||||
"attic": ["çatı katı", "tavan arası"],
|
||||
"storage": ["depo", "kiler"],
|
||||
"utility_room": ["kazan dairesi", "teknik oda"],
|
||||
"gym": ["spor salonu"],
|
||||
"pool": ["havuz"],
|
||||
"home_cinema": ["ev sineması"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["вітальня", "зала"],
|
||||
"bedroom": ["спальня", "гостьова кімната"],
|
||||
"kids_room": ["дитяча", "дитяча кімната", "ігрова"],
|
||||
"kitchen": ["кухня"],
|
||||
"dining_room": ["їдальня"],
|
||||
"bathroom": ["ванна", "ванна кімната", "душова", "санвузол"],
|
||||
"toilet": ["туалет", "вбиральня", "wc"],
|
||||
"office": ["кабінет", "офіс"],
|
||||
"laundry_room": ["пральня"],
|
||||
"hallway": ["передпокій", "коридор", "хол", "тамбур"],
|
||||
"stairs": ["сходи"],
|
||||
"garage": ["гараж", "навіс"],
|
||||
"garden": ["сад", "двір", "город", "газон", "теплиця"],
|
||||
"terrace": ["тераса", "балкон", "веранда", "лоджія"],
|
||||
"basement": ["підвал", "льох", "цокольний поверх"],
|
||||
"attic": ["горище", "мансарда"],
|
||||
"storage": ["комора", "гардеробна", "сарай"],
|
||||
"utility_room": ["котельня", "технічне приміщення"],
|
||||
"gym": ["спортзал", "тренажерний зал"],
|
||||
"pool": ["басейн"],
|
||||
"home_cinema": ["домашній кінотеатр", "кінозал"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["لاؤنج", "ڈرائنگ روم", "بیٹھک"],
|
||||
"bedroom": ["سونے کا کمرہ", "بیڈروم", "مہمان خانہ"],
|
||||
"kids_room": ["بچوں کا کمرہ"],
|
||||
"kitchen": ["باورچی خانہ", "کچن"],
|
||||
"dining_room": ["کھانے کا کمرہ", "ڈائننگ روم"],
|
||||
"bathroom": ["غسل خانہ", "باتھ روم"],
|
||||
"toilet": ["بیت الخلا", "ٹوائلٹ", "wc"],
|
||||
"office": ["دفتر", "آفس", "اسٹڈی"],
|
||||
"laundry_room": ["لانڈری"],
|
||||
"hallway": ["راہداری", "داخلہ"],
|
||||
"stairs": ["سیڑھیاں"],
|
||||
"garage": ["گیراج", "پورچ"],
|
||||
"garden": ["باغ", "باغیچہ", "صحن", "لان"],
|
||||
"terrace": ["چھت", "بالکونی", "برآمدہ", "ٹیرس"],
|
||||
"basement": ["تہ خانہ"],
|
||||
"attic": ["اٹاری"],
|
||||
"storage": ["اسٹور", "گودام"],
|
||||
"utility_room": ["یوٹیلیٹی روم"],
|
||||
"gym": ["جم"],
|
||||
"pool": ["سوئمنگ پول", "تالاب"],
|
||||
"home_cinema": ["ہوم تھیٹر"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["phòng khách"],
|
||||
"bedroom": ["phòng ngủ", "phòng ngủ khách"],
|
||||
"kids_room": ["phòng trẻ em", "phòng bé", "phòng con", "phòng chơi"],
|
||||
"kitchen": ["bếp", "nhà bếp", "phòng bếp"],
|
||||
"dining_room": ["phòng ăn"],
|
||||
"bathroom": ["phòng tắm", "nhà tắm"],
|
||||
"toilet": ["nhà vệ sinh", "toilet", "wc"],
|
||||
"office": ["văn phòng", "phòng làm việc"],
|
||||
"laundry_room": ["phòng giặt"],
|
||||
"hallway": ["hành lang", "sảnh", "lối vào"],
|
||||
"stairs": ["cầu thang"],
|
||||
"garage": ["nhà để xe", "gara"],
|
||||
"garden": ["vườn", "sân", "sân vườn"],
|
||||
"terrace": ["sân thượng", "ban công", "hiên"],
|
||||
"basement": ["tầng hầm"],
|
||||
"attic": ["gác mái", "gác xép"],
|
||||
"storage": ["kho", "phòng kho"],
|
||||
"utility_room": ["phòng kỹ thuật"],
|
||||
"gym": ["phòng tập", "phòng gym"],
|
||||
"pool": ["hồ bơi", "bể bơi"],
|
||||
"home_cinema": ["phòng chiếu phim", "rạp tại gia"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["客厅", "起居室"],
|
||||
"bedroom": ["卧室", "主卧", "次卧", "客房", "睡房"],
|
||||
"kids_room": ["儿童房", "婴儿房", "游戏室"],
|
||||
"kitchen": ["厨房"],
|
||||
"dining_room": ["餐厅", "饭厅"],
|
||||
"bathroom": ["浴室", "卫生间", "洗手间", "淋浴间"],
|
||||
"toilet": ["厕所"],
|
||||
"office": ["书房", "办公室", "工作室"],
|
||||
"laundry_room": ["洗衣房"],
|
||||
"hallway": ["走廊", "门厅", "玄关", "过道"],
|
||||
"stairs": ["楼梯"],
|
||||
"garage": ["车库"],
|
||||
"garden": ["花园", "院子", "庭院", "菜园", "温室"],
|
||||
"terrace": ["露台", "阳台", "天台"],
|
||||
"basement": ["地下室"],
|
||||
"attic": ["阁楼"],
|
||||
"storage": ["储藏室", "储物间", "仓库", "衣帽间"],
|
||||
"utility_room": ["设备间", "锅炉房", "机房"],
|
||||
"gym": ["健身房"],
|
||||
"pool": ["泳池", "游泳池"],
|
||||
"home_cinema": ["家庭影院", "影音室"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"living_room": ["客廳", "起居室"],
|
||||
"bedroom": ["臥室", "主臥", "次臥", "客房", "睡房", "房間"],
|
||||
"kids_room": ["兒童房", "嬰兒房", "遊戲室"],
|
||||
"kitchen": ["廚房"],
|
||||
"dining_room": ["餐廳", "飯廳"],
|
||||
"bathroom": ["浴室", "衛浴", "淋浴間"],
|
||||
"toilet": ["廁所", "洗手間"],
|
||||
"office": ["書房", "辦公室", "工作室"],
|
||||
"laundry_room": ["洗衣房", "洗衣間"],
|
||||
"hallway": ["走廊", "玄關", "門廳", "走道"],
|
||||
"stairs": ["樓梯"],
|
||||
"garage": ["車庫"],
|
||||
"garden": ["花園", "院子", "庭院", "溫室"],
|
||||
"terrace": ["露台", "陽台", "天台"],
|
||||
"basement": ["地下室"],
|
||||
"attic": ["閣樓"],
|
||||
"storage": ["儲藏室", "儲物間", "倉庫", "衣帽間"],
|
||||
"utility_room": ["機房", "鍋爐房", "設備間"],
|
||||
"gym": ["健身房"],
|
||||
"pool": ["泳池", "游泳池"],
|
||||
"home_cinema": ["家庭劇院", "影音室"]
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
export const ROOM_ICONS = {
|
||||
living_room: [
|
||||
"mdi:sofa",
|
||||
"mdi:sofa-single",
|
||||
"mdi:television",
|
||||
"mdi:fireplace",
|
||||
"mdi:floor-lamp",
|
||||
],
|
||||
bedroom: ["mdi:bed", "mdi:bed-king", "mdi:bed-double", "mdi:lamp"],
|
||||
kids_room: ["mdi:teddy-bear", "mdi:toy-brick", "mdi:bunk-bed", "mdi:cradle"],
|
||||
kitchen: [
|
||||
"mdi:stove",
|
||||
"mdi:fridge",
|
||||
"mdi:countertop",
|
||||
"mdi:chef-hat",
|
||||
"mdi:pot-steam",
|
||||
"mdi:coffee-maker",
|
||||
],
|
||||
dining_room: [
|
||||
"mdi:silverware-fork-knife",
|
||||
"mdi:table-chair",
|
||||
"mdi:table-furniture",
|
||||
"mdi:glass-wine",
|
||||
],
|
||||
bathroom: [
|
||||
"mdi:shower",
|
||||
"mdi:bathtub",
|
||||
"mdi:shower-head",
|
||||
"mdi:toothbrush",
|
||||
"mdi:hair-dryer",
|
||||
],
|
||||
toilet: ["mdi:toilet", "mdi:paper-roll"],
|
||||
office: [
|
||||
"mdi:desk",
|
||||
"mdi:laptop",
|
||||
"mdi:monitor",
|
||||
"mdi:chair-rolling",
|
||||
"mdi:bookshelf",
|
||||
],
|
||||
laundry_room: [
|
||||
"mdi:washing-machine",
|
||||
"mdi:tumble-dryer",
|
||||
"mdi:iron",
|
||||
"mdi:hanger",
|
||||
],
|
||||
hallway: ["mdi:door", "mdi:door-open", "mdi:coat-rack", "mdi:key"],
|
||||
stairs: ["mdi:stairs", "mdi:stairs-up", "mdi:stairs-down"],
|
||||
garage: ["mdi:garage", "mdi:garage-variant", "mdi:car", "mdi:tools"],
|
||||
garden: [
|
||||
"mdi:flower",
|
||||
"mdi:tree",
|
||||
"mdi:grass",
|
||||
"mdi:sprout",
|
||||
"mdi:watering-can",
|
||||
"mdi:greenhouse",
|
||||
],
|
||||
terrace: [
|
||||
"mdi:balcony",
|
||||
"mdi:grill",
|
||||
"mdi:umbrella-outline",
|
||||
"mdi:coach-lamp",
|
||||
"mdi:patio-heater",
|
||||
],
|
||||
basement: [
|
||||
"mdi:home-floor-negative-1",
|
||||
"mdi:stairs-down",
|
||||
"mdi:water-boiler",
|
||||
],
|
||||
attic: ["mdi:home-roof", "mdi:package-variant-closed"],
|
||||
storage: ["mdi:archive", "mdi:package-variant-closed", "mdi:warehouse"],
|
||||
utility_room: [
|
||||
"mdi:water-boiler",
|
||||
"mdi:heat-pump",
|
||||
"mdi:server-network",
|
||||
"mdi:flash",
|
||||
],
|
||||
gym: ["mdi:dumbbell", "mdi:weight-lifter", "mdi:yoga", "mdi:run"],
|
||||
pool: ["mdi:pool", "mdi:swim"],
|
||||
home_cinema: ["mdi:theater", "mdi:projector", "mdi:television"],
|
||||
} as const satisfies Record<string, readonly string[]>;
|
||||
|
||||
export type RoomType = keyof typeof ROOM_ICONS;
|
||||
|
||||
type RoomKeywords = Partial<Record<RoomType, string[]>>;
|
||||
|
||||
export const ROOM_TYPES = Object.keys(ROOM_ICONS) as RoomType[];
|
||||
|
||||
export const isRoomType = (value: string): value is RoomType =>
|
||||
(ROOM_TYPES as string[]).includes(value);
|
||||
|
||||
// Languages written without spaces between words
|
||||
const NO_WORD_SPACING =
|
||||
/[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Thai}]/u;
|
||||
|
||||
const normalizeRoomText = (text: string): string =>
|
||||
text
|
||||
.normalize("NFD")
|
||||
.replace(/\p{M}/gu, "")
|
||||
.toLowerCase()
|
||||
.replace(/['’]/g, "")
|
||||
.replace(/[^\p{L}\p{N}]+/gu, " ")
|
||||
.trim();
|
||||
|
||||
interface RoomMatch {
|
||||
room: RoomType;
|
||||
start: number;
|
||||
end: number;
|
||||
}
|
||||
|
||||
const findMatches = (name: string, keywords: RoomKeywords): RoomMatch[] => {
|
||||
const text = ` ${normalizeRoomText(name)} `;
|
||||
const candidates: RoomMatch[] = [];
|
||||
for (const room of ROOM_TYPES) {
|
||||
for (const keyword of keywords[room] ?? []) {
|
||||
const phrase = normalizeRoomText(keyword);
|
||||
if (!phrase) {
|
||||
continue;
|
||||
}
|
||||
const needle = NO_WORD_SPACING.test(phrase) ? phrase : ` ${phrase} `;
|
||||
const start = text.indexOf(needle);
|
||||
if (start !== -1) {
|
||||
candidates.push({ room, start, end: start + needle.length });
|
||||
}
|
||||
}
|
||||
}
|
||||
// The longest phrase wins, so "guest bedroom" is not also read as "bedroom"
|
||||
candidates.sort((a, b) => b.end - b.start - (a.end - a.start));
|
||||
const kept: RoomMatch[] = [];
|
||||
for (const match of candidates) {
|
||||
const overlaps = kept.some(
|
||||
(other) => match.start < other.end - 1 && other.start < match.end - 1
|
||||
);
|
||||
if (!overlaps) {
|
||||
kept.push(match);
|
||||
}
|
||||
}
|
||||
return kept.sort((a, b) => a.start - b.start);
|
||||
};
|
||||
|
||||
const matchRoomTypes = (
|
||||
names: string[],
|
||||
keywords: RoomKeywords
|
||||
): RoomType[] => {
|
||||
const rooms = new Set<RoomType>();
|
||||
for (const name of names) {
|
||||
for (const match of findMatches(name, keywords)) {
|
||||
rooms.add(match.room);
|
||||
}
|
||||
}
|
||||
return [...rooms];
|
||||
};
|
||||
|
||||
const roomIconSuggestions = (rooms: RoomType[]): string[] => [
|
||||
...new Set(rooms.flatMap((room) => ROOM_ICONS[room])),
|
||||
];
|
||||
|
||||
const KEYWORDS: Record<string, Promise<RoomKeywords | undefined>> = {};
|
||||
|
||||
const loadRoomKeywords = (language: string) => {
|
||||
KEYWORDS[language] ??= import(`./area_icon_keywords/${language}.json`)
|
||||
.then((module) => module.default as RoomKeywords)
|
||||
.catch(() => undefined);
|
||||
return KEYWORDS[language];
|
||||
};
|
||||
|
||||
export const getAreaIconSuggestions = async (
|
||||
names: string[],
|
||||
language: string
|
||||
): Promise<string[]> => {
|
||||
const keywords =
|
||||
(await loadRoomKeywords(language)) ??
|
||||
(await loadRoomKeywords(language.split("-")[0]));
|
||||
if (!keywords) {
|
||||
return [];
|
||||
}
|
||||
return roomIconSuggestions(matchRoomTypes(names, keywords));
|
||||
};
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import type { CSSResultGroup } from "lit";
|
||||
import type { CSSResultGroup, PropertyValues } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
@@ -29,6 +29,10 @@ import type {
|
||||
AreaRegistryEntryMutableParams,
|
||||
} from "../../../data/area/area_registry";
|
||||
import { deleteAreaRegistryEntry } from "../../../data/area/area_registry";
|
||||
import {
|
||||
getAreaIconSuggestions,
|
||||
ROOM_ICONS,
|
||||
} from "../../../data/area_icon_suggestions";
|
||||
import {
|
||||
SENSOR_DEVICE_CLASS_HUMIDITY,
|
||||
SENSOR_DEVICE_CLASS_TEMPERATURE,
|
||||
@@ -96,6 +100,12 @@ class DialogAreaDetail
|
||||
|
||||
@state() private _submitting = false;
|
||||
|
||||
@state() private _suggestedIcons?: string[];
|
||||
|
||||
private _iconFollowsName = false;
|
||||
|
||||
private _iconSuggestionRequest = 0;
|
||||
|
||||
@state() private _open = false;
|
||||
|
||||
@state() private _suggestionInclude: MetadataSuggestionInclude = {
|
||||
@@ -128,6 +138,7 @@ class DialogAreaDetail
|
||||
this._temperatureEntity = null;
|
||||
this._humidityEntity = null;
|
||||
}
|
||||
this._iconFollowsName = !this._params.entry;
|
||||
this._open = true;
|
||||
this._initDirtyTracking({ type: "deep" }, this._currentState());
|
||||
await this.updateComplete;
|
||||
@@ -151,6 +162,34 @@ class DialogAreaDetail
|
||||
return true;
|
||||
}
|
||||
|
||||
protected willUpdate(changedProps: PropertyValues) {
|
||||
super.willUpdate(changedProps);
|
||||
if (changedProps.has("_name") || changedProps.has("_aliases")) {
|
||||
this._updateSuggestedIcons();
|
||||
}
|
||||
}
|
||||
|
||||
private async _updateSuggestedIcons() {
|
||||
const request = ++this._iconSuggestionRequest;
|
||||
const icons = await getAreaIconSuggestions(
|
||||
[this._name ?? "", ...(this._aliases ?? [])],
|
||||
this.hass.locale.language
|
||||
);
|
||||
if (request !== this._iconSuggestionRequest || !this._open) {
|
||||
return;
|
||||
}
|
||||
this._suggestedIcons = icons;
|
||||
if (this._iconFollowsName) {
|
||||
const untouched = !this.isDirtyState;
|
||||
this._icon = icons[0] ?? null;
|
||||
if (untouched) {
|
||||
this._initDirtyTracking({ type: "deep" }, this._currentState());
|
||||
} else {
|
||||
this._updateDirtyState(this._currentState());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _entityName(entityId: string | null): string | null {
|
||||
const stateObj = entityId ? this.hass.states[entityId] : undefined;
|
||||
return stateObj ? this.hass.formatEntityName(stateObj) : null;
|
||||
@@ -193,6 +232,7 @@ class DialogAreaDetail
|
||||
.value=${this._icon}
|
||||
@value-changed=${this._iconChanged}
|
||||
.label=${this.hass.localize("ui.panel.config.areas.editor.icon")}
|
||||
.suggestedIcons=${this._suggestedIcons}
|
||||
></ha-icon-picker>
|
||||
|
||||
<ha-floor-picker
|
||||
@@ -300,6 +340,7 @@ class DialogAreaDetail
|
||||
this._suggestionInclude = {
|
||||
...this._suggestionInclude,
|
||||
name: this._name.trim() === "",
|
||||
room: !this._icon || this._iconFollowsName,
|
||||
};
|
||||
|
||||
return generateMetadataSuggestionTask<{
|
||||
@@ -349,6 +390,11 @@ class DialogAreaDetail
|
||||
this._floor = processed.floor;
|
||||
}
|
||||
|
||||
if (processed.room && (!this._icon || this._iconFollowsName)) {
|
||||
this._icon = ROOM_ICONS[processed.room][0];
|
||||
this._iconFollowsName = false;
|
||||
}
|
||||
|
||||
this._updateDirtyState(this._currentState());
|
||||
}
|
||||
|
||||
@@ -464,6 +510,7 @@ class DialogAreaDetail
|
||||
private _iconChanged(ev) {
|
||||
this._error = undefined;
|
||||
this._icon = ev.detail.value;
|
||||
this._iconFollowsName = false;
|
||||
this._updateDirtyState(this._currentState());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { dump } from "js-yaml";
|
||||
import type { AITaskStructure, GenDataTaskResult } from "../../../data/ai_task";
|
||||
import type { RoomType } from "../../../data/area_icon_suggestions";
|
||||
import { isRoomType, ROOM_TYPES } from "../../../data/area_icon_suggestions";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import type { SuggestWithAIGenerateTask } from "../../../components/ha-suggest-with-ai-button";
|
||||
import {
|
||||
@@ -14,6 +16,7 @@ export interface MetadataSuggestionResult {
|
||||
category?: string;
|
||||
labels?: string[];
|
||||
floor?: string;
|
||||
room?: RoomType;
|
||||
}
|
||||
|
||||
export type MetadataSuggestionDomain =
|
||||
@@ -25,6 +28,7 @@ export interface MetadataSuggestionInclude {
|
||||
categories?: boolean;
|
||||
labels?: boolean;
|
||||
floor?: boolean;
|
||||
room?: boolean;
|
||||
}
|
||||
|
||||
export const SUGGESTION_INCLUDE_DEFAULT: MetadataSuggestionInclude = {
|
||||
@@ -86,6 +90,7 @@ export async function generateMetadataSuggestionTask<T>(
|
||||
// providers reject a select/enum schema with an empty options list.
|
||||
const includeCategories = categoryOptions.length > 0;
|
||||
const includeFloor = floorOptions.length > 0;
|
||||
const includeRoom = Boolean(include.room) && domain === "area";
|
||||
|
||||
const structure: AITaskStructure = {
|
||||
...(include.name && {
|
||||
@@ -139,6 +144,20 @@ export async function generateMetadataSuggestionTask<T>(
|
||||
},
|
||||
},
|
||||
}),
|
||||
...(includeRoom && {
|
||||
room: {
|
||||
description: `The type of room that best matches the ${domain}`,
|
||||
required: false,
|
||||
selector: {
|
||||
select: {
|
||||
options: ROOM_TYPES.map((room) => ({
|
||||
value: room,
|
||||
label: room.replace(/_/g, " "),
|
||||
})),
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
const requestedParts = [
|
||||
@@ -147,6 +166,7 @@ export async function generateMetadataSuggestionTask<T>(
|
||||
includeCategories ? "a category" : null,
|
||||
include.labels ? "labels" : null,
|
||||
includeFloor ? "a floor" : null,
|
||||
includeRoom ? "a room type" : null,
|
||||
].filter((entry): entry is string => entry !== null);
|
||||
|
||||
const categoryLabels: string[] = [
|
||||
@@ -233,6 +253,10 @@ export async function processMetadataSuggestion(
|
||||
const processed: MetadataSuggestionResult = {
|
||||
name: include.name ? result.data.name : undefined,
|
||||
description: include.description ? result.data.description : undefined,
|
||||
room:
|
||||
include.room && result.data.room && isRoomType(result.data.room)
|
||||
? result.data.room
|
||||
: undefined,
|
||||
};
|
||||
|
||||
// Convert category name to ID
|
||||
|
||||
@@ -95,7 +95,6 @@ import {
|
||||
showAlertDialog,
|
||||
showConfirmationDialog,
|
||||
} from "../../../dialogs/generic/show-dialog-box";
|
||||
import { showMoreInfoDialog } from "../../../dialogs/more-info/show-ha-more-info-dialog";
|
||||
import { showVoiceAssistantSetupDialog } from "../../../dialogs/voice-assistant-setup/show-voice-assistant-setup-dialog";
|
||||
import "../../../layouts/hass-error-screen";
|
||||
import "../../../layouts/hass-subpage";
|
||||
@@ -995,13 +994,7 @@ export class HaConfigDevicePage extends LitElement {
|
||||
(batteryDomain === "binary_sensor" ||
|
||||
!Number.isNaN(Number(battery.state)))
|
||||
? html`
|
||||
<button
|
||||
class="battery"
|
||||
aria-label=${`${this.hass.formatEntityName(
|
||||
battery
|
||||
)} ${this.hass.formatEntityState(battery)}`}
|
||||
@click=${this._showBatteryMoreInfo}
|
||||
>
|
||||
<div class="battery">
|
||||
${
|
||||
batteryDomain === "sensor"
|
||||
? this.hass.formatEntityState(battery)
|
||||
@@ -1011,7 +1004,7 @@ export class HaConfigDevicePage extends LitElement {
|
||||
.batteryStateObj=${battery}
|
||||
.batteryChargingStateObj=${batteryChargingState}
|
||||
></ha-battery-icon>
|
||||
</button>
|
||||
</div>
|
||||
`
|
||||
: ""
|
||||
}
|
||||
@@ -1394,15 +1387,6 @@ export class HaConfigDevicePage extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
private _showBatteryMoreInfo() {
|
||||
const batteryEntity = this._batteryEntity(
|
||||
this._entities(this.deviceId, this._entityReg, this.hass.devices)
|
||||
);
|
||||
if (batteryEntity) {
|
||||
showMoreInfoDialog(this, { entityId: batteryEntity.entity_id });
|
||||
}
|
||||
}
|
||||
|
||||
private _computeEntityName(
|
||||
entity: EntityRegistryEntry,
|
||||
devices: HomeAssistant["devices"]
|
||||
@@ -1772,19 +1756,6 @@ export class HaConfigDevicePage extends LitElement {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
white-space: nowrap;
|
||||
background: none;
|
||||
border: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font: inherit;
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
border-radius: var(--ha-border-radius-sm);
|
||||
}
|
||||
|
||||
.battery:focus-visible {
|
||||
outline: 2px solid var(--primary-color);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.column > *:not(:first-child) {
|
||||
|
||||
@@ -211,10 +211,6 @@ export const getMyRedirects = (): Redirects => ({
|
||||
tools_states: {
|
||||
redirect: "/config/tools/state",
|
||||
},
|
||||
tools_action_history: {
|
||||
component: "logbook",
|
||||
redirect: "/config/tools/action-history",
|
||||
},
|
||||
tools_actions: {
|
||||
redirect: "/config/tools/action",
|
||||
},
|
||||
|
||||
@@ -2,12 +2,12 @@ import { mdiDelete } from "@mdi/js";
|
||||
import type { CSSResultGroup, TemplateResult } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import "@home-assistant/components/card";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { relativeTime } from "../../common/datetime/relative_time";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import type { HASSDomCurrentTargetEvent } from "../../common/dom/fire_event";
|
||||
import "../../components/ha-button";
|
||||
import "../../components/ha-card";
|
||||
import "../../components/ha-icon-button";
|
||||
import type { HaIconButton } from "../../components/ha-icon-button";
|
||||
import "../../components/ha-settings-row";
|
||||
@@ -37,79 +37,83 @@ class HaLongLivedTokens extends LitElement {
|
||||
const accessTokens = this._accessTokens(this.refreshTokens);
|
||||
|
||||
return html`
|
||||
<hac-card>
|
||||
<h2 slot="header" class="header">
|
||||
${this.hass.localize(
|
||||
"ui.panel.profile.long_lived_access_tokens.header"
|
||||
)}
|
||||
</h2>
|
||||
${this.hass.localize(
|
||||
"ui.panel.profile.long_lived_access_tokens.description"
|
||||
<ha-card
|
||||
.header=${this.hass.localize(
|
||||
"ui.panel.profile.long_lived_access_tokens.header"
|
||||
)}
|
||||
>
|
||||
<div class="card-content">
|
||||
${this.hass.localize(
|
||||
"ui.panel.profile.long_lived_access_tokens.description"
|
||||
)}
|
||||
|
||||
<a
|
||||
href="https://contributors.home-assistant.io/core/internals/auth-api/#make-authenticated-requests"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.profile.long_lived_access_tokens.learn_auth_requests"
|
||||
)}
|
||||
</a>
|
||||
${
|
||||
!accessTokens.length
|
||||
? html`<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.profile.long_lived_access_tokens.empty_state"
|
||||
)}
|
||||
</p>`
|
||||
: accessTokens.map(
|
||||
(token) =>
|
||||
html`<ha-settings-row two-line>
|
||||
<span slot="heading">${token.client_name}</span>
|
||||
<div slot="description">
|
||||
${this.hass.localize(
|
||||
"ui.panel.profile.long_lived_access_tokens.created",
|
||||
{
|
||||
date: relativeTime(
|
||||
new Date(token.created_at),
|
||||
this.hass.locale
|
||||
),
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
${
|
||||
this._hasBeenUsed(token)
|
||||
? html`<div slot="description">
|
||||
${this.hass.localize(
|
||||
"ui.panel.profile.long_lived_access_tokens.last_used",
|
||||
{
|
||||
date: relativeTime(
|
||||
new Date(token.last_used_at),
|
||||
this.hass.locale
|
||||
),
|
||||
location: token.last_used_ip,
|
||||
}
|
||||
)}
|
||||
</div>`
|
||||
: nothing
|
||||
}
|
||||
<ha-icon-button
|
||||
.token=${token}
|
||||
.disabled=${token.is_current}
|
||||
.label=${this.hass.localize("ui.common.delete")}
|
||||
.path=${mdiDelete}
|
||||
@click=${this._deleteToken}
|
||||
></ha-icon-button>
|
||||
</ha-settings-row>`
|
||||
)
|
||||
}
|
||||
<ha-button slot="footer" @click=${this._createToken}>
|
||||
${this.hass.localize(
|
||||
"ui.panel.profile.long_lived_access_tokens.create"
|
||||
)}
|
||||
</ha-button>
|
||||
</hac-card>
|
||||
<a
|
||||
href="https://contributors.home-assistant.io/core/internals/auth-api/#make-authenticated-requests"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.profile.long_lived_access_tokens.learn_auth_requests"
|
||||
)}
|
||||
</a>
|
||||
${
|
||||
!accessTokens.length
|
||||
? html`<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.profile.long_lived_access_tokens.empty_state"
|
||||
)}
|
||||
</p>`
|
||||
: accessTokens.map(
|
||||
(token) =>
|
||||
html`<ha-settings-row two-line>
|
||||
<span slot="heading">${token.client_name}</span>
|
||||
<div slot="description">
|
||||
${this.hass.localize(
|
||||
"ui.panel.profile.long_lived_access_tokens.created",
|
||||
{
|
||||
date: relativeTime(
|
||||
new Date(token.created_at),
|
||||
this.hass.locale
|
||||
),
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
${
|
||||
this._hasBeenUsed(token)
|
||||
? html`<div slot="description">
|
||||
${this.hass.localize(
|
||||
"ui.panel.profile.long_lived_access_tokens.last_used",
|
||||
{
|
||||
date: relativeTime(
|
||||
new Date(token.last_used_at),
|
||||
this.hass.locale
|
||||
),
|
||||
location: token.last_used_ip,
|
||||
}
|
||||
)}
|
||||
</div>`
|
||||
: nothing
|
||||
}
|
||||
<ha-icon-button
|
||||
.token=${token}
|
||||
.disabled=${token.is_current}
|
||||
.label=${this.hass.localize("ui.common.delete")}
|
||||
.path=${mdiDelete}
|
||||
@click=${this._deleteToken}
|
||||
></ha-icon-button>
|
||||
</ha-settings-row>`
|
||||
)
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="card-actions">
|
||||
<ha-button @click=${this._createToken}>
|
||||
${this.hass.localize(
|
||||
"ui.panel.profile.long_lived_access_tokens.create"
|
||||
)}
|
||||
</ha-button>
|
||||
</div>
|
||||
</ha-card>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -170,9 +174,6 @@ class HaLongLivedTokens extends LitElement {
|
||||
return [
|
||||
haStyle,
|
||||
css`
|
||||
hac-card::part(footer) {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
ha-settings-row {
|
||||
padding: 0;
|
||||
}
|
||||
@@ -182,18 +183,9 @@ class HaLongLivedTokens extends LitElement {
|
||||
ha-icon-button {
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
.header {
|
||||
margin: 0;
|
||||
padding: var(--ha-space-5) var(--ha-space-4) var(--ha-space-4);
|
||||
color: var(--ha-card-header-color, var(--primary-text-color));
|
||||
font-family: var(--ha-card-header-font-family, inherit);
|
||||
font-size: var(--ha-card-header-font-size, var(--ha-font-size-2xl));
|
||||
font-weight: var(--ha-font-weight-normal);
|
||||
line-height: var(--ha-line-height-condensed);
|
||||
letter-spacing: -0.012em;
|
||||
/* haStyle truncates h2 to one line, long titles should wrap */
|
||||
white-space: normal;
|
||||
overflow: visible;
|
||||
.card-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
@@ -1105,6 +1105,10 @@
|
||||
"failed_create_floor": "Failed to create floor.",
|
||||
"unknown": "Unknown floor selected"
|
||||
},
|
||||
"icon_picker": {
|
||||
"suggested": "Suggested",
|
||||
"all_icons": "All icons"
|
||||
},
|
||||
"area-filter": {
|
||||
"title": "Areas",
|
||||
"no_areas": "No areas",
|
||||
|
||||
+1
-7
@@ -8,8 +8,6 @@
|
||||
// Modules
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
// Resolve workspace packages to their sources, see packages/components
|
||||
"customConditions": ["ha-source"],
|
||||
"resolveJsonModule": true,
|
||||
// Babel handles transpiling and no need for declaration files
|
||||
"noEmit": true,
|
||||
@@ -34,10 +32,6 @@
|
||||
{
|
||||
"name": "ts-lit-plugin",
|
||||
"strict": true,
|
||||
// Follows imports of @home-assistant/components entry points (workspace
|
||||
// packages resolve through node_modules) to the component classes
|
||||
// that declare their tags
|
||||
"maxNodeModuleImportDepth": 2,
|
||||
"rules": {
|
||||
// Custom elements
|
||||
"no-unknown-tag-name": "error",
|
||||
@@ -164,5 +158,5 @@
|
||||
}
|
||||
},
|
||||
// Exclude e2e tests — they have their own tsconfig that adds node types.
|
||||
"exclude": ["test/e2e", "packages/*/dist"]
|
||||
"exclude": ["test/e2e"]
|
||||
}
|
||||
Reference in new issue
Block a user