├── .commit-template ├── .devcontainer ├── configuration.yaml ├── ui-lovelace.yaml └── devcontainer.json ├── .github ├── FUNDING.yml ├── workflows │ ├── build.yml │ ├── release.yml │ └── eslint.yml └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── .eslintignore ├── hacs.json ├── .prettierrc.js ├── .vscode └── extensions.json ├── commitlint.config.js ├── src ├── types.ts └── kb-steam-card.ts ├── tsconfig.json ├── .eslintrc.js ├── rollup.config.js ├── LICENSE ├── .gitignore ├── info.md ├── CODE_OF_CONDUCT.md ├── package.json ├── README.md └── dist └── kb-steam-card.js /.commit-template: -------------------------------------------------------------------------------- 1 | type(scope): subject 2 | 3 | description -------------------------------------------------------------------------------- /.devcontainer/configuration.yaml: -------------------------------------------------------------------------------- 1 | default_config: 2 | lovelace: 3 | mode: yaml 4 | demo: -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | custom: 2 | - https://paypal.me/thatkookooguy?locale.x=en_US 3 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | coverage 2 | test-results 3 | node_modules 4 | *.config.js 5 | examples 6 | .eslintrc.js 7 | dist/* -------------------------------------------------------------------------------- /hacs.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Steam Card", 3 | "render_readme": true, 4 | "filename": "kb-steam-card.js" 5 | } 6 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | semi: true, 3 | trailingComma: 'all', 4 | singleQuote: true, 5 | printWidth: 120, 6 | tabWidth: 2, 7 | }; -------------------------------------------------------------------------------- /.devcontainer/ui-lovelace.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - url: http://127.0.0.1:5000/boilerplate-card.js 3 | type: module 4 | views: 5 | - cards: 6 | - type: custom:boilerplate-card 7 | name: Boilerplate Card Development 8 | entity: sun.sun 9 | test_gui: true 10 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "github.vscode-pull-request-github", 4 | "eamodio.gitlens", 5 | "dbaeumer.vscode-eslint", 6 | "esbenp.prettier-vscode", 7 | "bierner.lit-html", 8 | "runem.lit-plugin", 9 | "auchenberg.vscode-browser-preview", 10 | "davidanson.vscode-markdownlint", 11 | "redhat.vscode-yaml" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: "Build" 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | - next 8 | pull_request: 9 | branches: 10 | - master 11 | - next 12 | 13 | jobs: 14 | build: 15 | name: Test build 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/checkout@v1 19 | - name: Build 20 | run: | 21 | npm install 22 | npm run build -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: [ '@commitlint/config-angular' ], 3 | rules: { 4 | 'type-enum': [ 5 | 2, 6 | 'always', [ 7 | 'build', 8 | 'chore', 9 | 'ci', 10 | 'docs', 11 | 'feat', 12 | 'fix', 13 | 'perf', 14 | 'refactor', 15 | 'revert', 16 | 'style', 17 | 'test' 18 | ] 19 | ] 20 | } 21 | }; -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | import { ActionConfig, LovelaceCardConfig } from 'custom-card-helpers'; 2 | 3 | // TODO Add your configuration elements here for type-checking 4 | export interface BoilerplateCardConfig extends LovelaceCardConfig { 5 | type: string; 6 | name?: string; 7 | show_warning?: boolean; 8 | show_error?: boolean; 9 | test_gui?: boolean; 10 | entity?: string; 11 | tap_action?: ActionConfig; 12 | hold_action?: ActionConfig; 13 | double_tap_action?: ActionConfig; 14 | } 15 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2017", 4 | "module": "esnext", 5 | "moduleResolution": "node", 6 | "lib": ["es2017", "dom", "dom.iterable"], 7 | "noEmit": true, 8 | "noUnusedParameters": true, 9 | "noImplicitReturns": true, 10 | "noFallthroughCasesInSwitch": true, 11 | "strict": true, 12 | "noImplicitAny": false, 13 | "skipLibCheck": true, 14 | "resolveJsonModule": true, 15 | "experimentalDecorators": true 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: feature request 6 | assignees: '' 7 | --- 8 | 9 | **Is your feature request related to a problem? Please describe.** 10 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 11 | 12 | **Describe the solution you'd like** 13 | A clear and concise description of what you want to happen. 14 | 15 | **Describe alternatives you've considered** 16 | A clear and concise description of any alternative solutions or features you've considered. 17 | 18 | **Additional context** 19 | Add any other context or screenshots about the feature request here. 20 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | on: 3 | push: 4 | branches: 5 | - master 6 | - next 7 | jobs: 8 | release: 9 | name: Release 10 | runs-on: ubuntu-18.04 11 | steps: 12 | - name: Checkout 13 | uses: actions/checkout@v2 14 | with: 15 | fetch-depth: 0 16 | - name: Setup Node.js 17 | uses: actions/setup-node@v1 18 | with: 19 | node-version: 12 20 | - name: Install dependencies 21 | run: | 22 | npm ci 23 | npm install 24 | npm run build 25 | - name: Release 26 | env: 27 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 28 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 29 | run: npm run semantic-release -------------------------------------------------------------------------------- /.github/workflows/eslint.yml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | run-linters: 13 | name: Run linters 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - name: Check out Git repository 18 | uses: actions/checkout@v2 19 | 20 | - name: Set up Node.js 21 | uses: actions/setup-node@v1 22 | with: 23 | node-version: 12 24 | 25 | # ESLint and Prettier must be in `package.json` 26 | - name: Install Node.js dependencies 27 | run: npm install 28 | 29 | - name: Run linters 30 | uses: wearerequired/lint-action@v1 31 | with: 32 | github_token: ${{ secrets.github_token }} 33 | # Enable linters 34 | eslint: true 35 | eslint_dir: src/ -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: '@typescript-eslint/parser', // Specifies the ESLint parser 3 | extends: [ 4 | 'plugin:@typescript-eslint/recommended', // Uses the recommended rules from the @typescript-eslint/eslint-plugin 5 | 'prettier/@typescript-eslint', // Uses eslint-config-prettier to disable ESLint rules from @typescript-eslint/eslint-plugin that would conflict with prettier 6 | 'plugin:prettier/recommended', // Enables eslint-plugin-prettier and displays prettier errors as ESLint errors. Make sure this is always the last configuration in the extends array. 7 | ], 8 | parserOptions: { 9 | ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features 10 | sourceType: 'module', // Allows for the use of imports 11 | experimentalDecorators: true 12 | }, 13 | rules: { 14 | '@typescript-eslint/camelcase': 0, 15 | '@typescript-eslint/no-unused-vars': 0 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import typescript from 'rollup-plugin-typescript2'; 2 | import commonjs from 'rollup-plugin-commonjs'; 3 | import nodeResolve from 'rollup-plugin-node-resolve'; 4 | import babel from 'rollup-plugin-babel'; 5 | import { terser } from 'rollup-plugin-terser'; 6 | import serve from 'rollup-plugin-serve'; 7 | import json from '@rollup/plugin-json'; 8 | 9 | const dev = process.env.ROLLUP_WATCH; 10 | 11 | const serveopts = { 12 | contentBase: ['./dist'], 13 | host: '0.0.0.0', 14 | port: 5000, 15 | allowCrossOrigin: true, 16 | headers: { 17 | 'Access-Control-Allow-Origin': '*', 18 | }, 19 | }; 20 | 21 | const plugins = [ 22 | nodeResolve({}), 23 | commonjs(), 24 | typescript(), 25 | json(), 26 | babel({ 27 | exclude: 'node_modules/**', 28 | }), 29 | dev && serve(serveopts), 30 | !dev && terser(), 31 | ]; 32 | 33 | export default [ 34 | { 35 | input: 'src/kb-steam-card.ts', 36 | output: { 37 | dir: 'dist', 38 | format: 'es', 39 | }, 40 | plugins: [...plugins], 41 | }, 42 | ]; 43 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // See https://aka.ms/vscode-remote/devcontainer.json for format details. 2 | { 3 | "name": "Boilerplate Card Development", 4 | "image": "ludeeus/container:monster", 5 | "context": "..", 6 | "appPort": ["5000:5000", "9123:8123"], 7 | "postCreateCommand": "npm install", 8 | "runArgs": [ 9 | "-v", 10 | "${env:HOME}${env:USERPROFILE}/.ssh:/tmp/.ssh" // This is added so you can push from inside the container 11 | ], 12 | "extensions": [ 13 | "github.vscode-pull-request-github", 14 | "eamodio.gitlens", 15 | "dbaeumer.vscode-eslint", 16 | "esbenp.prettier-vscode", 17 | "bierner.lit-html", 18 | "runem.lit-plugin", 19 | "auchenberg.vscode-browser-preview", 20 | "davidanson.vscode-markdownlint", 21 | "redhat.vscode-yaml" 22 | ], 23 | "settings": { 24 | "files.eol": "\n", 25 | "editor.tabSize": 4, 26 | "terminal.integrated.shell.linux": "/bin/bash", 27 | "editor.formatOnPaste": false, 28 | "editor.formatOnSave": true, 29 | "editor.formatOnType": true, 30 | "files.trimTrailingWhitespace": true 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 thatkookooguy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | --- 8 | 9 | 14 | 15 | **Checklist:** 16 | 17 | - [ ] I updated to the latest version available 18 | - [ ] I cleared the cache of my browser 19 | 20 | **Release with the issue:** 21 | 22 | **Last working release (if known):** 23 | 24 | **Browser and Operating System:** 25 | 26 | 29 | 30 | **Description of problem:** 31 | 32 | 35 | 36 | **Javascript errors shown in the web inspector (if applicable):** 37 | 38 | ``` 39 | 40 | ``` 41 | 42 | **Additional information:** 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # kibibit 2 | test-results 3 | 4 | # Logs 5 | logs 6 | *.log 7 | npm-debug.log* 8 | yarn-debug.log* 9 | yarn-error.log* 10 | lerna-debug.log* 11 | 12 | # Diagnostic reports (https://nodejs.org/api/report.html) 13 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 14 | 15 | # Runtime data 16 | pids 17 | *.pid 18 | *.seed 19 | *.pid.lock 20 | 21 | # Directory for instrumented libs generated by jscoverage/JSCover 22 | lib-cov 23 | 24 | # Coverage directory used by tools like istanbul 25 | coverage 26 | *.lcov 27 | 28 | # nyc test coverage 29 | .nyc_output 30 | 31 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 32 | .grunt 33 | 34 | # Bower dependency directory (https://bower.io/) 35 | bower_components 36 | 37 | # node-waf configuration 38 | .lock-wscript 39 | 40 | # Compiled binary addons (https://nodejs.org/api/addons.html) 41 | build/Release 42 | 43 | # Dependency directories 44 | node_modules/ 45 | jspm_packages/ 46 | 47 | # Snowpack dependency directory (https://snowpack.dev/) 48 | web_modules/ 49 | 50 | # TypeScript cache 51 | *.tsbuildinfo 52 | 53 | # Optional npm cache directory 54 | .npm 55 | 56 | # Optional eslint cache 57 | .eslintcache 58 | 59 | # Microbundle cache 60 | .rpt2_cache/ 61 | .rts2_cache_cjs/ 62 | .rts2_cache_es/ 63 | .rts2_cache_umd/ 64 | 65 | # Optional REPL history 66 | .node_repl_history 67 | 68 | # Output of 'npm pack' 69 | *.tgz 70 | 71 | # Yarn Integrity file 72 | .yarn-integrity 73 | 74 | # dotenv environment variables file 75 | .env 76 | .env.test 77 | 78 | # parcel-bundler cache (https://parceljs.org/) 79 | .cache 80 | .parcel-cache 81 | 82 | # Next.js build output 83 | .next 84 | out 85 | 86 | # Nuxt.js build / generate output 87 | .nuxt 88 | # dist 89 | 90 | # Gatsby files 91 | .cache/ 92 | # Comment in the public line in if your project uses Gatsby and not Next.js 93 | # https://nextjs.org/blog/next-9-1#public-directory-support 94 | # public 95 | 96 | # vuepress build output 97 | .vuepress/dist 98 | 99 | # Serverless directories 100 | .serverless/ 101 | 102 | # FuseBox cache 103 | .fusebox/ 104 | 105 | # DynamoDB Local files 106 | .dynamodb/ 107 | 108 | # TernJS port file 109 | .tern-port 110 | 111 | # Stores VSCode versions used for testing VSCode extensions 112 | .vscode-test 113 | 114 | # yarn v2 115 | .yarn/cache 116 | .yarn/unplugged 117 | .yarn/build-state.yml 118 | .yarn/install-state.gz 119 | .pnp.* -------------------------------------------------------------------------------- /info.md: -------------------------------------------------------------------------------- 1 |

2 | achievibit Logo 3 | 4 |

5 | @kibibit/hass-kibibit-theme 6 |

7 |

8 |

9 | 10 | 11 |

12 |

13 | A Home Assistant card for Steam integrations 14 |

15 |
16 | 17 | ([Theme](https://github.com/kibibit/hass-kibibit-theme) used in screenshots) 18 | 19 | ## Screenshots 20 | 21 | ### away \ offline state 22 | 23 | ![away \ offline state](screenshots/offline.jpeg) 24 | 25 | ### online state 26 | 27 | ![online state](screenshots/online.jpeg) 28 | 29 | ### while playing a game 30 | 31 | ![now playing](screenshots/now-playing.jpeg) 32 | 33 | ## Installation 34 | 35 | ### Prerequisites 36 | 37 | You need at least one [steam integration]() to use with this card. 38 | 39 | ### HACS (recommended) 40 | 41 | 1. Go to the Community Store. 42 | 2. Search for `steam card`. 43 | 3. Press `Install`. 44 | 45 | ### Manual Installation 46 | 47 | ```yaml 48 | resources: 49 | url: '' 50 | type: module 51 | ``` 52 | 53 | ## Usage 54 | 55 | for a single user card, use `entity`: 56 | 57 | ```yaml 58 | entity: sensor.steam_ 59 | type: 'custom:kb-steam-card' 60 | ``` 61 | 62 | you can change the username using the following: 63 | 64 | ```yaml 65 | entity: sensor.steam_ 66 | friendly_name: Myself 67 | type: 'custom:kb-steam-card' 68 | ``` 69 | 70 | for multiple users, use the `entities` attribute: 71 | ![](screenshots/multi.png) 72 | 73 | ```yaml 74 | entities: 75 | - sensor.steam_ 76 | - sensor.steam_ 77 | - sensor.steam_ 78 | type: 'custom:kb-steam-card' 79 | ``` 80 | 81 | you can also show the game header image as background with `game_background: true`: 82 | ![](screenshots/game-bg.png) 83 | 84 | ```yaml 85 | entities: 86 | - sensor.steam_ 87 | - sensor.steam_ 88 | - sensor.steam_ 89 | friendly_name: hello 90 | game_background: true 91 | type: 'custom:kb-steam-card' 92 | ``` 93 | 94 | ## Stay in touch 95 | 96 | - Author - [Neil Kalman](https://github.com/thatkookooguy) 97 | - Website - [https://github.com/kibibit](https://github.com/kibibit) 98 | - StackOverflow - [thatkookooguy](https://stackoverflow.com/users/1788884/thatkookooguy) 99 | - Twitter - [@thatkookooguy](https://twitter.com/thatkookooguy) 100 | - Twitter - [@kibibit_opensrc](https://twitter.com/kibibit_opensrc) 101 | 102 | ## Support 103 | 104 | Hey dude! Help me out for a couple of :beers: or a :coffee: by clicking on the sponsering link! 105 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at neilkalman@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@kibibit/kb-steam-card", 3 | "version": "0.0.0-development", 4 | "description": "Lovelace Steam Card", 5 | "keywords": [ 6 | "home-assistant", 7 | "homeassistant", 8 | "hass", 9 | "automation", 10 | "lovelace", 11 | "custom-cards", 12 | "hassio" 13 | ], 14 | "module": "dist/kb-steam-card.js", 15 | "files": [ 16 | "/dist", 17 | "info.md", 18 | "/themes", 19 | "hacs.json" 20 | ], 21 | "author": "thatkookooguy ", 22 | "license": "MIT", 23 | "dependencies": { 24 | "custom-card-helpers": "^1.6.6", 25 | "home-assistant-js-websocket": "^5.7.0", 26 | "lit-element": "^2.4.0", 27 | "lit-html": "^1.3.0", 28 | "timeago": "^1.6.7", 29 | "timeago.js": "^4.0.2" 30 | }, 31 | "devDependencies": { 32 | "@babel/core": "^7.12.3", 33 | "@babel/plugin-proposal-class-properties": "^7.12.1", 34 | "@babel/plugin-proposal-decorators": "^7.12.1", 35 | "@commitlint/cli": "^11.0.0", 36 | "@commitlint/config-angular": "^11.0.0", 37 | "@commitlint/config-conventional": "^11.0.0", 38 | "@rollup/plugin-json": "^4.1.0", 39 | "@semantic-release/commit-analyzer": "^8.0.1", 40 | "@semantic-release/exec": "^5.0.0", 41 | "@semantic-release/git": "^9.0.0", 42 | "@semantic-release/github": "^7.1.2", 43 | "@semantic-release/release-notes-generator": "^9.0.1", 44 | "@typescript-eslint/eslint-plugin": "^4.7.0", 45 | "@typescript-eslint/parser": "^4.7.0", 46 | "all-contributors-cli": "^6.19.0", 47 | "commitizen": "^4.2.2", 48 | "coveralls": "^3.1.0", 49 | "cz-conventional-changelog": "^3.3.0", 50 | "eslint": "^7.13.0", 51 | "eslint-config-airbnb-base": "^14.2.1", 52 | "eslint-config-prettier": "^6.15.0", 53 | "eslint-plugin-import": "^2.22.1", 54 | "eslint-plugin-prettier": "^3.1.4", 55 | "husky": "^4.3.0", 56 | "jest": "^26.6.3", 57 | "jest-stare": "^2.2.0", 58 | "prettier": "^2.1.2", 59 | "rollup": "^2.33.2", 60 | "rollup-plugin-babel": "^4.3.3", 61 | "rollup-plugin-commonjs": "^10.1.0", 62 | "rollup-plugin-node-resolve": "^5.2.0", 63 | "rollup-plugin-serve": "^1.1.0", 64 | "rollup-plugin-terser": "^7.0.2", 65 | "rollup-plugin-typescript2": "^0.29.0", 66 | "rollup-plugin-uglify": "^6.0.4", 67 | "semantic-release": "^17.2.2", 68 | "semantic-release-cli": "^5.4.0", 69 | "ts-jest": "^26.4.4", 70 | "ts-node": "^9.0.0", 71 | "typescript": "^4.0.5" 72 | }, 73 | "scripts": { 74 | "contributors:add": "all-contributors add", 75 | "contributors:generate": "all-contributors generate", 76 | "start": "rollup -c --watch", 77 | "build": "npm run lint && npm run rollup", 78 | "lint": "eslint src/*.ts", 79 | "lint:fix": "eslint src/*.ts --fix", 80 | "rollup": "rollup -c", 81 | "commit": "cz", 82 | "semantic-release": "semantic-release", 83 | "semantic-release:init": "semantic-release-cli setup" 84 | }, 85 | "config": { 86 | "commitizen": { 87 | "path": "./node_modules/cz-conventional-changelog" 88 | } 89 | }, 90 | "husky": { 91 | "hooks": { 92 | "prepare-commit-msg": "exec < /dev/tty && git cz --hook || true", 93 | "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" 94 | } 95 | }, 96 | "publishConfig": { 97 | "access": "public" 98 | }, 99 | "repository": { 100 | "type": "git", 101 | "url": "https://github.com/Kibibit/kb-steam-card.git" 102 | }, 103 | "bugs": { 104 | "url": "https://github.com/Kibibit/kb-steam-card/issues" 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | achievibit Logo 3 | 4 |

5 | @kibibit/hass-kibibit-theme 6 |

7 |

8 |

9 | 10 |

11 |

12 | 13 | 14 |

15 |

16 | A Home Assistant card for Steam integrations 17 |

18 |
19 | 20 | ([Theme](https://github.com/kibibit/hass-kibibit-theme) used in screenshots) 21 | 22 | ## Screenshots 23 | 24 | ### away \ offline state 25 | 26 | ![away \ offline state](https://thatkookooguy.github.io/https-assets/screenshots/kb-steam-card-offline.jpeg) 27 | 28 | ### online state 29 | 30 | ![online state](https://thatkookooguy.github.io/https-assets/screenshots/kb-steam-card-online.jpeg) 31 | 32 | ### while playing a game 33 | 34 | ![now playing](https://thatkookooguy.github.io/https-assets/screenshots/kb-steam-card-now-playing.jpeg) 35 | 36 | ## Installation 37 | 38 | ### Prerequisites 39 | You need at least one [steam integration](https://www.home-assistant.io/integrations/steam_online/) to use with this card. 40 | 41 | ### HACS (recommended) 42 | 43 | 1. Go to the Community Store. 44 | 2. Search for `steam card`. 45 | 3. Press `Install`. 46 | 47 | ### Manual Installation 48 | 49 | ```yaml 50 | resources: 51 | url: '' 52 | type: module 53 | ``` 54 | 55 | ## Usage 56 | 57 | for a single user card, use `entity`: 58 | 59 | ```yaml 60 | entity: sensor.steam_ 61 | type: 'custom:kb-steam-card' 62 | ``` 63 | 64 | you can change the username using the following: 65 | 66 | ```yaml 67 | entity: sensor.steam_ 68 | friendly_name: Myself 69 | type: 'custom:kb-steam-card' 70 | ``` 71 | 72 | for multiple users, use the `entities` attribute: 73 | ![](screenshots/multi.png) 74 | 75 | ```yaml 76 | entities: 77 | - sensor.steam_ 78 | - sensor.steam_ 79 | - sensor.steam_ 80 | type: 'custom:kb-steam-card' 81 | ``` 82 | 83 | you can also use a prefix selector to select all steam sensors: 84 | 85 | ```yaml 86 | type: 'custom:kb-steam-card' 87 | entities: sensor.steam_ 88 | ``` 89 | 90 | to show only **online users**, add the `online_only` attribute: 91 | 92 | ```yaml 93 | type: 'custom:kb-steam-card' 94 | entities: sensor.steam_ 95 | online_only: true 96 | ``` 97 | 98 | you can also show the game header image as background with `game_background: true`: 99 | ![](screenshots/game-bg.png) 100 | 101 | ```yaml 102 | entities: 103 | - sensor.steam_ 104 | - sensor.steam_ 105 | - sensor.steam_ 106 | friendly_name: hello 107 | game_background: true 108 | type: 'custom:kb-steam-card' 109 | ``` 110 | 111 | ## Stay in touch 112 | 113 | - Author - [Neil Kalman](https://github.com/thatkookooguy) 114 | - Website - [https://github.com/kibibit](https://github.com/kibibit) 115 | - StackOverflow - [thatkookooguy](https://stackoverflow.com/users/1788884/thatkookooguy) 116 | - Twitter - [@thatkookooguy](https://twitter.com/thatkookooguy) 117 | - Twitter - [@kibibit_opensrc](https://twitter.com/kibibit_opensrc) 118 | 119 | ## Support 120 | 121 | Hey dude! Help me out for a couple of :beers: or a :coffee: by clicking on the sponsering link! 122 | -------------------------------------------------------------------------------- /src/kb-steam-card.ts: -------------------------------------------------------------------------------- 1 | import { LitElement, html, customElement, CSSResult, TemplateResult, css, PropertyDeclarations } from 'lit-element'; 2 | 3 | import * as packageDetails from '../package.json'; 4 | 5 | declare global { 6 | interface Window { 7 | customCards: { 8 | type: string; 9 | name: string; 10 | description: string; 11 | }[]; 12 | } 13 | } 14 | 15 | console.info( 16 | `%c KB-STEAM-CARD \n%c ${packageDetails.version} `, 17 | 'color: orange; font-weight: bold; background: black', 18 | 'color: white; font-weight: bold; background: dimgray', 19 | ); 20 | 21 | window.customCards = window.customCards || []; 22 | window.customCards.push({ 23 | type: 'kb-steam-card', 24 | name: 'kb Steam Card', 25 | description: 'A card to show Steam integrations', 26 | }); 27 | 28 | import { format } from 'timeago.js'; 29 | 30 | @customElement('kb-steam-card') 31 | class KbSteamCard extends LitElement { 32 | hass; 33 | config; 34 | static get properties(): PropertyDeclarations { 35 | return { 36 | hass: {}, 37 | config: {}, 38 | }; 39 | } 40 | 41 | render(): TemplateResult { 42 | return html` 43 | 44 | ${this.config.entity 45 | ? this.createEntityCard(this.hass.states[this.config.entity]) 46 | : this.createEntitiesCard(this.config.entities)} 47 | 48 | `; 49 | } 50 | 51 | setConfig(config): void { 52 | if (!config.entities && !config.entity) { 53 | throw new Error('You need to define either a single entity or an entities field'); 54 | } 55 | this.config = config; 56 | } 57 | 58 | // The height of your card. Home Assistant uses this to automatically 59 | // distribute all cards over the available columns. 60 | getCardSize(): number { 61 | return this.config.entities ? this.config.entities.length + 1 : 2; 62 | } 63 | 64 | _toggle(state): void { 65 | this.hass.callService('homeassistant', 'toggle', { 66 | entity_id: state.entity_id, 67 | }); 68 | } 69 | 70 | createEntitiesCard(entities): TemplateResult[] { 71 | if (typeof entities === 'string') { 72 | const newEntities = [] as string[]; 73 | 74 | Object.values(this.hass.states).forEach((entity: any) => { 75 | if (entity.entity_id.startsWith(entities)) { 76 | newEntities.push(entity.entity_id); 77 | } 78 | }); 79 | 80 | entities = newEntities; 81 | } 82 | 83 | if (this.config.online_only) { 84 | const newEntities = [] as string[]; 85 | 86 | entities.forEach((entity: string) => { 87 | const entityObj = this.hass.states[entity]; 88 | if (entityObj && entityObj.state && entityObj.state !== 'offline') { 89 | newEntities.push(entity); 90 | } 91 | }); 92 | 93 | entities = newEntities; 94 | } 95 | 96 | return [ 97 | html`
Steam Friends
`, 98 | ...entities.map((ent, index) => { 99 | const entity = this.hass.states[ent]; 100 | return entity 101 | ? html` 102 |
this.handlePopup(entity)} 105 | > 106 |
107 | 108 |
${entity.attributes.friendly_name}
109 |
110 |
${entity.attributes.game || '-'}
111 | ${entity.attributes.game && this.config.game_background 112 | ? html` ` 113 | : ''} 114 |
115 | ` 116 | : html`
Entity ${ent} not found.
`; 117 | }), 118 | ]; 119 | } 120 | 121 | handlePopup(entity) { 122 | const entityId = entity.entity_id; 123 | const e = new Event('hass-more-info', { composed: true }) as any; 124 | e.detail = { entityId }; 125 | this.dispatchEvent(e); 126 | } 127 | 128 | createEntityCard(entity): TemplateResult { 129 | return html` 130 |
this.handlePopup(entity)}> 131 |
132 | ${this.config.friendly_name ? this.config.friendly_name : entity.attributes.friendly_name} 133 |
134 | ${this.renderUserAvatar(entity)} 135 |
${entity.state}
136 |
137 | 138 | ${entity.attributes.level} 139 | 140 | 141 |
142 |
143 | 144 | 145 | ${entity.state === 'online' ? 'Online Since' : 'Last Online'} 146 | 147 | ${this.formatLastOnline(entity.attributes.last_online)} 148 |
149 | ${this.renderCurrentlyPlayingGame(entity)} 150 |
151 | `; 152 | } 153 | 154 | formatLastOnline(lastOnline): string { 155 | return format(new Date(lastOnline)); 156 | } 157 | 158 | renderUserAvatar(entity): TemplateResult { 159 | return entity.attributes.entity_picture 160 | ? html` ` 161 | : html` `; 162 | } 163 | 164 | renderCurrentlyPlayingGame(entity): TemplateResult { 165 | const currentlyPlayingGame = entity.attributes.game; 166 | 167 | return currentlyPlayingGame 168 | ? html` 169 |
170 |
Now Playing
171 |
${entity.attributes.game}
172 | 173 |
174 | ` 175 | : html``; 176 | } 177 | 178 | static get styles(): CSSResult { 179 | return css` 180 | /* :host { 181 | } */ 182 | 183 | .card-header { 184 | width: 100%; 185 | padding-top: 8px; 186 | padding-bottom: 8px; 187 | } 188 | 189 | .kb-clickable { 190 | cursor: pointer; 191 | } 192 | 193 | .kb-steam-value { 194 | padding: 0 0.3em; 195 | } 196 | 197 | .kb-steam-value, 198 | .kb-steam-user { 199 | z-index: 2; 200 | } 201 | 202 | .kb-steam-game-bg { 203 | z-index: 0; 204 | position: absolute; 205 | right: 0; 206 | height: 170%; 207 | width: auto; 208 | opacity: 0.5; 209 | mask-image: linear-gradient(to right, transparent 10%, black 90%); 210 | -webkit-mask-image: linear-gradient(to right, transparent 10%, black 90%); 211 | } 212 | 213 | .not-found { 214 | background-color: yellow; 215 | font-family: sans-serif; 216 | font-size: 14px; 217 | padding: 8px; 218 | } 219 | 220 | ha-card, 221 | ha-card > .kb-container { 222 | padding: 16px; 223 | display: flex; 224 | flex-direction: column; 225 | align-items: center; 226 | } 227 | 228 | .kb-container { 229 | width: 100%; 230 | } 231 | 232 | .kb-steam-avatar { 233 | border-radius: 50%; 234 | width: 40px; 235 | height: 40px; 236 | margin: 8px; 237 | } 238 | 239 | ha-icon.kb-steam-avatar { 240 | display: flex; 241 | align-items: center; 242 | justify-content: center; 243 | background: rgba(0, 0, 0, 0.8); 244 | } 245 | 246 | .kb-steam-level { 247 | position: relative; 248 | margin: 16px; 249 | } 250 | 251 | .kb-steam-level > .kb-steam-level-text-container { 252 | position: absolute; 253 | top: 0; 254 | bottom: 0; 255 | left: 0; 256 | right: 0; 257 | display: flex; 258 | justify-content: center; 259 | /* align-items: center; */ 260 | margin-top: 2px; 261 | color: var(--secondary-background-color); 262 | z-index: 2; 263 | /* fix for font */ 264 | transform: translateY(1px); 265 | } 266 | 267 | .kb-steam-last-online { 268 | width: 100%; 269 | display: flex; 270 | align-items: center; 271 | justify-content: space-between; 272 | } 273 | 274 | .kb-steam-now-playing { 275 | width: 100%; 276 | overflow: hidden; 277 | margin-top: 2em; 278 | } 279 | 280 | .kb-steam-now-playing > .game-title { 281 | font-size: 1.7em; 282 | margin: 0.2em 0 1.5em; 283 | } 284 | 285 | .kb-steam-now-playing > .game-img { 286 | width: 100%; 287 | height: auto; 288 | } 289 | 290 | .kb-steam-multi { 291 | width: 100%; 292 | display: flex; 293 | align-items: center; 294 | justify-content: space-between; 295 | margin: 0 0 8px; 296 | position: relative; 297 | overflow: hidden; 298 | } 299 | 300 | .kb-steam-multi .kb-steam-user { 301 | display: flex; 302 | align-items: center; 303 | } 304 | 305 | .kb-steam-multi .kb-steam-avatar { 306 | margin: 0 16px 0 0; 307 | } 308 | 309 | .kb-steam-multi::before { 310 | z-index: 1; 311 | position: absolute; 312 | bottom: 0; 313 | left: 2em; 314 | width: 1em; 315 | height: 1em; 316 | border-radius: 50%; 317 | background: #646464; 318 | background-image: radial-gradient(top, #616161 0%, #616161 20%, #535353 60%); 319 | content: ''; 320 | z-index: 3; 321 | } 322 | 323 | .kb-steam-multi.online::before, 324 | .kb-steam-multi.snooze::before { 325 | box-shadow: 0 0 1em #1c1c17, 0 0 1em #ff4242; 326 | background: #ff4f4f; 327 | } 328 | 329 | .kb-last { 330 | margin-bottom: 0; 331 | } 332 | `; 333 | } 334 | } 335 | -------------------------------------------------------------------------------- /dist/kb-steam-card.js: -------------------------------------------------------------------------------- 1 | /*! ***************************************************************************** 2 | Copyright (c) Microsoft Corporation. 3 | 4 | Permission to use, copy, modify, and/or distribute this software for any 5 | purpose with or without fee is hereby granted. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 8 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 9 | AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 10 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 11 | LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 12 | OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 13 | PERFORMANCE OF THIS SOFTWARE. 14 | ***************************************************************************** */ 15 | /** 16 | * @license 17 | * Copyright (c) 2017 The Polymer Project Authors. All rights reserved. 18 | * This code may only be used under the BSD style license found at 19 | * http://polymer.github.io/LICENSE.txt 20 | * The complete set of authors may be found at 21 | * http://polymer.github.io/AUTHORS.txt 22 | * The complete set of contributors may be found at 23 | * http://polymer.github.io/CONTRIBUTORS.txt 24 | * Code distributed by Google as part of the polymer project is also 25 | * subject to an additional IP rights grant found at 26 | * http://polymer.github.io/PATENTS.txt 27 | */ 28 | const t="undefined"!=typeof window&&null!=window.customElements&&void 0!==window.customElements.polyfillWrapFlushCallback,e=(t,e,s=null)=>{for(;e!==s;){const s=e.nextSibling;t.removeChild(e),e=s}},s=`{{lit-${String(Math.random()).slice(2)}}}`,i=`\x3c!--${s}--\x3e`,n=new RegExp(`${s}|${i}`);class r{constructor(t,e){this.parts=[],this.element=e;const i=[],r=[],o=document.createTreeWalker(e.content,133,null,!1);let d=0,h=-1,p=0;const{strings:u,values:{length:m}}=t;for(;p0;){const e=u[p],s=c.exec(e)[2],i=s.toLowerCase()+"$lit$",r=t.getAttribute(i);t.removeAttribute(i);const a=r.split(n);this.parts.push({type:"attribute",index:h,name:s,strings:a}),p+=a.length-1}}"TEMPLATE"===t.tagName&&(r.push(t),o.currentNode=t.content)}else if(3===t.nodeType){const e=t.data;if(e.indexOf(s)>=0){const s=t.parentNode,r=e.split(n),o=r.length-1;for(let e=0;e{const s=t.length-e.length;return s>=0&&t.slice(s)===e},o=t=>-1!==t.index,l=()=>document.createComment(""),c=/([ \x09\x0a\x0c\x0d])([^\0-\x1F\x7F-\x9F "'>=/]+)([ \x09\x0a\x0c\x0d]*=[ \x09\x0a\x0c\x0d]*(?:[^ \x09\x0a\x0c\x0d"'`<>=]*|"[^"]*|'[^']*))$/;function d(t,e){const{element:{content:s},parts:i}=t,n=document.createTreeWalker(s,133,null,!1);let r=p(i),a=i[r],o=-1,l=0;const c=[];let d=null;for(;n.nextNode();){o++;const t=n.currentNode;for(t.previousSibling===d&&(d=null),e.has(t)&&(c.push(t),null===d&&(d=t)),null!==d&&l++;void 0!==a&&a.index===o;)a.index=null!==d?-1:a.index-l,r=p(i,r),a=i[r]}c.forEach((t=>t.parentNode.removeChild(t)))}const h=t=>{let e=11===t.nodeType?0:1;const s=document.createTreeWalker(t,133,null,!1);for(;s.nextNode();)e++;return e},p=(t,e=-1)=>{for(let s=e+1;s"function"==typeof t&&u.has(t),f={},g={}; 43 | /** 44 | * @license 45 | * Copyright (c) 2017 The Polymer Project Authors. All rights reserved. 46 | * This code may only be used under the BSD style license found at 47 | * http://polymer.github.io/LICENSE.txt 48 | * The complete set of authors may be found at 49 | * http://polymer.github.io/AUTHORS.txt 50 | * The complete set of contributors may be found at 51 | * http://polymer.github.io/CONTRIBUTORS.txt 52 | * Code distributed by Google as part of the polymer project is also 53 | * subject to an additional IP rights grant found at 54 | * http://polymer.github.io/PATENTS.txt 55 | */ 56 | class y{constructor(t,e,s){this.__parts=[],this.template=t,this.processor=e,this.options=s}update(t){let e=0;for(const s of this.__parts)void 0!==s&&s.setValue(t[e]),e++;for(const t of this.__parts)void 0!==t&&t.commit()}_clone(){const e=t?this.template.element.content.cloneNode(!0):document.importNode(this.template.element.content,!0),s=[],i=this.template.parts,n=document.createTreeWalker(e,133,null,!1);let r,a=0,l=0,c=n.nextNode();for(;at}),v=` ${s} `;class b{constructor(t,e,s,i){this.strings=t,this.values=e,this.type=s,this.processor=i}getHTML(){const t=this.strings.length-1;let e="",n=!1;for(let r=0;r-1||n)&&-1===t.indexOf("--\x3e",a+1);const o=c.exec(t);e+=null===o?t+(n?v:i):t.substr(0,o.index)+o[1]+o[2]+"$lit$"+o[3]+s}return e+=this.strings[t],e}getTemplateElement(){const t=document.createElement("template");let e=this.getHTML();return void 0!==_&&(e=_.createHTML(e)),t.innerHTML=e,t}} 70 | /** 71 | * @license 72 | * Copyright (c) 2017 The Polymer Project Authors. All rights reserved. 73 | * This code may only be used under the BSD style license found at 74 | * http://polymer.github.io/LICENSE.txt 75 | * The complete set of authors may be found at 76 | * http://polymer.github.io/AUTHORS.txt 77 | * The complete set of contributors may be found at 78 | * http://polymer.github.io/CONTRIBUTORS.txt 79 | * Code distributed by Google as part of the polymer project is also 80 | * subject to an additional IP rights grant found at 81 | * http://polymer.github.io/PATENTS.txt 82 | */const S=t=>null===t||!("object"==typeof t||"function"==typeof t),w=t=>Array.isArray(t)||!(!t||!t[Symbol.iterator]);class x{constructor(t,e,s){this.dirty=!0,this.element=t,this.name=e,this.strings=s,this.parts=[];for(let t=0;t{try{const t={get capture(){return T=!0,!1}};window.addEventListener("test",t,t),window.removeEventListener("test",t,t)}catch(t){}})();class A{constructor(t,e,s){this.value=void 0,this.__pendingValue=void 0,this.element=t,this.eventName=e,this.eventContext=s,this.__boundHandleEvent=t=>this.handleEvent(t)}setValue(t){this.__pendingValue=t}commit(){for(;m(this.__pendingValue);){const t=this.__pendingValue;this.__pendingValue=f,t(this)}if(this.__pendingValue===f)return;const t=this.__pendingValue,e=this.value,s=null==t||null!=e&&(t.capture!==e.capture||t.once!==e.once||t.passive!==e.passive),i=null!=t&&(null==e||s);s&&this.element.removeEventListener(this.eventName,this.__boundHandleEvent,this.__options),i&&(this.__options=$(t),this.element.addEventListener(this.eventName,this.__boundHandleEvent,this.__options)),this.value=t,this.__pendingValue=f}handleEvent(t){"function"==typeof this.value?this.value.call(this.eventContext||this.element,t):this.value.handleEvent(t)}}const $=t=>t&&(T?{capture:t.capture,passive:t.passive,once:t.once}:t.capture) 83 | /** 84 | * @license 85 | * Copyright (c) 2017 The Polymer Project Authors. All rights reserved. 86 | * This code may only be used under the BSD style license found at 87 | * http://polymer.github.io/LICENSE.txt 88 | * The complete set of authors may be found at 89 | * http://polymer.github.io/AUTHORS.txt 90 | * The complete set of contributors may be found at 91 | * http://polymer.github.io/CONTRIBUTORS.txt 92 | * Code distributed by Google as part of the polymer project is also 93 | * subject to an additional IP rights grant found at 94 | * http://polymer.github.io/PATENTS.txt 95 | */;function V(t){let e=U.get(t.type);void 0===e&&(e={stringsArray:new WeakMap,keyString:new Map},U.set(t.type,e));let i=e.stringsArray.get(t.strings);if(void 0!==i)return i;const n=t.strings.join(s);return i=e.keyString.get(n),void 0===i&&(i=new r(t,t.getTemplateElement()),e.keyString.set(n,i)),e.stringsArray.set(t.strings,i),i}const U=new Map,O=new WeakMap; 96 | /** 97 | * @license 98 | * Copyright (c) 2017 The Polymer Project Authors. All rights reserved. 99 | * This code may only be used under the BSD style license found at 100 | * http://polymer.github.io/LICENSE.txt 101 | * The complete set of authors may be found at 102 | * http://polymer.github.io/AUTHORS.txt 103 | * The complete set of contributors may be found at 104 | * http://polymer.github.io/CONTRIBUTORS.txt 105 | * Code distributed by Google as part of the polymer project is also 106 | * subject to an additional IP rights grant found at 107 | * http://polymer.github.io/PATENTS.txt 108 | */const R=new 109 | /** 110 | * @license 111 | * Copyright (c) 2017 The Polymer Project Authors. All rights reserved. 112 | * This code may only be used under the BSD style license found at 113 | * http://polymer.github.io/LICENSE.txt 114 | * The complete set of authors may be found at 115 | * http://polymer.github.io/AUTHORS.txt 116 | * The complete set of contributors may be found at 117 | * http://polymer.github.io/CONTRIBUTORS.txt 118 | * Code distributed by Google as part of the polymer project is also 119 | * subject to an additional IP rights grant found at 120 | * http://polymer.github.io/PATENTS.txt 121 | */ 122 | class{handleAttributeExpressions(t,e,s,i){const n=e[0];if("."===n){return new N(t,e.slice(1),s).parts}if("@"===n)return[new A(t,e.slice(1),i.eventContext)];if("?"===n)return[new C(t,e.slice(1),s)];return new x(t,e,s).parts}handleTextExpression(t){return new P(t)}}; 123 | /** 124 | * @license 125 | * Copyright (c) 2017 The Polymer Project Authors. All rights reserved. 126 | * This code may only be used under the BSD style license found at 127 | * http://polymer.github.io/LICENSE.txt 128 | * The complete set of authors may be found at 129 | * http://polymer.github.io/AUTHORS.txt 130 | * The complete set of contributors may be found at 131 | * http://polymer.github.io/CONTRIBUTORS.txt 132 | * Code distributed by Google as part of the polymer project is also 133 | * subject to an additional IP rights grant found at 134 | * http://polymer.github.io/PATENTS.txt 135 | */"undefined"!=typeof window&&(window.litHtmlVersions||(window.litHtmlVersions=[])).push("1.3.0");const M=(t,...e)=>new b(t,e,"html",R) 136 | /** 137 | * @license 138 | * Copyright (c) 2017 The Polymer Project Authors. All rights reserved. 139 | * This code may only be used under the BSD style license found at 140 | * http://polymer.github.io/LICENSE.txt 141 | * The complete set of authors may be found at 142 | * http://polymer.github.io/AUTHORS.txt 143 | * The complete set of contributors may be found at 144 | * http://polymer.github.io/CONTRIBUTORS.txt 145 | * Code distributed by Google as part of the polymer project is also 146 | * subject to an additional IP rights grant found at 147 | * http://polymer.github.io/PATENTS.txt 148 | */,j=(t,e)=>`${t}--${e}`;let z=!0;void 0===window.ShadyCSS?z=!1:void 0===window.ShadyCSS.prepareTemplateDom&&(console.warn("Incompatible ShadyCSS version detected. Please update to at least @webcomponents/webcomponentsjs@2.0.2 and @webcomponents/shadycss@1.3.1."),z=!1);const I=t=>e=>{const i=j(e.type,t);let n=U.get(i);void 0===n&&(n={stringsArray:new WeakMap,keyString:new Map},U.set(i,n));let a=n.stringsArray.get(e.strings);if(void 0!==a)return a;const o=e.strings.join(s);if(a=n.keyString.get(o),void 0===a){const s=e.getTemplateElement();z&&window.ShadyCSS.prepareTemplateDom(s,t),a=new r(e,s),n.keyString.set(o,a)}return n.stringsArray.set(e.strings,a),a},q=["html","svg"],L=new Set,D=(t,e,s)=>{L.add(t);const i=s?s.element:document.createElement("template"),n=e.querySelectorAll("style"),{length:r}=n;if(0===r)return void window.ShadyCSS.prepareTemplateStyles(i,t);const a=document.createElement("style");for(let t=0;t{q.forEach((e=>{const s=U.get(j(e,t));void 0!==s&&s.keyString.forEach((t=>{const{element:{content:e}}=t,s=new Set;Array.from(e.querySelectorAll("style")).forEach((t=>{s.add(t)})),d(t,s)}))}))})(t);const o=i.content;s?function(t,e,s=null){const{element:{content:i},parts:n}=t;if(null==s)return void i.appendChild(e);const r=document.createTreeWalker(i,133,null,!1);let a=p(n),o=0,l=-1;for(;r.nextNode();)for(l++,r.currentNode===s&&(o=h(e),s.parentNode.insertBefore(e,s));-1!==a&&n[a].index===l;){if(o>0){for(;-1!==a;)n[a].index+=o,a=p(n,a);return}a=p(n,a)}}(s,a,o.firstChild):o.insertBefore(a,o.firstChild),window.ShadyCSS.prepareTemplateStyles(i,t);const l=o.querySelector("style");if(window.ShadyCSS.nativeShadow&&null!==l)e.insertBefore(l.cloneNode(!0),e.firstChild);else if(s){o.insertBefore(a,o.firstChild);const t=new Set;t.add(a),d(s,t)}};window.JSCompiler_renameProperty=(t,e)=>t;const F={toAttribute(t,e){switch(e){case Boolean:return t?"":null;case Object:case Array:return null==t?t:JSON.stringify(t)}return t},fromAttribute(t,e){switch(e){case Boolean:return null!==t;case Number:return null===t?null:Number(t);case Object:case Array:return JSON.parse(t)}return t}},H=(t,e)=>e!==t&&(e==e||t==t),B={attribute:!0,type:String,converter:F,reflect:!1,hasChanged:H};class W extends HTMLElement{constructor(){super(),this.initialize()}static get observedAttributes(){this.finalize();const t=[];return this._classProperties.forEach(((e,s)=>{const i=this._attributeNameForProperty(s,e);void 0!==i&&(this._attributeToPropertyMap.set(i,s),t.push(i))})),t}static _ensureClassProperties(){if(!this.hasOwnProperty(JSCompiler_renameProperty("_classProperties",this))){this._classProperties=new Map;const t=Object.getPrototypeOf(this)._classProperties;void 0!==t&&t.forEach(((t,e)=>this._classProperties.set(e,t)))}}static createProperty(t,e=B){if(this._ensureClassProperties(),this._classProperties.set(t,e),e.noAccessor||this.prototype.hasOwnProperty(t))return;const s="symbol"==typeof t?Symbol():"__"+t,i=this.getPropertyDescriptor(t,s,e);void 0!==i&&Object.defineProperty(this.prototype,t,i)}static getPropertyDescriptor(t,e,s){return{get(){return this[e]},set(i){const n=this[t];this[e]=i,this.requestUpdateInternal(t,n,s)},configurable:!0,enumerable:!0}}static getPropertyOptions(t){return this._classProperties&&this._classProperties.get(t)||B}static finalize(){const t=Object.getPrototypeOf(this);if(t.hasOwnProperty("finalized")||t.finalize(),this.finalized=!0,this._ensureClassProperties(),this._attributeToPropertyMap=new Map,this.hasOwnProperty(JSCompiler_renameProperty("properties",this))){const t=this.properties,e=[...Object.getOwnPropertyNames(t),..."function"==typeof Object.getOwnPropertySymbols?Object.getOwnPropertySymbols(t):[]];for(const s of e)this.createProperty(s,t[s])}}static _attributeNameForProperty(t,e){const s=e.attribute;return!1===s?void 0:"string"==typeof s?s:"string"==typeof t?t.toLowerCase():void 0}static _valueHasChanged(t,e,s=H){return s(t,e)}static _propertyValueFromAttribute(t,e){const s=e.type,i=e.converter||F,n="function"==typeof i?i:i.fromAttribute;return n?n(t,s):t}static _propertyValueToAttribute(t,e){if(void 0===e.reflect)return;const s=e.type,i=e.converter;return(i&&i.toAttribute||F.toAttribute)(t,s)}initialize(){this._updateState=0,this._updatePromise=new Promise((t=>this._enableUpdatingResolver=t)),this._changedProperties=new Map,this._saveInstanceProperties(),this.requestUpdateInternal()}_saveInstanceProperties(){this.constructor._classProperties.forEach(((t,e)=>{if(this.hasOwnProperty(e)){const t=this[e];delete this[e],this._instanceProperties||(this._instanceProperties=new Map),this._instanceProperties.set(e,t)}}))}_applyInstanceProperties(){this._instanceProperties.forEach(((t,e)=>this[e]=t)),this._instanceProperties=void 0}connectedCallback(){this.enableUpdating()}enableUpdating(){void 0!==this._enableUpdatingResolver&&(this._enableUpdatingResolver(),this._enableUpdatingResolver=void 0)}disconnectedCallback(){}attributeChangedCallback(t,e,s){e!==s&&this._attributeToProperty(t,s)}_propertyToAttribute(t,e,s=B){const i=this.constructor,n=i._attributeNameForProperty(t,s);if(void 0!==n){const t=i._propertyValueToAttribute(e,s);if(void 0===t)return;this._updateState=8|this._updateState,null==t?this.removeAttribute(n):this.setAttribute(n,t),this._updateState=-9&this._updateState}}_attributeToProperty(t,e){if(8&this._updateState)return;const s=this.constructor,i=s._attributeToPropertyMap.get(t);if(void 0!==i){const t=s.getPropertyOptions(i);this._updateState=16|this._updateState,this[i]=s._propertyValueFromAttribute(e,t),this._updateState=-17&this._updateState}}requestUpdateInternal(t,e,s){let i=!0;if(void 0!==t){const n=this.constructor;s=s||n.getPropertyOptions(t),n._valueHasChanged(this[t],e,s.hasChanged)?(this._changedProperties.has(t)||this._changedProperties.set(t,e),!0!==s.reflect||16&this._updateState||(void 0===this._reflectingProperties&&(this._reflectingProperties=new Map),this._reflectingProperties.set(t,s))):i=!1}!this._hasRequestedUpdate&&i&&(this._updatePromise=this._enqueueUpdate())}requestUpdate(t,e){return this.requestUpdateInternal(t,e),this.updateComplete}async _enqueueUpdate(){this._updateState=4|this._updateState;try{await this._updatePromise}catch(t){}const t=this.performUpdate();return null!=t&&await t,!this._hasRequestedUpdate}get _hasRequestedUpdate(){return 4&this._updateState}get hasUpdated(){return 1&this._updateState}performUpdate(){if(!this._hasRequestedUpdate)return;this._instanceProperties&&this._applyInstanceProperties();let t=!1;const e=this._changedProperties;try{t=this.shouldUpdate(e),t?this.update(e):this._markUpdated()}catch(e){throw t=!1,this._markUpdated(),e}t&&(1&this._updateState||(this._updateState=1|this._updateState,this.firstUpdated(e)),this.updated(e))}_markUpdated(){this._changedProperties=new Map,this._updateState=-5&this._updateState}get updateComplete(){return this._getUpdateComplete()}_getUpdateComplete(){return this._updatePromise}shouldUpdate(t){return!0}update(t){void 0!==this._reflectingProperties&&this._reflectingProperties.size>0&&(this._reflectingProperties.forEach(((t,e)=>this._propertyToAttribute(e,this[e],t))),this._reflectingProperties=void 0),this._markUpdated()}updated(t){}firstUpdated(t){}}W.finalized=!0; 149 | /** 150 | * @license 151 | * Copyright (c) 2017 The Polymer Project Authors. All rights reserved. 152 | * This code may only be used under the BSD style license found at 153 | * http://polymer.github.io/LICENSE.txt 154 | * The complete set of authors may be found at 155 | * http://polymer.github.io/AUTHORS.txt 156 | * The complete set of contributors may be found at 157 | * http://polymer.github.io/CONTRIBUTORS.txt 158 | * Code distributed by Google as part of the polymer project is also 159 | * subject to an additional IP rights grant found at 160 | * http://polymer.github.io/PATENTS.txt 161 | */ 162 | const J=window.ShadowRoot&&(void 0===window.ShadyCSS||window.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,G=Symbol();class Y{constructor(t,e){if(e!==G)throw new Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=t}get styleSheet(){return void 0===this._styleSheet&&(J?(this._styleSheet=new CSSStyleSheet,this._styleSheet.replaceSync(this.cssText)):this._styleSheet=null),this._styleSheet}toString(){return this.cssText}}const K=(t,...e)=>{const s=e.reduce(((e,s,i)=>e+(t=>{if(t instanceof Y)return t.cssText;if("number"==typeof t)return t;throw new Error(`Value passed to 'css' function must be a 'css' function result: ${t}. Use 'unsafeCSS' to pass non-literal values, but\n take care to ensure page security.`)})(s)+t[i+1]),t[0]);return new Y(s,G)}; 163 | /** 164 | * @license 165 | * Copyright (c) 2017 The Polymer Project Authors. All rights reserved. 166 | * This code may only be used under the BSD style license found at 167 | * http://polymer.github.io/LICENSE.txt 168 | * The complete set of authors may be found at 169 | * http://polymer.github.io/AUTHORS.txt 170 | * The complete set of contributors may be found at 171 | * http://polymer.github.io/CONTRIBUTORS.txt 172 | * Code distributed by Google as part of the polymer project is also 173 | * subject to an additional IP rights grant found at 174 | * http://polymer.github.io/PATENTS.txt 175 | */ 176 | (window.litElementVersions||(window.litElementVersions=[])).push("2.4.0");const Z={};class Q extends W{static getStyles(){return this.styles}static _getUniqueStyles(){if(this.hasOwnProperty(JSCompiler_renameProperty("_styles",this)))return;const t=this.getStyles();if(Array.isArray(t)){const e=(t,s)=>t.reduceRight(((t,s)=>Array.isArray(s)?e(s,t):(t.add(s),t)),s),s=e(t,new Set),i=[];s.forEach((t=>i.unshift(t))),this._styles=i}else this._styles=void 0===t?[]:[t];this._styles=this._styles.map((t=>{if(t instanceof CSSStyleSheet&&!J){const e=Array.prototype.slice.call(t.cssRules).reduce(((t,e)=>t+e.cssText),"");return new Y(String(e),G)}return t}))}initialize(){super.initialize(),this.constructor._getUniqueStyles(),this.renderRoot=this.createRenderRoot(),window.ShadowRoot&&this.renderRoot instanceof window.ShadowRoot&&this.adoptStyles()}createRenderRoot(){return this.attachShadow({mode:"open"})}adoptStyles(){const t=this.constructor._styles;0!==t.length&&(void 0===window.ShadyCSS||window.ShadyCSS.nativeShadow?J?this.renderRoot.adoptedStyleSheets=t.map((t=>t instanceof CSSStyleSheet?t:t.styleSheet)):this._needsShimAdoptedStyleSheets=!0:window.ShadyCSS.ScopingShim.prepareAdoptedCssText(t.map((t=>t.cssText)),this.localName))}connectedCallback(){super.connectedCallback(),this.hasUpdated&&void 0!==window.ShadyCSS&&window.ShadyCSS.styleElement(this)}update(t){const e=this.render();super.update(t),e!==Z&&this.constructor.render(e,this.renderRoot,{scopeName:this.localName,eventContext:this}),this._needsShimAdoptedStyleSheets&&(this._needsShimAdoptedStyleSheets=!1,this.constructor._styles.forEach((t=>{const e=document.createElement("style");e.textContent=t.cssText,this.renderRoot.appendChild(e)})))}render(){return Z}}Q.finalized=!0,Q.render=(t,s,i)=>{if(!i||"object"!=typeof i||!i.scopeName)throw new Error("The `scopeName` option is required.");const n=i.scopeName,r=O.has(s),a=z&&11===s.nodeType&&!!s.host,o=a&&!L.has(n),l=o?document.createDocumentFragment():s;if(((t,s,i)=>{let n=O.get(s);void 0===n&&(e(s,s.firstChild),O.set(s,n=new P(Object.assign({templateFactory:V},i))),n.appendInto(s)),n.setValue(t),n.commit()})(t,l,Object.assign({templateFactory:I(n)},i)),o){const t=O.get(l);O.delete(l);const i=t.value instanceof y?t.value.template:void 0;D(n,l,i),e(s,s.firstChild),s.appendChild(l),O.set(s,t)}!r&&a&&window.ShadyCSS.styleElement(s.host)};var X=["second","minute","hour","day","week","month","year"];var tt=["秒","分钟","小时","天","周","个月","年"];var et={},st=function(t,e){et[t]=e},it=[60,60,24,7,365/7/12,12];function nt(t){return t instanceof Date?t:!isNaN(t)||/^\d+$/.test(t)?new Date(parseInt(t)):(t=(t||"").trim().replace(/\.\d+/,"").replace(/-/,"/").replace(/-/,"/").replace(/(\d)T(\d)/,"$1 $2").replace(/Z/," UTC").replace(/([+-]\d\d):?(\d\d)/," $1$2"),new Date(t))}var rt=function(t,e,s){return function(t,e){for(var s=t<0?1:0,i=t=Math.abs(t),n=0;t>=it[n]&&n(0==(n*=2)?9:1)&&(n+=1),e(t,n,i)[s].replace("%s",t.toString())}(function(t,e){return(+(e?nt(e):new Date)-+nt(t))/1e3}(t,s&&s.relativeDate),function(t){return et[t]||et.en_US}(e))};st("en_US",(function(t,e){if(0===e)return["just now","right now"];var s=X[Math.floor(e/2)];return t>1&&(s+="s"),[t+" "+s+" ago","in "+t+" "+s]})),st("zh_CN",(function(t,e){if(0===e)return["刚刚","片刻后"];var s=tt[~~(e/2)];return[t+" "+s+"前",t+" "+s+"后"]})),console.info("%c KB-STEAM-CARD \n%c 0.0.0-development ","color: orange; font-weight: bold; background: black","color: white; font-weight: bold; background: dimgray"),window.customCards=window.customCards||[],window.customCards.push({type:"kb-steam-card",name:"kb Steam Card",description:"A card to show Steam integrations"});let at=class extends Q{static get properties(){return{hass:{},config:{}}}render(){return M` 177 | 178 | ${this.config.entity?this.createEntityCard(this.hass.states[this.config.entity]):this.createEntitiesCard(this.config.entities)} 179 | 180 | `}setConfig(t){if(!t.entities&&!t.entity)throw new Error("You need to define either a single entity or an entities field");this.config=t}getCardSize(){return this.config.entities?this.config.entities.length+1:2}_toggle(t){this.hass.callService("homeassistant","toggle",{entity_id:t.entity_id})}createEntitiesCard(t){if("string"==typeof t){const e=[];Object.values(this.hass.states).forEach((s=>{s.entity_id.startsWith(t)&&e.push(s.entity_id)})),t=e}if(this.config.online_only){const e=[];t.forEach((t=>{const s=this.hass.states[t];s&&s.state&&"offline"!==s.state&&e.push(t)})),t=e}return[M`
Steam Friends
`,...t.map(((e,s)=>{const i=this.hass.states[e];return i?M` 181 |
this.handlePopup(i)} 184 | > 185 |
186 | 187 |
${i.attributes.friendly_name}
188 |
189 |
${i.attributes.game||"-"}
190 | ${i.attributes.game&&this.config.game_background?M` `:""} 191 |
192 | `:M`
Entity ${e} not found.
`}))]}handlePopup(t){const e=t.entity_id,s=new Event("hass-more-info",{composed:!0});s.detail={entityId:e},this.dispatchEvent(s)}createEntityCard(t){return M` 193 |
this.handlePopup(t)}> 194 |
195 | ${this.config.friendly_name?this.config.friendly_name:t.attributes.friendly_name} 196 |
197 | ${this.renderUserAvatar(t)} 198 |
${t.state}
199 |
200 | 201 | ${t.attributes.level} 202 | 203 | 204 |
205 |
206 | 207 | 208 | ${"online"===t.state?"Online Since":"Last Online"} 209 | 210 | ${this.formatLastOnline(t.attributes.last_online)} 211 |
212 | ${this.renderCurrentlyPlayingGame(t)} 213 |
214 | `}formatLastOnline(t){return rt(new Date(t))}renderUserAvatar(t){return t.attributes.entity_picture?M` `:M` `}renderCurrentlyPlayingGame(t){return t.attributes.game?M` 215 |
216 |
Now Playing
217 |
${t.attributes.game}
218 | 219 |
220 | `:M``}static get styles(){return K` 221 | /* :host { 222 | } */ 223 | 224 | .card-header { 225 | width: 100%; 226 | padding-top: 8px; 227 | padding-bottom: 8px; 228 | } 229 | 230 | .kb-clickable { 231 | cursor: pointer; 232 | } 233 | 234 | .kb-steam-value { 235 | padding: 0 0.3em; 236 | } 237 | 238 | .kb-steam-value, 239 | .kb-steam-user { 240 | z-index: 2; 241 | } 242 | 243 | .kb-steam-game-bg { 244 | z-index: 0; 245 | position: absolute; 246 | right: 0; 247 | height: 170%; 248 | width: auto; 249 | opacity: 0.5; 250 | mask-image: linear-gradient(to right, transparent 10%, black 90%); 251 | -webkit-mask-image: linear-gradient(to right, transparent 10%, black 90%); 252 | } 253 | 254 | .not-found { 255 | background-color: yellow; 256 | font-family: sans-serif; 257 | font-size: 14px; 258 | padding: 8px; 259 | } 260 | 261 | ha-card, 262 | ha-card > .kb-container { 263 | padding: 16px; 264 | display: flex; 265 | flex-direction: column; 266 | align-items: center; 267 | } 268 | 269 | .kb-container { 270 | width: 100%; 271 | } 272 | 273 | .kb-steam-avatar { 274 | border-radius: 50%; 275 | width: 40px; 276 | height: 40px; 277 | margin: 8px; 278 | } 279 | 280 | ha-icon.kb-steam-avatar { 281 | display: flex; 282 | align-items: center; 283 | justify-content: center; 284 | background: rgba(0, 0, 0, 0.8); 285 | } 286 | 287 | .kb-steam-level { 288 | position: relative; 289 | margin: 16px; 290 | } 291 | 292 | .kb-steam-level > .kb-steam-level-text-container { 293 | position: absolute; 294 | top: 0; 295 | bottom: 0; 296 | left: 0; 297 | right: 0; 298 | display: flex; 299 | justify-content: center; 300 | /* align-items: center; */ 301 | margin-top: 2px; 302 | color: var(--secondary-background-color); 303 | z-index: 2; 304 | /* fix for font */ 305 | transform: translateY(1px); 306 | } 307 | 308 | .kb-steam-last-online { 309 | width: 100%; 310 | display: flex; 311 | align-items: center; 312 | justify-content: space-between; 313 | } 314 | 315 | .kb-steam-now-playing { 316 | width: 100%; 317 | overflow: hidden; 318 | margin-top: 2em; 319 | } 320 | 321 | .kb-steam-now-playing > .game-title { 322 | font-size: 1.7em; 323 | margin: 0.2em 0 1.5em; 324 | } 325 | 326 | .kb-steam-now-playing > .game-img { 327 | width: 100%; 328 | height: auto; 329 | } 330 | 331 | .kb-steam-multi { 332 | width: 100%; 333 | display: flex; 334 | align-items: center; 335 | justify-content: space-between; 336 | margin: 0 0 8px; 337 | position: relative; 338 | overflow: hidden; 339 | } 340 | 341 | .kb-steam-multi .kb-steam-user { 342 | display: flex; 343 | align-items: center; 344 | } 345 | 346 | .kb-steam-multi .kb-steam-avatar { 347 | margin: 0 16px 0 0; 348 | } 349 | 350 | .kb-steam-multi::before { 351 | z-index: 1; 352 | position: absolute; 353 | bottom: 0; 354 | left: 2em; 355 | width: 1em; 356 | height: 1em; 357 | border-radius: 50%; 358 | background: #646464; 359 | background-image: radial-gradient(top, #616161 0%, #616161 20%, #535353 60%); 360 | content: ''; 361 | z-index: 3; 362 | } 363 | 364 | .kb-steam-multi.online::before, 365 | .kb-steam-multi.snooze::before { 366 | box-shadow: 0 0 1em #1c1c17, 0 0 1em #ff4242; 367 | background: #ff4f4f; 368 | } 369 | 370 | .kb-last { 371 | margin-bottom: 0; 372 | } 373 | `}};var ot; 374 | /** 375 | @license 376 | Copyright (c) 2019 The Polymer Project Authors. All rights reserved. 377 | This code may only be used under the BSD style license found at 378 | http://polymer.github.io/LICENSE.txt The complete set of authors may be found at 379 | http://polymer.github.io/AUTHORS.txt The complete set of contributors may be 380 | found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as 381 | part of the polymer project is also subject to an additional IP rights grant 382 | found at http://polymer.github.io/PATENTS.txt 383 | */at=function(t,e,s,i){var n,r=arguments.length,a=r<3?e:null===i?i=Object.getOwnPropertyDescriptor(e,s):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)a=Reflect.decorate(t,e,s,i);else for(var o=t.length-1;o>=0;o--)(n=t[o])&&(a=(r<3?n(a):r>3?n(e,s,a):n(e,s))||a);return r>3&&a&&Object.defineProperty(e,s,a),a}([(ot="kb-steam-card",t=>"function"==typeof t?((t,e)=>(window.customElements.define(t,e),e))(ot,t):((t,e)=>{const{kind:s,elements:i}=e;return{kind:s,elements:i,finisher(e){window.customElements.define(t,e)}}})(ot,t))],at); 384 | --------------------------------------------------------------------------------