Compare commits
1 Commits
lit-grid-l
...
restore-co
Author | SHA1 | Date | |
---|---|---|---|
![]() |
3272c32f87 |
4
.dockerignore
Normal file
@@ -0,0 +1,4 @@
|
||||
node_modules
|
||||
hass_frontend
|
||||
hass_frontend_es5
|
||||
.git
|
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"extends": [
|
||||
"airbnb-typescript/base",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"airbnb-typescript/base",
|
||||
"plugin:wc/recommended",
|
||||
"plugin:lit/recommended",
|
||||
"prettier",
|
||||
@@ -45,16 +45,16 @@
|
||||
"func-names": 0,
|
||||
"prefer-arrow-callback": 0,
|
||||
"no-underscore-dangle": 0,
|
||||
"no-var": 0,
|
||||
"strict": 0,
|
||||
"prefer-spread": 0,
|
||||
"no-plusplus": 0,
|
||||
"no-bitwise": 2,
|
||||
"no-bitwise": 0,
|
||||
"comma-dangle": 0,
|
||||
"vars-on-top": 0,
|
||||
"no-continue": 0,
|
||||
"no-param-reassign": 0,
|
||||
"no-multi-assign": 0,
|
||||
"no-console": 2,
|
||||
"radix": 0,
|
||||
"no-alert": 0,
|
||||
"no-return-await": 0,
|
||||
@@ -75,16 +75,13 @@
|
||||
"object-curly-newline": 0,
|
||||
"default-case": 0,
|
||||
"wc/no-self-class": 0,
|
||||
"no-shadow": 0,
|
||||
"@typescript-eslint/camelcase": 0,
|
||||
"@typescript-eslint/ban-ts-comment": 0,
|
||||
"@typescript-eslint/ban-ts-ignore": 0,
|
||||
"@typescript-eslint/no-use-before-define": 0,
|
||||
"@typescript-eslint/no-non-null-assertion": 0,
|
||||
"@typescript-eslint/no-explicit-any": 0,
|
||||
"@typescript-eslint/no-unused-vars": 0,
|
||||
"@typescript-eslint/explicit-function-return-type": 0,
|
||||
"@typescript-eslint/explicit-module-boundary-types": 0,
|
||||
"@typescript-eslint/no-shadow": ["error"]
|
||||
"@typescript-eslint/explicit-function-return-type": 0
|
||||
},
|
||||
"plugins": ["disable", "import", "lit", "prettier", "@typescript-eslint"],
|
||||
"processor": "disable/disable"
|
||||
|
2
.github/ISSUE_TEMPLATE/BUG_REPORT.md
vendored
@@ -51,7 +51,7 @@ DO NOT DELETE ANY TEXT from this template! Otherwise, your issue may be closed w
|
||||
<!--
|
||||
Provide details about the versions you are using, which helps us reproducing
|
||||
and finding the issue quicker. Version information is found in the
|
||||
Home Assistant frontend: Configuration -> Info.
|
||||
Home Assistant frontend: Developer tools -> Info.
|
||||
|
||||
Browser version and operating system is important! Please try to replicate
|
||||
your issue in a different browser and be sure to include your findings.
|
||||
|
26
.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
---
|
||||
name: Request a feature for the UI, Frontend or Lovelace
|
||||
about: Request an new feature for the Home Assistant frontend.
|
||||
labels: feature request
|
||||
---
|
||||
|
||||
<!--
|
||||
DO NOT DELETE ANY TEXT from this template!
|
||||
Otherwise, your request may be closed without comment.
|
||||
-->
|
||||
|
||||
## The request
|
||||
|
||||
<!--
|
||||
Describe to our maintainers, the feature you would like to be added.
|
||||
Please be clear and concise and, if possible, provide a screenshot or mockup.
|
||||
-->
|
||||
|
||||
## The alternatives
|
||||
|
||||
<!--
|
||||
Are you currently using, or have you considered alternatives?
|
||||
If so, could you please describe those?
|
||||
-->
|
||||
|
||||
## Additional information
|
3
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,8 +1,5 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Request a feature for the UI, Frontend or Lovelace
|
||||
url: https://github.com/home-assistant/frontend/discussions/category_choices
|
||||
about: Request an new feature for the Home Assistant frontend.
|
||||
- name: Report a bug that is NOT related to the UI, Frontend or Lovelace
|
||||
url: https://github.com/home-assistant/core/issues
|
||||
about: This is the issue tracker for our frontend. Please report other issues with the backend repository.
|
||||
|
6
.github/workflows/ci.yaml
vendored
@@ -34,8 +34,10 @@ jobs:
|
||||
run: yarn install
|
||||
env:
|
||||
CI: true
|
||||
- name: Build resources
|
||||
run: ./node_modules/.bin/gulp gen-icons-json build-translations gather-gallery-demos
|
||||
- name: Build icons
|
||||
run: ./node_modules/.bin/gulp gen-icons-json
|
||||
- name: Build translations
|
||||
run: ./node_modules/.bin/gulp build-translations
|
||||
- name: Run eslint
|
||||
run: ./node_modules/.bin/eslint '{**/src,src}/**/*.{js,ts,html}' --ignore-path .gitignore
|
||||
- name: Run tsc
|
||||
|
60
.github/workflows/codeql-analysis.yml
vendored
@@ -1,60 +0,0 @@
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [dev, master]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [dev]
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# Override automatic language detection by changing the below list
|
||||
# Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
|
||||
language: ['javascript']
|
||||
# Learn more...
|
||||
# https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
# We must fetch at least the immediate parents so that if this is
|
||||
# a pull request then we can checkout the head.
|
||||
fetch-depth: 2
|
||||
|
||||
# If this run was triggered by a pull request event, then checkout
|
||||
# the head of the pull request instead of the merge commit.
|
||||
- run: git checkout HEAD^2
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
2
.gitignore
vendored
@@ -24,7 +24,7 @@ dist
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
|
||||
# Cast dev settings
|
||||
# Cast dev settings
|
||||
src/cast/dev_const.ts
|
||||
|
||||
# Secrets
|
||||
|
31
Dockerfile
Normal file
@@ -0,0 +1,31 @@
|
||||
FROM node:8.11.1-alpine
|
||||
|
||||
# install yarn
|
||||
ENV PATH /root/.yarn/bin:$PATH
|
||||
|
||||
## Install/force base tools
|
||||
RUN apk update \
|
||||
&& apk add make g++ curl bash binutils tar git python2 python3 \
|
||||
&& rm -rf /var/cache/apk/* \
|
||||
&& /bin/bash \
|
||||
&& touch ~/.bashrc
|
||||
|
||||
## Install yarn
|
||||
RUN curl -o- -L https://yarnpkg.com/install.sh | bash
|
||||
|
||||
## Setup the project
|
||||
RUN mkdir -p /frontend
|
||||
|
||||
WORKDIR /frontend
|
||||
|
||||
COPY package.json yarn.lock ./
|
||||
|
||||
RUN yarn install --frozen-lockfile
|
||||
|
||||
COPY . .
|
||||
|
||||
COPY script/docker_entrypoint.sh /usr/bin/docker_entrypoint.sh
|
||||
|
||||
RUN chmod +x /usr/bin/docker_entrypoint.sh
|
||||
|
||||
CMD [ "docker_entrypoint.sh" ]
|
11
README.md
@@ -22,8 +22,17 @@ This is the repository for the official [Home Assistant](https://home-assistant.
|
||||
|
||||
A complete guide can be found at the following [link](https://www.home-assistant.io/developers/frontend/). It describes a short guide for the build of project.
|
||||
|
||||
### Docker environment
|
||||
|
||||
It is possible to compile the project and/or run commands in the development environment having only the [Docker](https://www.docker.com) pre-installed in the system. On the root of project you can do:
|
||||
|
||||
- `sh ./script/docker_run.sh build` Build all the project with one command
|
||||
- `sh ./script/docker_run.sh bash` Open an interactive shell (the same environment generated by the _classic environment_) where you can run commands. This bash work on your project directory and any change on your file is automatically present within your build bash.
|
||||
|
||||
**Note**: if you have installed `npm` in addition to the `docker`, you can use the commands `npm run docker_build` and `npm run bash` to get a full build or bash as explained above
|
||||
|
||||
## License
|
||||
|
||||
Home Assistant is open-source and Apache 2 licensed. Feel free to browse the repository, learn and reuse parts in your own projects.
|
||||
|
||||
We use [BrowserStack](https://www.browserstack.com) to test Home Assistant on a large variety of devices.
|
||||
We use [BrowserStack](https://www.browserstack.com) to test Home Assistant on a large variation of devices.
|
||||
|
@@ -20,13 +20,7 @@ module.exports.emptyPackages = ({ latestBuild }) =>
|
||||
// Loads stuff from a CDN
|
||||
require.resolve("@polymer/font-roboto/roboto.js"),
|
||||
require.resolve("@vaadin/vaadin-material-styles/font-roboto.js"),
|
||||
// Compatibility not needed for latest builds
|
||||
latestBuild &&
|
||||
// wrapped in require.resolve so it blows up if file no longer exists
|
||||
require.resolve(
|
||||
path.resolve(paths.polymer_dir, "src/resources/compatibility.ts")
|
||||
),
|
||||
// This polyfill is loaded in workers to support ES5, filter it out.
|
||||
// Polyfill only needed for ES5 workers so filter out in latestBuild
|
||||
latestBuild && require.resolve("proxy-polyfill/src/index.js"),
|
||||
].filter(Boolean);
|
||||
|
||||
@@ -52,24 +46,17 @@ module.exports.terserOptions = (latestBuild) => ({
|
||||
module.exports.babelOptions = ({ latestBuild }) => ({
|
||||
babelrc: false,
|
||||
presets: [
|
||||
!latestBuild && [
|
||||
require("@babel/preset-env").default,
|
||||
{
|
||||
useBuiltIns: "entry",
|
||||
corejs: "3.6",
|
||||
},
|
||||
],
|
||||
!latestBuild && [require("@babel/preset-env").default, { modules: false }],
|
||||
require("@babel/preset-typescript").default,
|
||||
].filter(Boolean),
|
||||
plugins: [
|
||||
// Part of ES2018. Converts {...a, b: 2} to Object.assign({}, a, {b: 2})
|
||||
!latestBuild && [
|
||||
[
|
||||
"@babel/plugin-proposal-object-rest-spread",
|
||||
{ loose: true, useBuiltIns: true },
|
||||
],
|
||||
// Only support the syntax, Webpack will handle it.
|
||||
"@babel/plugin-syntax-import-meta",
|
||||
"@babel/plugin-syntax-dynamic-import",
|
||||
"@babel/syntax-dynamic-import",
|
||||
"@babel/plugin-proposal-optional-chaining",
|
||||
"@babel/plugin-proposal-nullish-coalescing-operator",
|
||||
[
|
||||
@@ -80,7 +67,7 @@ module.exports.babelOptions = ({ latestBuild }) => ({
|
||||
require("@babel/plugin-proposal-class-properties").default,
|
||||
{ loose: true },
|
||||
],
|
||||
].filter(Boolean),
|
||||
],
|
||||
});
|
||||
|
||||
// Are already ES5, cause warnings when babelified.
|
||||
@@ -92,8 +79,8 @@ module.exports.babelExclude = () => [
|
||||
const outputPath = (outputRoot, latestBuild) =>
|
||||
path.resolve(outputRoot, latestBuild ? "frontend_latest" : "frontend_es5");
|
||||
|
||||
const publicPath = (latestBuild, root = "") =>
|
||||
latestBuild ? `${root}/frontend_latest/` : `${root}/frontend_es5/`;
|
||||
const publicPath = (latestBuild) =>
|
||||
latestBuild ? "/frontend_latest/" : "/frontend_es5/";
|
||||
|
||||
/*
|
||||
BundleConfig {
|
||||
@@ -125,6 +112,7 @@ module.exports.config = {
|
||||
authorize: "./src/entrypoints/authorize.ts",
|
||||
onboarding: "./src/entrypoints/onboarding.ts",
|
||||
core: "./src/entrypoints/core.ts",
|
||||
compatibility: "./src/entrypoints/compatibility.ts",
|
||||
"custom-panel": "./src/entrypoints/custom-panel.ts",
|
||||
},
|
||||
outputPath: outputPath(paths.app_output_root, latestBuild),
|
||||
@@ -139,6 +127,10 @@ module.exports.config = {
|
||||
return {
|
||||
entry: {
|
||||
main: path.resolve(paths.demo_dir, "src/entrypoint.ts"),
|
||||
compatibility: path.resolve(
|
||||
paths.polymer_dir,
|
||||
"src/entrypoints/compatibility.ts"
|
||||
),
|
||||
},
|
||||
outputPath: outputPath(paths.demo_output_root, latestBuild),
|
||||
publicPath: publicPath(latestBuild),
|
||||
@@ -177,14 +169,18 @@ module.exports.config = {
|
||||
},
|
||||
|
||||
hassio({ isProdBuild, latestBuild }) {
|
||||
if (latestBuild) {
|
||||
throw new Error("Hass.io does not support latest build!");
|
||||
}
|
||||
return {
|
||||
entry: {
|
||||
entrypoint: path.resolve(paths.hassio_dir, "src/entrypoint.ts"),
|
||||
},
|
||||
outputPath: outputPath(paths.hassio_output_root, latestBuild),
|
||||
publicPath: publicPath(latestBuild, paths.hassio_publicPath),
|
||||
outputPath: paths.hassio_output_root,
|
||||
publicPath: paths.hassio_publicPath,
|
||||
isProdBuild,
|
||||
latestBuild,
|
||||
dontHash: new Set(["entrypoint"]),
|
||||
};
|
||||
},
|
||||
|
||||
|
@@ -20,7 +20,6 @@ gulp.task(
|
||||
"translations-enable-merge-backend",
|
||||
gulp.parallel("gen-icons-json", "build-translations"),
|
||||
"copy-static-cast",
|
||||
"gen-index-cast-dev",
|
||||
env.useRollup() ? "rollup-dev-server-cast" : "webpack-dev-server-cast"
|
||||
)
|
||||
);
|
||||
|
@@ -6,32 +6,30 @@ const merge = require("merge-stream");
|
||||
const path = require("path");
|
||||
const paths = require("../paths");
|
||||
|
||||
const zopfliOptions = { threshold: 150 };
|
||||
|
||||
gulp.task("compress-app", function compressApp() {
|
||||
const jsLatest = gulp
|
||||
.src(path.resolve(paths.app_output_latest, "**/*.js"))
|
||||
.pipe(zopfli(zopfliOptions))
|
||||
.pipe(zopfli({ threshold: 150 }))
|
||||
.pipe(gulp.dest(paths.app_output_latest));
|
||||
|
||||
const jsEs5 = gulp
|
||||
.src(path.resolve(paths.app_output_es5, "**/*.js"))
|
||||
.pipe(zopfli(zopfliOptions))
|
||||
.pipe(zopfli({ threshold: 150 }))
|
||||
.pipe(gulp.dest(paths.app_output_es5));
|
||||
|
||||
const polyfills = gulp
|
||||
.src(path.resolve(paths.app_output_static, "polyfills/*.js"))
|
||||
.pipe(zopfli(zopfliOptions))
|
||||
.pipe(zopfli({ threshold: 150 }))
|
||||
.pipe(gulp.dest(path.resolve(paths.app_output_static, "polyfills")));
|
||||
|
||||
const translations = gulp
|
||||
.src(path.resolve(paths.app_output_static, "translations/**/*.json"))
|
||||
.pipe(zopfli(zopfliOptions))
|
||||
.pipe(zopfli({ threshold: 150 }))
|
||||
.pipe(gulp.dest(path.resolve(paths.app_output_static, "translations")));
|
||||
|
||||
const icons = gulp
|
||||
.src(path.resolve(paths.app_output_static, "mdi/*.json"))
|
||||
.pipe(zopfli(zopfliOptions))
|
||||
.pipe(zopfli({ threshold: 150 }))
|
||||
.pipe(gulp.dest(path.resolve(paths.app_output_static, "mdi")));
|
||||
|
||||
return merge(jsLatest, jsEs5, polyfills, translations, icons);
|
||||
@@ -40,6 +38,6 @@ gulp.task("compress-app", function compressApp() {
|
||||
gulp.task("compress-hassio", function compressApp() {
|
||||
return gulp
|
||||
.src(path.resolve(paths.hassio_output_root, "**/*.js"))
|
||||
.pipe(zopfli(zopfliOptions))
|
||||
.pipe(zopfli())
|
||||
.pipe(gulp.dest(paths.hassio_output_root));
|
||||
});
|
||||
|
@@ -53,6 +53,7 @@ gulp.task("gen-pages-dev", (done) => {
|
||||
const content = renderTemplate(page, {
|
||||
latestPageJS: `/frontend_latest/${page}.js`,
|
||||
|
||||
es5Compatibility: "/frontend_es5/compatibility.js",
|
||||
es5PageJS: `/frontend_es5/${page}.js`,
|
||||
});
|
||||
|
||||
@@ -78,6 +79,7 @@ gulp.task("gen-pages-prod", (done) => {
|
||||
const content = renderTemplate(page, {
|
||||
latestPageJS: latestManifest[`${page}.js`],
|
||||
|
||||
es5Compatibility: es5Manifest["compatibility.js"],
|
||||
es5PageJS: es5Manifest[`${page}.js`],
|
||||
});
|
||||
|
||||
@@ -90,11 +92,14 @@ gulp.task("gen-pages-prod", (done) => {
|
||||
});
|
||||
|
||||
gulp.task("gen-index-app-dev", (done) => {
|
||||
// In dev mode we don't mangle names, so we hardcode urls. That way we can
|
||||
// run webpack as last in watch mode, which blocks output.
|
||||
const content = renderTemplate("index", {
|
||||
latestAppJS: "/frontend_latest/app.js",
|
||||
latestCoreJS: "/frontend_latest/core.js",
|
||||
latestCustomPanelJS: "/frontend_latest/custom-panel.js",
|
||||
|
||||
es5Compatibility: "/frontend_es5/compatibility.js",
|
||||
es5AppJS: "/frontend_es5/app.js",
|
||||
es5CoreJS: "/frontend_es5/core.js",
|
||||
es5CustomPanelJS: "/frontend_es5/custom-panel.js",
|
||||
@@ -118,6 +123,7 @@ gulp.task("gen-index-app-prod", (done) => {
|
||||
latestCoreJS: latestManifest["core.js"],
|
||||
latestCustomPanelJS: latestManifest["custom-panel.js"],
|
||||
|
||||
es5Compatibility: es5Manifest["compatibility.js"],
|
||||
es5AppJS: es5Manifest["app.js"],
|
||||
es5CoreJS: es5Manifest["core.js"],
|
||||
es5CustomPanelJS: es5Manifest["custom-panel.js"],
|
||||
@@ -199,9 +205,12 @@ gulp.task("gen-index-cast-prod", (done) => {
|
||||
});
|
||||
|
||||
gulp.task("gen-index-demo-dev", (done) => {
|
||||
// In dev mode we don't mangle names, so we hardcode urls. That way we can
|
||||
// run webpack as last in watch mode, which blocks output.
|
||||
const content = renderDemoTemplate("index", {
|
||||
latestDemoJS: "/frontend_latest/main.js",
|
||||
|
||||
es5Compatibility: "/frontend_es5/compatibility.js",
|
||||
es5DemoJS: "/frontend_es5/main.js",
|
||||
});
|
||||
|
||||
@@ -224,6 +233,7 @@ gulp.task("gen-index-demo-prod", (done) => {
|
||||
const content = renderDemoTemplate("index", {
|
||||
latestDemoJS: latestManifest["main.js"],
|
||||
|
||||
es5Compatibility: es5Manifest["compatibility.js"],
|
||||
es5DemoJS: es5Manifest["main.js"],
|
||||
});
|
||||
const minified = minifyHtml(content);
|
||||
@@ -236,6 +246,8 @@ gulp.task("gen-index-demo-prod", (done) => {
|
||||
});
|
||||
|
||||
gulp.task("gen-index-gallery-dev", (done) => {
|
||||
// In dev mode we don't mangle names, so we hardcode urls. That way we can
|
||||
// run webpack as last in watch mode, which blocks output.
|
||||
const content = renderGalleryTemplate("index", {
|
||||
latestGalleryJS: "./frontend_latest/entrypoint.js",
|
||||
});
|
||||
@@ -263,42 +275,3 @@ gulp.task("gen-index-gallery-prod", (done) => {
|
||||
);
|
||||
done();
|
||||
});
|
||||
|
||||
gulp.task("gen-index-hassio-dev", async () => {
|
||||
writeHassioEntrypoint(
|
||||
`${paths.hassio_publicPath}/frontend_latest/entrypoint.js`,
|
||||
`${paths.hassio_publicPath}/frontend_es5/entrypoint.js`
|
||||
);
|
||||
});
|
||||
|
||||
gulp.task("gen-index-hassio-prod", async () => {
|
||||
const latestManifest = require(path.resolve(
|
||||
paths.hassio_output_latest,
|
||||
"manifest.json"
|
||||
));
|
||||
const es5Manifest = require(path.resolve(
|
||||
paths.hassio_output_es5,
|
||||
"manifest.json"
|
||||
));
|
||||
writeHassioEntrypoint(
|
||||
latestManifest["entrypoint.js"],
|
||||
es5Manifest["entrypoint.js"]
|
||||
);
|
||||
});
|
||||
|
||||
function writeHassioEntrypoint(latestEntrypoint, es5Entrypoint) {
|
||||
fs.mkdirSync(paths.hassio_output_root, { recursive: true });
|
||||
fs.writeFileSync(
|
||||
path.resolve(paths.hassio_output_root, "entrypoint.js"),
|
||||
`
|
||||
try {
|
||||
new Function("import('${latestEntrypoint}')")();
|
||||
} catch (err) {
|
||||
var el = document.createElement('script');
|
||||
el.src = '${es5Entrypoint}';
|
||||
document.body.appendChild(el);
|
||||
}
|
||||
`,
|
||||
{ encoding: "utf-8" }
|
||||
);
|
||||
}
|
||||
|
@@ -1,10 +1,7 @@
|
||||
// Run demo develop mode
|
||||
const gulp = require("gulp");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
const env = require("../env");
|
||||
const paths = require("../paths");
|
||||
|
||||
require("./clean.js");
|
||||
require("./translations.js");
|
||||
@@ -15,31 +12,6 @@ require("./service-worker.js");
|
||||
require("./entry-html.js");
|
||||
require("./rollup.js");
|
||||
|
||||
gulp.task("gather-gallery-demos", async function gatherDemos() {
|
||||
const files = await fs.promises.readdir(
|
||||
path.resolve(paths.gallery_dir, "src/demos")
|
||||
);
|
||||
|
||||
let content = "export const DEMOS = {\n";
|
||||
|
||||
for (const file of files) {
|
||||
const demoId = path.basename(file, ".ts");
|
||||
const demoPath = "../src/demos/" + demoId;
|
||||
content += ` "${demoId}": () => import("${demoPath}"),\n`;
|
||||
}
|
||||
|
||||
content += "};";
|
||||
|
||||
const galleryBuild = path.resolve(paths.gallery_dir, "build");
|
||||
|
||||
fs.mkdirSync(galleryBuild, { recursive: true });
|
||||
fs.writeFileSync(
|
||||
path.resolve(galleryBuild, "import-demos.ts"),
|
||||
content,
|
||||
"utf-8"
|
||||
);
|
||||
});
|
||||
|
||||
gulp.task(
|
||||
"develop-gallery",
|
||||
gulp.series(
|
||||
@@ -48,11 +20,7 @@ gulp.task(
|
||||
},
|
||||
"clean-gallery",
|
||||
"translations-enable-merge-backend",
|
||||
gulp.parallel(
|
||||
"gen-icons-json",
|
||||
"build-translations",
|
||||
"gather-gallery-demos"
|
||||
),
|
||||
gulp.parallel("gen-icons-json", "build-translations"),
|
||||
"copy-static-gallery",
|
||||
"gen-index-gallery-dev",
|
||||
env.useRollup() ? "rollup-dev-server-gallery" : "webpack-dev-server-gallery"
|
||||
@@ -67,11 +35,7 @@ gulp.task(
|
||||
},
|
||||
"clean-gallery",
|
||||
"translations-enable-merge-backend",
|
||||
gulp.parallel(
|
||||
"gen-icons-json",
|
||||
"build-translations",
|
||||
"gather-gallery-demos"
|
||||
),
|
||||
gulp.parallel("gen-icons-json", "build-translations"),
|
||||
"copy-static-gallery",
|
||||
env.useRollup() ? "rollup-prod-gallery" : "webpack-prod-gallery",
|
||||
"gen-index-gallery-prod"
|
||||
|
@@ -36,13 +36,11 @@ function copyMdiIcons(staticDir) {
|
||||
function copyPolyfills(staticDir) {
|
||||
const staticPath = genStaticPath(staticDir);
|
||||
|
||||
// For custom panels using ES5 builds that don't use Babel 7+
|
||||
// Web Component polyfills and adapters
|
||||
copyFileDir(
|
||||
npmPath("@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js"),
|
||||
staticPath("polyfills/")
|
||||
);
|
||||
|
||||
// Web Component polyfills and adapters
|
||||
copyFileDir(
|
||||
npmPath("@webcomponents/webcomponentsjs/webcomponents-bundle.js"),
|
||||
staticPath("polyfills/")
|
||||
|
@@ -11,7 +11,6 @@ const META_PATH = path.resolve(ICON_PACKAGE_PATH, "meta.json");
|
||||
const PACKAGE_PATH = path.resolve(ICON_PACKAGE_PATH, "package.json");
|
||||
const ICON_PATH = path.resolve(ICON_PACKAGE_PATH, "svg");
|
||||
const OUTPUT_DIR = path.resolve(__dirname, "../../build/mdi");
|
||||
const REMOVED_ICONS_PATH = path.resolve(__dirname, "../removedIcons.json");
|
||||
|
||||
const encoding = "utf8";
|
||||
|
||||
@@ -26,13 +25,6 @@ const getMeta = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const addRemovedMeta = (meta) => {
|
||||
const file = fs.readFileSync(REMOVED_ICONS_PATH, { encoding });
|
||||
const removed = JSON.parse(file);
|
||||
const combinedMeta = [...meta, ...removed];
|
||||
return combinedMeta.sort((a, b) => a.name.localeCompare(b.name));
|
||||
};
|
||||
|
||||
const splitBySize = (meta) => {
|
||||
const chunks = [];
|
||||
const CHUNK_SIZE = 50000;
|
||||
@@ -77,7 +69,7 @@ const findDifferentiator = (curString, prevString) => {
|
||||
};
|
||||
|
||||
gulp.task("gen-icons-json", (done) => {
|
||||
const meta = addRemovedMeta(getMeta());
|
||||
const meta = getMeta();
|
||||
const split = splitBySize(meta);
|
||||
|
||||
if (!fs.existsSync(OUTPUT_DIR)) {
|
||||
|
@@ -1,9 +1,6 @@
|
||||
const gulp = require("gulp");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
const env = require("../env");
|
||||
const paths = require("../paths");
|
||||
|
||||
require("./clean.js");
|
||||
require("./gen-icons-json.js");
|
||||
@@ -19,7 +16,6 @@ gulp.task(
|
||||
},
|
||||
"clean-hassio",
|
||||
"gen-icons-json",
|
||||
"gen-index-hassio-dev",
|
||||
env.useRollup() ? "rollup-watch-hassio" : "webpack-watch-hassio"
|
||||
)
|
||||
);
|
||||
@@ -33,7 +29,6 @@ gulp.task(
|
||||
"clean-hassio",
|
||||
"gen-icons-json",
|
||||
env.useRollup() ? "rollup-prod-hassio" : "webpack-prod-hassio",
|
||||
"gen-index-hassio-prod",
|
||||
...// Don't compress running tests
|
||||
(env.isTest() ? [] : ["compress-hassio"])
|
||||
)
|
||||
|
@@ -92,7 +92,11 @@ gulp.task("rollup-watch-app", () => {
|
||||
});
|
||||
|
||||
gulp.task("rollup-watch-hassio", () => {
|
||||
watchRollup(rollupConfig.createHassioConfig, ["hassio/src/**"]);
|
||||
watchRollup(
|
||||
// Force latestBuild = false for hassio config.
|
||||
(conf) => rollupConfig.createHassioConfig({ ...conf, latestBuild: false }),
|
||||
["hassio/src/**"]
|
||||
);
|
||||
});
|
||||
|
||||
gulp.task("rollup-dev-server-demo", () => {
|
||||
@@ -133,7 +137,12 @@ gulp.task(
|
||||
);
|
||||
|
||||
gulp.task("rollup-prod-hassio", () =>
|
||||
bothBuilds(rollupConfig.createHassioConfig, { isProdBuild: true })
|
||||
buildRollup(
|
||||
rollupConfig.createHassioConfig({
|
||||
isProdBuild: true,
|
||||
latestBuild: false,
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
gulp.task("rollup-prod-gallery", () =>
|
||||
|
@@ -7,6 +7,7 @@ const gulp = require("gulp");
|
||||
const fs = require("fs");
|
||||
const foreach = require("gulp-foreach");
|
||||
const merge = require("gulp-merge-json");
|
||||
const minify = require("gulp-jsonminify");
|
||||
const rename = require("gulp-rename");
|
||||
const transform = require("gulp-json-transform");
|
||||
const { mapFiles } = require("../util");
|
||||
@@ -300,6 +301,7 @@ gulp.task("build-flattened-translations", function () {
|
||||
return flatten(data);
|
||||
})
|
||||
)
|
||||
.pipe(minify())
|
||||
.pipe(
|
||||
rename((filePath) => {
|
||||
if (filePath.dirname === "core") {
|
||||
|
@@ -129,7 +129,7 @@ gulp.task("webpack-watch-hassio", () => {
|
||||
webpack(
|
||||
createHassioConfig({
|
||||
isProdBuild: false,
|
||||
latestBuild: true,
|
||||
latestBuild: false,
|
||||
})
|
||||
).watch({}, handler());
|
||||
});
|
||||
@@ -139,8 +139,9 @@ gulp.task(
|
||||
() =>
|
||||
new Promise((resolve) =>
|
||||
webpack(
|
||||
bothBuilds(createHassioConfig, {
|
||||
createHassioConfig({
|
||||
isProdBuild: true,
|
||||
latestBuild: false,
|
||||
}),
|
||||
handler(resolve)
|
||||
)
|
||||
|
@@ -34,12 +34,7 @@ module.exports = {
|
||||
|
||||
hassio_dir: path.resolve(__dirname, "../hassio"),
|
||||
hassio_output_root: path.resolve(__dirname, "../hassio/build"),
|
||||
hassio_output_latest: path.resolve(
|
||||
__dirname,
|
||||
"../hassio/build/frontend_latest"
|
||||
),
|
||||
hassio_output_es5: path.resolve(__dirname, "../hassio/build/frontend_es5"),
|
||||
hassio_publicPath: "/api/hassio/app",
|
||||
hassio_publicPath: "/api/hassio/app/",
|
||||
|
||||
translations_src: path.resolve(__dirname, "../src/translations"),
|
||||
};
|
||||
|
@@ -1 +0,0 @@
|
||||
[]
|
@@ -14,6 +14,32 @@ module.exports = function (userOptions = {}) {
|
||||
|
||||
return {
|
||||
name: "ignore",
|
||||
resolveId(importee, importer) {
|
||||
// Only use ignore to intercept imports that we don't control
|
||||
// inside node_module dependencies.
|
||||
if (
|
||||
importee.endsWith("commonjsHelpers.js") ||
|
||||
importee.endsWith("rollupPluginBabelHelpers.js") ||
|
||||
importee.endsWith("?commonjs-proxy") ||
|
||||
!importer ||
|
||||
!importer.includes("/node_modules/")
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
let fullPath;
|
||||
try {
|
||||
fullPath = importee.startsWith(".")
|
||||
? path.resolve(importee, importer)
|
||||
: require.resolve(importee);
|
||||
} catch (err) {
|
||||
console.error("Error in ignore plugin", { importee, importer }, err);
|
||||
throw err;
|
||||
}
|
||||
|
||||
return files.some((toIgnorePath) => fullPath.startsWith(toIgnorePath))
|
||||
? fullPath
|
||||
: null;
|
||||
},
|
||||
|
||||
load(id) {
|
||||
return files.some((toIgnorePath) => id.startsWith(toIgnorePath))
|
||||
|
@@ -2,6 +2,7 @@ const webpack = require("webpack");
|
||||
const path = require("path");
|
||||
const TerserPlugin = require("terser-webpack-plugin");
|
||||
const ManifestPlugin = require("webpack-manifest-plugin");
|
||||
const WorkerPlugin = require("worker-plugin");
|
||||
const paths = require("./paths.js");
|
||||
const bundle = require("./bundle");
|
||||
|
||||
@@ -29,15 +30,12 @@ const createWebpackConfig = ({
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.m?js$|\.ts$/,
|
||||
test: /\.js$|\.ts$/,
|
||||
exclude: bundle.babelExclude(),
|
||||
use: {
|
||||
loader: "babel-loader",
|
||||
options: bundle.babelOptions({ latestBuild }),
|
||||
},
|
||||
resolve: {
|
||||
fullySpecified: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
@@ -48,13 +46,16 @@ const createWebpackConfig = ({
|
||||
optimization: {
|
||||
minimizer: [
|
||||
new TerserPlugin({
|
||||
cache: true,
|
||||
parallel: true,
|
||||
extractComments: true,
|
||||
sourceMap: true,
|
||||
terserOptions: bundle.terserOptions(latestBuild),
|
||||
}),
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
new WorkerPlugin(),
|
||||
new ManifestPlugin({
|
||||
// Only include the JS of entrypoints
|
||||
filter: (file) => file.isInitial && !file.name.endsWith(".map"),
|
||||
@@ -69,9 +70,7 @@ const createWebpackConfig = ({
|
||||
if (
|
||||
!context.includes("/node_modules/") ||
|
||||
// calling define.amd will call require("!!webpack amd options")
|
||||
resource.startsWith("!!webpack") ||
|
||||
// loaded by webpack dev server but doesn't exist.
|
||||
resource === "webpack/hot"
|
||||
resource.startsWith("!!webpack")
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
@@ -81,11 +80,7 @@ const createWebpackConfig = ({
|
||||
? path.resolve(context, resource)
|
||||
: require.resolve(resource);
|
||||
} catch (err) {
|
||||
console.error(
|
||||
"Error in Home Assistant ignore plugin",
|
||||
resource,
|
||||
context
|
||||
);
|
||||
console.error("Error in ignore plugin", resource, context);
|
||||
throw err;
|
||||
}
|
||||
|
||||
@@ -98,15 +93,6 @@ const createWebpackConfig = ({
|
||||
new RegExp(bundle.emptyPackages({ latestBuild }).join("|")),
|
||||
path.resolve(paths.polymer_dir, "src/util/empty.js")
|
||||
),
|
||||
// We need to change the import of the polyfill for EventTarget, so we replace the polyfill file with our customized one
|
||||
new webpack.NormalModuleReplacementPlugin(
|
||||
new RegExp(
|
||||
require.resolve(
|
||||
"lit-virtualizer/lib/uni-virtualizer/lib/polyfillLoaders/EventTarget.js"
|
||||
)
|
||||
),
|
||||
path.resolve(paths.polymer_dir, "src/resources/EventTarget-ponyfill.js")
|
||||
),
|
||||
],
|
||||
resolve: {
|
||||
extensions: [".ts", ".js", ".json"],
|
||||
@@ -118,22 +104,6 @@ const createWebpackConfig = ({
|
||||
}
|
||||
return `${chunk.name}.${chunk.hash.substr(0, 8)}.js`;
|
||||
},
|
||||
environment: {
|
||||
// The environment supports arrow functions ('() => { ... }').
|
||||
arrowFunction: latestBuild,
|
||||
// The environment supports BigInt as literal (123n).
|
||||
bigIntLiteral: false,
|
||||
// The environment supports const and let for variable declarations.
|
||||
const: latestBuild,
|
||||
// The environment supports destructuring ('{ a, b } = obj').
|
||||
destructuring: latestBuild,
|
||||
// The environment supports an async import() function to import EcmaScript modules.
|
||||
dynamicImport: latestBuild,
|
||||
// The environment supports 'for of' iteration ('for (const x of array) { ... }').
|
||||
forOf: latestBuild,
|
||||
// The environment supports ECMAScript Module syntax to import ECMAScript modules (import ... from '...').
|
||||
module: latestBuild,
|
||||
},
|
||||
chunkFilename:
|
||||
isProdBuild && !isStatsBuild
|
||||
? "chunk.[chunkhash].js"
|
||||
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 186 KiB After Width: | Height: | Size: 186 KiB |
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 68 KiB |
@@ -37,21 +37,24 @@
|
||||
<body>
|
||||
<%= renderTemplate('_js_base') %>
|
||||
|
||||
<script>
|
||||
import("<%= latestLauncherJS %>");
|
||||
window.latestJS = true;
|
||||
<script type="module" crossorigin="use-credentials">
|
||||
import "<%= latestLauncherJS %>";
|
||||
</script>
|
||||
|
||||
<script>
|
||||
if (!window.latestJS) {
|
||||
<% if (useRollup) { %>
|
||||
_ls("/static/js/s.min.js").onload = function() {
|
||||
System.import("<%= es5LauncherJS %>");
|
||||
};
|
||||
<% } else { %>
|
||||
_ls("<%= es5LauncherJS %>");
|
||||
<% } %>
|
||||
}
|
||||
<script nomodule>
|
||||
(function() {
|
||||
// // Safari 10.1 supports type=module but ignores nomodule, so we add this check.
|
||||
if (!isS101) {
|
||||
_ls("/static/polyfills/custom-elements-es5-adapter.js");
|
||||
<% if (useRollup) { %>
|
||||
_ls("/static/js/s.min.js").onload = function() {
|
||||
System.import("<%= es5LauncherJS %>");
|
||||
};
|
||||
<% } else { %>
|
||||
_ls("<%= es5LauncherJS %>");
|
||||
<% } %>
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
||||
<hc-layout subtitle="FAQ">
|
||||
@@ -212,8 +215,13 @@
|
||||
Chromecast is a technology developed by Google, and is available on:
|
||||
</p>
|
||||
<ul>
|
||||
<li>Google Chrome (all platforms except iOS)</li>
|
||||
<li>Microsoft Edge (all platforms)</li>
|
||||
<li>Google Chrome (all platforms except on iOS)</li>
|
||||
<li>
|
||||
Microsoft Edge (all platforms,
|
||||
<a href="https://www.microsoftedgeinsider.com" target="_blank"
|
||||
>dev and canary builds only</a
|
||||
>)
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -246,7 +254,7 @@ http:
|
||||
|
||||
<script>
|
||||
var _gaq = [["_setAccount", "UA-57927901-9"], ["_trackPageview"]];
|
||||
(function (d, t) {
|
||||
(function(d, t) {
|
||||
var g = d.createElement(t),
|
||||
s = d.getElementsByTagName(t)[0];
|
||||
g.src =
|
||||
|
@@ -28,21 +28,24 @@
|
||||
|
||||
<hc-connect></hc-connect>
|
||||
|
||||
<script>
|
||||
import("<%= latestLauncherJS %>");
|
||||
window.latestJS = true;
|
||||
<script type="module" crossorigin="use-credentials">
|
||||
import "<%= latestLauncherJS %>";
|
||||
</script>
|
||||
|
||||
<script>
|
||||
if (!window.latestJS) {
|
||||
<% if (useRollup) { %>
|
||||
_ls("/static/js/s.min.js").onload = function() {
|
||||
System.import("<%= es5LauncherJS %>");
|
||||
};
|
||||
<% } else { %>
|
||||
_ls("<%= es5LauncherJS %>");
|
||||
<% } %>
|
||||
}
|
||||
<script nomodule>
|
||||
(function() {
|
||||
// // Safari 10.1 supports type=module but ignores nomodule, so we add this check.
|
||||
if (!isS101) {
|
||||
_ls("/static/polyfills/custom-elements-es5-adapter.js");
|
||||
<% if (useRollup) { %>
|
||||
_ls("/static/js/s.min.js").onload = function() {
|
||||
System.import("<%= es5LauncherJS %>");
|
||||
};
|
||||
<% } else { %>
|
||||
_ls("<%= es5LauncherJS %>");
|
||||
<% } %>
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
|
@@ -1,4 +1,3 @@
|
||||
import "../../../src/resources/safari-14-attachshadow-patch";
|
||||
import "../../../src/resources/ha-style";
|
||||
import "../../../src/resources/roboto";
|
||||
import "./layout/hc-connect";
|
||||
|
@@ -8,7 +8,6 @@ import {
|
||||
html,
|
||||
LitElement,
|
||||
property,
|
||||
internalProperty,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import { CastManager } from "../../../../src/cast/cast_manager";
|
||||
@@ -29,7 +28,7 @@ import {
|
||||
getLovelaceCollection,
|
||||
LovelaceConfig,
|
||||
} from "../../../../src/data/lovelace";
|
||||
import "../../../../src/layouts/hass-loading-screen";
|
||||
import "../../../../src/layouts/loading-screen";
|
||||
import { generateDefaultViewConfig } from "../../../../src/panels/lovelace/common/generate-lovelace-config";
|
||||
import "./hc-layout";
|
||||
import "@material/mwc-button/mwc-button";
|
||||
@@ -42,13 +41,13 @@ class HcCast extends LitElement {
|
||||
|
||||
@property() public castManager!: CastManager;
|
||||
|
||||
@internalProperty() private askWrite = false;
|
||||
@property() private askWrite = false;
|
||||
|
||||
@internalProperty() private lovelaceConfig?: LovelaceConfig | null;
|
||||
@property() private lovelaceConfig?: LovelaceConfig | null;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (this.lovelaceConfig === undefined) {
|
||||
return html` <hass-loading-screen no-toolbar></hass-loading-screen>> `;
|
||||
return html` <loading-screen></loading-screen>> `;
|
||||
}
|
||||
|
||||
const error =
|
||||
|
@@ -17,8 +17,8 @@ import {
|
||||
customElement,
|
||||
html,
|
||||
LitElement,
|
||||
property,
|
||||
TemplateResult,
|
||||
internalProperty,
|
||||
} from "lit-element";
|
||||
import { CastManager, getCastManager } from "../../../../src/cast/cast_manager";
|
||||
import { castSendShowDemo } from "../../../../src/cast/receiver_messages";
|
||||
@@ -27,7 +27,7 @@ import {
|
||||
saveTokens,
|
||||
} from "../../../../src/common/auth/token_storage";
|
||||
import "../../../../src/components/ha-icon";
|
||||
import "../../../../src/layouts/hass-loading-screen";
|
||||
import "../../../../src/layouts/loading-screen";
|
||||
import { registerServiceWorker } from "../../../../src/util/register-service-worker";
|
||||
import "./hc-layout";
|
||||
|
||||
@@ -60,19 +60,19 @@ const INTRO = html`
|
||||
|
||||
@customElement("hc-connect")
|
||||
export class HcConnect extends LitElement {
|
||||
@internalProperty() private loading = false;
|
||||
@property() private loading = false;
|
||||
|
||||
// If we had stored credentials but we cannot connect,
|
||||
// show a screen asking retry or logout.
|
||||
@internalProperty() private cannotConnect = false;
|
||||
@property() private cannotConnect = false;
|
||||
|
||||
@internalProperty() private error?: string | TemplateResult;
|
||||
@property() private error?: string | TemplateResult;
|
||||
|
||||
@internalProperty() private auth?: Auth;
|
||||
@property() private auth?: Auth;
|
||||
|
||||
@internalProperty() private connection?: Connection;
|
||||
@property() private connection?: Connection;
|
||||
|
||||
@internalProperty() private castManager?: CastManager | null;
|
||||
@property() private castManager?: CastManager | null;
|
||||
|
||||
private openDemo = false;
|
||||
|
||||
@@ -98,7 +98,7 @@ export class HcConnect extends LitElement {
|
||||
}
|
||||
|
||||
if (this.castManager === undefined || this.loading) {
|
||||
return html` <hass-loading-screen no-toolbar></hass-loading-screen> `;
|
||||
return html` <loading-screen></loading-screen> `;
|
||||
}
|
||||
|
||||
if (this.castManager === null) {
|
||||
|
@@ -30,7 +30,7 @@ class HcLayout extends LitElement {
|
||||
<ha-card>
|
||||
<div class="layout">
|
||||
<img class="hero" src="/images/google-nest-hub.png" />
|
||||
<h1 class="card-header">
|
||||
<div class="card-header">
|
||||
Home Assistant Cast${this.subtitle ? ` – ${this.subtitle}` : ""}
|
||||
${this.auth
|
||||
? html`
|
||||
@@ -44,7 +44,7 @@ class HcLayout extends LitElement {
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
</h1>
|
||||
</div>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</ha-card>
|
||||
|
@@ -6,60 +6,13 @@ import { castContext } from "./cast_context";
|
||||
import { HcMain } from "./layout/hc-main";
|
||||
import { ReceivedMessage } from "./types";
|
||||
|
||||
const lovelaceController = new HcMain();
|
||||
document.body.append(lovelaceController);
|
||||
|
||||
const mediaPlayer = document.createElement("cast-media-player");
|
||||
mediaPlayer.style.display = "none";
|
||||
document.body.append(mediaPlayer);
|
||||
const playerStylesAdded = false;
|
||||
|
||||
let controls: HTMLElement | null;
|
||||
|
||||
const setTouchControlsVisibility = (visible: boolean) => {
|
||||
if (!castContext.getDeviceCapabilities().touch_input_supported) {
|
||||
return;
|
||||
}
|
||||
controls =
|
||||
controls ||
|
||||
(document.body.querySelector("touch-controls") as HTMLElement | null);
|
||||
if (controls) {
|
||||
controls.style.display = visible ? "initial" : "none";
|
||||
}
|
||||
};
|
||||
|
||||
const showLovelaceController = () => {
|
||||
mediaPlayer.style.display = "none";
|
||||
lovelaceController.style.display = "initial";
|
||||
document.body.setAttribute("style", "overflow-y: auto !important");
|
||||
setTouchControlsVisibility(false);
|
||||
};
|
||||
|
||||
const showMediaPlayer = () => {
|
||||
lovelaceController.style.display = "none";
|
||||
mediaPlayer.style.display = "initial";
|
||||
document.body.removeAttribute("style");
|
||||
setTouchControlsVisibility(true);
|
||||
if (!playerStylesAdded) {
|
||||
const style = document.createElement("style");
|
||||
style.innerHTML = `
|
||||
body {
|
||||
--logo-image: url('https://www.home-assistant.io/images/home-assistant-logo.svg');
|
||||
--logo-repeat: no-repeat;
|
||||
--playback-logo-image: url('https://www.home-assistant.io/images/home-assistant-logo.svg');
|
||||
--theme-hue: 200;
|
||||
--progress-color: #03a9f4;
|
||||
--splash-image: url('https://home-assistant.io/images/cast/splash.png');
|
||||
--splash-size: cover;
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
};
|
||||
const controller = new HcMain();
|
||||
document.body.append(controller);
|
||||
|
||||
const options = new cast.framework.CastReceiverOptions();
|
||||
options.disableIdleTimeout = true;
|
||||
options.customNamespaces = {
|
||||
// @ts-ignore
|
||||
[CAST_NS]: cast.framework.system.MessageType.JSON,
|
||||
};
|
||||
|
||||
@@ -77,61 +30,13 @@ options.uiConfig = new cast.framework.ui.UiConfig();
|
||||
// @ts-ignore
|
||||
options.uiConfig.touchScreenOptimizedApp = true;
|
||||
|
||||
castContext.setInactivityTimeout(86400); // 1 day
|
||||
|
||||
castContext.addCustomMessageListener(
|
||||
CAST_NS,
|
||||
// @ts-ignore
|
||||
(ev: ReceivedMessage<HassMessage>) => {
|
||||
// We received a show Lovelace command, stop media from playing, hide media player and show Lovelace controller
|
||||
if (
|
||||
playerManager.getPlayerState() !==
|
||||
cast.framework.messages.PlayerState.IDLE
|
||||
) {
|
||||
playerManager.stop();
|
||||
} else {
|
||||
showLovelaceController();
|
||||
}
|
||||
const msg = ev.data;
|
||||
msg.senderId = ev.senderId;
|
||||
lovelaceController.processIncomingMessage(msg);
|
||||
}
|
||||
);
|
||||
|
||||
const playerManager = castContext.getPlayerManager();
|
||||
|
||||
playerManager.setMessageInterceptor(
|
||||
cast.framework.messages.MessageType.LOAD,
|
||||
(loadRequestData) => {
|
||||
// We received a play media command, hide Lovelace and show media player
|
||||
showMediaPlayer();
|
||||
const media = loadRequestData.media;
|
||||
// Special handling if it came from Google Assistant
|
||||
if (media.entity) {
|
||||
media.contentId = media.entity;
|
||||
media.streamType = cast.framework.messages.StreamType.LIVE;
|
||||
media.contentType = "application/vnd.apple.mpegurl";
|
||||
// @ts-ignore
|
||||
media.hlsVideoSegmentFormat =
|
||||
cast.framework.messages.HlsVideoSegmentFormat.FMP4;
|
||||
}
|
||||
return loadRequestData;
|
||||
}
|
||||
);
|
||||
|
||||
playerManager.addEventListener(
|
||||
cast.framework.events.EventType.MEDIA_STATUS,
|
||||
(event) => {
|
||||
if (
|
||||
event.mediaStatus?.playerState ===
|
||||
cast.framework.messages.PlayerState.IDLE &&
|
||||
event.mediaStatus?.idleReason &&
|
||||
event.mediaStatus?.idleReason !==
|
||||
cast.framework.messages.IdleReason.INTERRUPTED
|
||||
) {
|
||||
// media finished or stopped, return to default Lovelace
|
||||
showLovelaceController();
|
||||
}
|
||||
controller.processIncomingMessage(msg);
|
||||
}
|
||||
);
|
||||
|
||||
|
@@ -1,10 +1,4 @@
|
||||
import {
|
||||
customElement,
|
||||
html,
|
||||
property,
|
||||
internalProperty,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import { customElement, html, property, TemplateResult } from "lit-element";
|
||||
import { mockHistory } from "../../../../demo/src/stubs/history";
|
||||
import { LovelaceConfig } from "../../../../src/data/lovelace";
|
||||
import {
|
||||
@@ -19,9 +13,9 @@ import "./hc-lovelace";
|
||||
|
||||
@customElement("hc-demo")
|
||||
class HcDemo extends HassElement {
|
||||
@property({ attribute: false }) public lovelacePath!: string;
|
||||
@property() public lovelacePath!: string;
|
||||
|
||||
@internalProperty() private _lovelaceConfig?: LovelaceConfig;
|
||||
@property() private _lovelaceConfig?: LovelaceConfig;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (!this._lovelaceConfig) {
|
||||
|
@@ -11,7 +11,7 @@ import { HomeAssistant } from "../../../../src/types";
|
||||
|
||||
@customElement("hc-launch-screen")
|
||||
class HcLaunchScreen extends LitElement {
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
||||
@property() public error?: string;
|
||||
|
||||
|
@@ -9,20 +9,19 @@ import {
|
||||
} from "lit-element";
|
||||
import { LovelaceConfig } from "../../../../src/data/lovelace";
|
||||
import { Lovelace } from "../../../../src/panels/lovelace/types";
|
||||
import "../../../../src/panels/lovelace/views/hui-panel-view";
|
||||
import "../../../../src/panels/lovelace/views/hui-view";
|
||||
import { HomeAssistant } from "../../../../src/types";
|
||||
import "./hc-launch-screen";
|
||||
|
||||
@customElement("hc-lovelace")
|
||||
class HcLovelace extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
@property() public hass!: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public lovelaceConfig!: LovelaceConfig;
|
||||
@property() public lovelaceConfig!: LovelaceConfig;
|
||||
|
||||
@property() public viewPath?: string | number;
|
||||
|
||||
public urlPath?: string | null;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
const index = this._viewIndex;
|
||||
if (index === undefined) {
|
||||
@@ -36,7 +35,6 @@ class HcLovelace extends LitElement {
|
||||
const lovelace: Lovelace = {
|
||||
config: this.lovelaceConfig,
|
||||
editMode: false,
|
||||
urlPath: this.urlPath!,
|
||||
enableFullEditMode: () => undefined,
|
||||
mode: "storage",
|
||||
language: "en",
|
||||
@@ -44,13 +42,22 @@ class HcLovelace extends LitElement {
|
||||
deleteConfig: async () => undefined,
|
||||
setEditMode: () => undefined,
|
||||
};
|
||||
return html`
|
||||
<hui-view
|
||||
.hass=${this.hass}
|
||||
.lovelace=${lovelace}
|
||||
.index=${index}
|
||||
></hui-view>
|
||||
`;
|
||||
return this.lovelaceConfig.views[index].panel
|
||||
? html`
|
||||
<hui-panel-view
|
||||
.hass=${this.hass}
|
||||
.lovelace=${lovelace}
|
||||
.config=${this.lovelaceConfig.views[index]}
|
||||
></hui-panel-view>
|
||||
`
|
||||
: html`
|
||||
<hui-view
|
||||
.hass=${this.hass}
|
||||
.lovelace=${lovelace}
|
||||
.index=${index}
|
||||
columns="2"
|
||||
></hui-view>
|
||||
`;
|
||||
}
|
||||
|
||||
protected updated(changedProps) {
|
||||
@@ -66,7 +73,7 @@ class HcLovelace extends LitElement {
|
||||
|
||||
if (configBackground) {
|
||||
(this.shadowRoot!.querySelector(
|
||||
"hui-view"
|
||||
"hui-view, hui-panel-view"
|
||||
) as HTMLElement)!.style.setProperty(
|
||||
"--lovelace-background",
|
||||
configBackground
|
||||
|
@@ -3,12 +3,7 @@ import {
|
||||
getAuth,
|
||||
UnsubscribeFunc,
|
||||
} from "home-assistant-js-websocket";
|
||||
import {
|
||||
customElement,
|
||||
html,
|
||||
internalProperty,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import { customElement, html, property, TemplateResult } from "lit-element";
|
||||
import { CAST_NS } from "../../../../src/cast/const";
|
||||
import {
|
||||
ConnectMessage,
|
||||
@@ -36,13 +31,13 @@ let resourcesLoaded = false;
|
||||
|
||||
@customElement("hc-main")
|
||||
export class HcMain extends HassElement {
|
||||
@internalProperty() private _showDemo = false;
|
||||
@property() private _showDemo = false;
|
||||
|
||||
@internalProperty() private _lovelaceConfig?: LovelaceConfig;
|
||||
@property() private _lovelaceConfig?: LovelaceConfig;
|
||||
|
||||
@internalProperty() private _lovelacePath: string | number | null = null;
|
||||
@property() private _lovelacePath: string | number | null = null;
|
||||
|
||||
@internalProperty() private _error?: string;
|
||||
@property() private _error?: string;
|
||||
|
||||
private _unsubLovelace?: UnsubscribeFunc;
|
||||
|
||||
@@ -87,7 +82,6 @@ export class HcMain extends HassElement {
|
||||
.hass=${this.hass}
|
||||
.lovelaceConfig=${this._lovelaceConfig}
|
||||
.viewPath=${this._lovelacePath}
|
||||
.urlPath=${this._urlPath}
|
||||
@config-refresh=${this._generateLovelaceConfig}
|
||||
></hc-lovelace>
|
||||
`;
|
||||
@@ -198,8 +192,6 @@ export class HcMain extends HassElement {
|
||||
this._handleNewLovelaceConfig(lovelaceConfig)
|
||||
);
|
||||
} catch (err) {
|
||||
// eslint-disable-next-line
|
||||
console.log("Error fetching Lovelace configuration", err, msg);
|
||||
// Generate a Lovelace config.
|
||||
this._unsubLovelace = () => undefined;
|
||||
await this._generateLovelaceConfig();
|
||||
@@ -216,7 +208,9 @@ export class HcMain extends HassElement {
|
||||
}
|
||||
this._showDemo = false;
|
||||
this._lovelacePath = msg.viewPath;
|
||||
|
||||
if (castContext.getDeviceCapabilities().touch_input_supported) {
|
||||
this._breakFree();
|
||||
}
|
||||
this._sendStatus();
|
||||
}
|
||||
|
||||
@@ -239,6 +233,9 @@ export class HcMain extends HassElement {
|
||||
this._showDemo = true;
|
||||
this._lovelacePath = "overview";
|
||||
this._sendStatus();
|
||||
if (castContext.getDeviceCapabilities().touch_input_supported) {
|
||||
this._breakFree();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -259,6 +256,14 @@ export class HcMain extends HassElement {
|
||||
}
|
||||
}
|
||||
|
||||
private _breakFree() {
|
||||
const controls = document.body.querySelector("touch-controls");
|
||||
if (controls) {
|
||||
controls.remove();
|
||||
}
|
||||
document.body.setAttribute("style", "overflow-y: auto !important");
|
||||
}
|
||||
|
||||
private sendMessage(senderId: string, response: any) {
|
||||
castContext.sendCustomMessage(CAST_NS, senderId, response);
|
||||
}
|
||||
|
@@ -1,8 +1,11 @@
|
||||
const { createCastConfig } = require("../build-scripts/webpack.js");
|
||||
const { isProdBuild, isStatsBuild } = require("../build-scripts/env.js");
|
||||
const { isProdBuild } = require("../build-scripts/env.js");
|
||||
|
||||
// File just used for stats builds
|
||||
|
||||
const latestBuild = true;
|
||||
|
||||
module.exports = createCastConfig({
|
||||
isProdBuild: isProdBuild(),
|
||||
isStatsBuild: isStatsBuild(),
|
||||
latestBuild: true,
|
||||
latestBuild,
|
||||
});
|
||||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 8.4 KiB |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.3 KiB |
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 7.7 KiB |
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.4 KiB |
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.5 KiB |
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 9.9 KiB |
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 7.9 KiB |
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 6.5 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 8.2 KiB |
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 8.5 KiB |
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 9.9 KiB |
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 532 B After Width: | Height: | Size: 767 B |
Before Width: | Height: | Size: 535 B After Width: | Height: | Size: 803 B |
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 75 KiB |
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB |
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 71 KiB |
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 8.2 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 106 KiB |
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 60 KiB |
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 62 KiB |
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 56 KiB |
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 57 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 83 KiB After Width: | Height: | Size: 83 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 62 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 184 B After Width: | Height: | Size: 375 B |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 110 KiB After Width: | Height: | Size: 111 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 20 KiB |
@@ -26,9 +26,9 @@ export const demoThemeJimpower = () => ({
|
||||
"switch-checked-color": "var(--accent-color)",
|
||||
"paper-dialog-background-color": "#434954",
|
||||
"secondary-text-color": "#5294E2",
|
||||
"error-color": "#E45E65",
|
||||
"google-red-500": "#E45E65",
|
||||
"divider-color": "rgba(0, 0, 0, .12)",
|
||||
"success-color": "#39E949",
|
||||
"google-green-500": "#39E949",
|
||||
"switch-unchecked-button-color": "var(--disabled-text-color)",
|
||||
"label-badge-border-color": "green",
|
||||
"paper-listbox-color": "var(--primary-color)",
|
||||
|
@@ -27,9 +27,9 @@ export const demoThemeKernehed = () => ({
|
||||
"switch-checked-color": "var(--accent-color)",
|
||||
"paper-dialog-background-color": "#292929",
|
||||
"secondary-text-color": "#b58e31",
|
||||
"error-color": "#b58e31",
|
||||
"google-red-500": "#b58e31",
|
||||
"divider-color": "rgba(0, 0, 0, .12)",
|
||||
"success-color": "#2980b9",
|
||||
"google-green-500": "#2980b9",
|
||||
"switch-unchecked-button-color": "var(--disabled-text-color)",
|
||||
"label-badge-border-color": "green",
|
||||
"paper-listbox-color": "#777777",
|
||||
|
@@ -7,183 +7,205 @@ export const demoLovelaceTeachingbirds: DemoConfig["lovelace"] = () => ({
|
||||
cards: [
|
||||
{ type: "custom:ha-demo-card" },
|
||||
{
|
||||
type: "grid",
|
||||
columns: 4,
|
||||
cards: [
|
||||
{
|
||||
image: "/assets/teachingbirds/isa_square.jpg",
|
||||
type: "picture-entity",
|
||||
show_name: false,
|
||||
tap_action: {
|
||||
action: "more-info",
|
||||
},
|
||||
entity: "sensor.presence_isa",
|
||||
},
|
||||
{
|
||||
image: "/assets/teachingbirds/Stefan_square.jpg",
|
||||
type: "picture-entity",
|
||||
show_name: false,
|
||||
tap_action: {
|
||||
action: "more-info",
|
||||
},
|
||||
entity: "sensor.presence_stefan",
|
||||
},
|
||||
{
|
||||
image: "/assets/teachingbirds/background_square.png",
|
||||
elements: [
|
||||
cards: [
|
||||
{
|
||||
state_image: {
|
||||
on: "/assets/teachingbirds/radiator_on.jpg",
|
||||
off: "/assets/teachingbirds/radiator_off.jpg",
|
||||
},
|
||||
type: "image",
|
||||
style: {
|
||||
width: "100%",
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
},
|
||||
image: "/assets/teachingbirds/isa_square.jpg",
|
||||
type: "picture-entity",
|
||||
show_name: false,
|
||||
tap_action: {
|
||||
action: "more-info",
|
||||
},
|
||||
entity: "switch.stefan_radiator_3",
|
||||
entity: "sensor.presence_isa",
|
||||
},
|
||||
{
|
||||
style: {
|
||||
top: "90%",
|
||||
left: "50%",
|
||||
image: "/assets/teachingbirds/Stefan_square.jpg",
|
||||
type: "picture-entity",
|
||||
show_name: false,
|
||||
tap_action: {
|
||||
action: "more-info",
|
||||
},
|
||||
type: "state-label",
|
||||
entity: "sensor.presence_stefan",
|
||||
},
|
||||
{
|
||||
image: "/assets/teachingbirds/background_square.png",
|
||||
elements: [
|
||||
{
|
||||
state_image: {
|
||||
on: "/assets/teachingbirds/radiator_on.jpg",
|
||||
off: "/assets/teachingbirds/radiator_off.jpg",
|
||||
},
|
||||
type: "image",
|
||||
style: {
|
||||
width: "100%",
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
},
|
||||
tap_action: {
|
||||
action: "more-info",
|
||||
},
|
||||
entity: "switch.stefan_radiator_3",
|
||||
},
|
||||
{
|
||||
style: {
|
||||
top: "90%",
|
||||
left: "50%",
|
||||
},
|
||||
type: "state-label",
|
||||
entity: "sensor.temperature_stefan",
|
||||
},
|
||||
],
|
||||
type: "picture-elements",
|
||||
},
|
||||
{
|
||||
image: "/assets/teachingbirds/background_square.png",
|
||||
elements: [
|
||||
{
|
||||
style: {
|
||||
"--mdc-icon-size": "100%",
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
},
|
||||
type: "icon",
|
||||
tap_action: {
|
||||
action: "navigate",
|
||||
navigation_path: "/lovelace/home_info",
|
||||
},
|
||||
icon: "mdi:car",
|
||||
},
|
||||
],
|
||||
type: "picture-elements",
|
||||
},
|
||||
],
|
||||
type: "horizontal-stack",
|
||||
},
|
||||
{
|
||||
cards: [
|
||||
{
|
||||
show_name: false,
|
||||
type: "picture-entity",
|
||||
name: "Alarm",
|
||||
image: "/assets/teachingbirds/House_square.jpg",
|
||||
entity: "alarm_control_panel.house",
|
||||
},
|
||||
{
|
||||
name: "Roomba",
|
||||
image: "/assets/teachingbirds/roomba_square.jpg",
|
||||
show_name: false,
|
||||
type: "picture-entity",
|
||||
state_image: {
|
||||
"Not Today": "/assets/teachingbirds/roomba_bw_square.jpg",
|
||||
},
|
||||
entity: "input_select.roomba_mode",
|
||||
},
|
||||
{
|
||||
show_name: false,
|
||||
type: "picture-entity",
|
||||
state_image: {
|
||||
Mail: "/assets/teachingbirds/mailbox_square.jpg",
|
||||
"Package and mail":
|
||||
"/assets/teachingbirds/mailbox_square.jpg",
|
||||
Empty: "/assets/teachingbirds/mailbox_bw_square.jpg",
|
||||
Package: "/assets/teachingbirds/mailbox_square.jpg",
|
||||
},
|
||||
entity: "sensor.mailbox",
|
||||
},
|
||||
{
|
||||
show_name: false,
|
||||
state_image: {
|
||||
"Put out": "/assets/teachingbirds/trash_square.jpg",
|
||||
"Take in": "/assets/teachingbirds/trash_square.jpg",
|
||||
},
|
||||
type: "picture-entity",
|
||||
image: "/assets/teachingbirds/trash_bear_bw_square.jpg",
|
||||
entity: "sensor.trash_status",
|
||||
},
|
||||
],
|
||||
type: "horizontal-stack",
|
||||
},
|
||||
{
|
||||
cards: [
|
||||
{
|
||||
state_image: {
|
||||
Idle: "/assets/teachingbirds/washer_square.jpg",
|
||||
Running: "/assets/teachingbirds/laundry_running_square.jpg",
|
||||
Clean: "/assets/teachingbirds/laundry_clean_2_square.jpg",
|
||||
},
|
||||
entity: "input_select.washing_machine_status",
|
||||
type: "picture-entity",
|
||||
show_name: false,
|
||||
name: "Washer",
|
||||
},
|
||||
{
|
||||
state_image: {
|
||||
Idle: "/assets/teachingbirds/dryer_square.jpg",
|
||||
Running: "/assets/teachingbirds/clothes_drying_square.jpg",
|
||||
Clean: "/assets/teachingbirds/folded_clothes_square.jpg",
|
||||
},
|
||||
entity: "input_select.dryer_status",
|
||||
type: "picture-entity",
|
||||
show_name: false,
|
||||
name: "Dryer",
|
||||
},
|
||||
{
|
||||
image: "/assets/teachingbirds/guests_square.jpg",
|
||||
type: "picture-entity",
|
||||
show_name: false,
|
||||
tap_action: {
|
||||
action: "toggle",
|
||||
},
|
||||
entity: "input_boolean.guest_mode",
|
||||
},
|
||||
{
|
||||
image: "/assets/teachingbirds/cleaning_square.jpg",
|
||||
type: "picture-entity",
|
||||
show_name: false,
|
||||
tap_action: {
|
||||
action: "toggle",
|
||||
},
|
||||
entity: "input_boolean.cleaning_day",
|
||||
},
|
||||
],
|
||||
type: "horizontal-stack",
|
||||
},
|
||||
],
|
||||
type: "vertical-stack",
|
||||
},
|
||||
{
|
||||
type: "vertical-stack",
|
||||
cards: [
|
||||
{
|
||||
cards: [
|
||||
{
|
||||
graph: "line",
|
||||
type: "sensor",
|
||||
entity: "sensor.temperature_bedroom",
|
||||
},
|
||||
{
|
||||
graph: "line",
|
||||
type: "sensor",
|
||||
name: "S's room",
|
||||
entity: "sensor.temperature_stefan",
|
||||
},
|
||||
],
|
||||
type: "picture-elements",
|
||||
type: "horizontal-stack",
|
||||
},
|
||||
{
|
||||
image: "/assets/teachingbirds/background_square.png",
|
||||
elements: [
|
||||
cards: [
|
||||
{
|
||||
style: {
|
||||
"--mdc-icon-size": "100%",
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
},
|
||||
type: "icon",
|
||||
tap_action: {
|
||||
action: "navigate",
|
||||
navigation_path: "/lovelace/home_info",
|
||||
},
|
||||
icon: "mdi:car",
|
||||
graph: "line",
|
||||
type: "sensor",
|
||||
entity: "sensor.temperature_passage",
|
||||
},
|
||||
{
|
||||
graph: "line",
|
||||
type: "sensor",
|
||||
name: "Laundry",
|
||||
entity: "sensor.temperature_downstairs_bathroom",
|
||||
},
|
||||
],
|
||||
type: "picture-elements",
|
||||
},
|
||||
|
||||
{
|
||||
show_name: false,
|
||||
type: "picture-entity",
|
||||
name: "Alarm",
|
||||
image: "/assets/teachingbirds/House_square.jpg",
|
||||
entity: "alarm_control_panel.house",
|
||||
},
|
||||
{
|
||||
name: "Roomba",
|
||||
image: "/assets/teachingbirds/roomba_square.jpg",
|
||||
show_name: false,
|
||||
type: "picture-entity",
|
||||
state_image: {
|
||||
"Not Today": "/assets/teachingbirds/roomba_bw_square.jpg",
|
||||
},
|
||||
entity: "input_select.roomba_mode",
|
||||
},
|
||||
{
|
||||
show_name: false,
|
||||
type: "picture-entity",
|
||||
state_image: {
|
||||
Mail: "/assets/teachingbirds/mailbox_square.jpg",
|
||||
"Package and mail": "/assets/teachingbirds/mailbox_square.jpg",
|
||||
Empty: "/assets/teachingbirds/mailbox_bw_square.jpg",
|
||||
Package: "/assets/teachingbirds/mailbox_square.jpg",
|
||||
},
|
||||
entity: "sensor.mailbox",
|
||||
},
|
||||
{
|
||||
show_name: false,
|
||||
state_image: {
|
||||
"Put out": "/assets/teachingbirds/trash_square.jpg",
|
||||
"Take in": "/assets/teachingbirds/trash_square.jpg",
|
||||
},
|
||||
type: "picture-entity",
|
||||
image: "/assets/teachingbirds/trash_bear_bw_square.jpg",
|
||||
entity: "sensor.trash_status",
|
||||
},
|
||||
|
||||
{
|
||||
state_image: {
|
||||
Idle: "/assets/teachingbirds/washer_square.jpg",
|
||||
Running: "/assets/teachingbirds/laundry_running_square.jpg",
|
||||
Clean: "/assets/teachingbirds/laundry_clean_2_square.jpg",
|
||||
},
|
||||
entity: "input_select.washing_machine_status",
|
||||
type: "picture-entity",
|
||||
show_name: false,
|
||||
name: "Washer",
|
||||
},
|
||||
{
|
||||
state_image: {
|
||||
Idle: "/assets/teachingbirds/dryer_square.jpg",
|
||||
Running: "/assets/teachingbirds/clothes_drying_square.jpg",
|
||||
Clean: "/assets/teachingbirds/folded_clothes_square.jpg",
|
||||
},
|
||||
entity: "input_select.dryer_status",
|
||||
type: "picture-entity",
|
||||
show_name: false,
|
||||
name: "Dryer",
|
||||
},
|
||||
{
|
||||
image: "/assets/teachingbirds/guests_square.jpg",
|
||||
type: "picture-entity",
|
||||
show_name: false,
|
||||
tap_action: {
|
||||
action: "toggle",
|
||||
},
|
||||
entity: "input_boolean.guest_mode",
|
||||
},
|
||||
{
|
||||
image: "/assets/teachingbirds/cleaning_square.jpg",
|
||||
type: "picture-entity",
|
||||
show_name: false,
|
||||
tap_action: {
|
||||
action: "toggle",
|
||||
},
|
||||
entity: "input_boolean.cleaning_day",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: "grid",
|
||||
columns: 2,
|
||||
cards: [
|
||||
{
|
||||
graph: "line",
|
||||
type: "sensor",
|
||||
entity: "sensor.temperature_bedroom",
|
||||
},
|
||||
{
|
||||
graph: "line",
|
||||
type: "sensor",
|
||||
name: "S's room",
|
||||
entity: "sensor.temperature_stefan",
|
||||
},
|
||||
{
|
||||
graph: "line",
|
||||
type: "sensor",
|
||||
entity: "sensor.temperature_passage",
|
||||
},
|
||||
{
|
||||
graph: "line",
|
||||
type: "sensor",
|
||||
name: "Laundry",
|
||||
entity: "sensor.temperature_downstairs_bathroom",
|
||||
type: "horizontal-stack",
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@@ -4,7 +4,7 @@ import {
|
||||
customElement,
|
||||
html,
|
||||
LitElement,
|
||||
internalProperty,
|
||||
property,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import { CastManager } from "../../../src/cast/cast_manager";
|
||||
@@ -20,7 +20,7 @@ import { HomeAssistant } from "../../../src/types";
|
||||
class CastDemoRow extends LitElement implements LovelaceRow {
|
||||
public hass!: HomeAssistant;
|
||||
|
||||
@internalProperty() private _castManager?: CastManager | null;
|
||||
@property() private _castManager?: CastManager | null;
|
||||
|
||||
public setConfig(_config: CastConfig): void {
|
||||
// No config possible.
|
||||
@@ -52,6 +52,7 @@ class CastDemoRow extends LitElement implements LovelaceRow {
|
||||
});
|
||||
mgr.castContext.addEventListener(
|
||||
// eslint-disable-next-line no-undef
|
||||
// @ts-ignore
|
||||
cast.framework.CastContextEventType.SESSION_STATE_CHANGED,
|
||||
(ev) => {
|
||||
// On Android, opening a new session always results in SESSION_RESUMED.
|
||||
|
@@ -1,16 +1,15 @@
|
||||
import "@material/mwc-button";
|
||||
import "@polymer/paper-spinner/paper-spinner-lite";
|
||||
import {
|
||||
css,
|
||||
CSSResult,
|
||||
html,
|
||||
LitElement,
|
||||
property,
|
||||
internalProperty,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import { until } from "lit-html/directives/until";
|
||||
import "../../../src/components/ha-card";
|
||||
import "../../../src/components/ha-circular-progress";
|
||||
import { LovelaceCardConfig } from "../../../src/data/lovelace";
|
||||
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
||||
import { Lovelace, LovelaceCard } from "../../../src/panels/lovelace/types";
|
||||
@@ -22,11 +21,11 @@ import {
|
||||
} from "../configs/demo-configs";
|
||||
|
||||
export class HADemoCard extends LitElement implements LovelaceCard {
|
||||
@property({ attribute: false }) public lovelace?: Lovelace;
|
||||
@property() public lovelace?: Lovelace;
|
||||
|
||||
@property({ attribute: false }) public hass!: MockHomeAssistant;
|
||||
@property() public hass!: MockHomeAssistant;
|
||||
|
||||
@internalProperty() private _switching?: boolean;
|
||||
@property() private _switching?: boolean;
|
||||
|
||||
private _hidden = localStorage.hide_demo_card;
|
||||
|
||||
@@ -50,7 +49,7 @@ export class HADemoCard extends LitElement implements LovelaceCard {
|
||||
<div class="picker">
|
||||
<div class="label">
|
||||
${this._switching
|
||||
? html`<ha-circular-progress active></ha-circular-progress>`
|
||||
? html` <paper-spinner-lite active></paper-spinner-lite> `
|
||||
: until(
|
||||
selectedDemoConfig.then(
|
||||
(conf) => html`
|
||||
|
@@ -1,4 +1,3 @@
|
||||
import "../../src/resources/safari-14-attachshadow-patch";
|
||||
import "@polymer/polymer/lib/elements/dom-if";
|
||||
import "@polymer/polymer/lib/elements/dom-repeat";
|
||||
import "../../src/resources/ha-style";
|
||||
|
@@ -1,4 +1,3 @@
|
||||
import "../../src/resources/compatibility";
|
||||
import { isNavigationClick } from "../../src/common/dom/is-navigation-click";
|
||||
import { navigate } from "../../src/common/navigate";
|
||||
import {
|
||||
|