Create repository

This commit is contained in:
Julien Lengrand-Lambert
2021-02-22 16:56:40 +01:00
commit 693259b561
61 changed files with 392864 additions and 0 deletions

120
.gitignore vendored Normal file
View File

@@ -0,0 +1,120 @@
.DS_Store
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
openwc-epaper/

0
README.md Normal file
View File

40
dashboard.sh Normal file
View File

@@ -0,0 +1,40 @@
#!/bin/sh
SERVICE_NAME=dashboard
PATH_TO_INDEX=index.js
PID_PATH_NAME=/tmp/dashboard.pid
case $1 in
start)
echo "Starting $SERVICE_NAME ..."
if [ ! -f $PID_PATH_NAME ]; then
/usr/local/bin/node $PATH_TO_INDEX
echo "$SERVICE_NAME started ..."
else
echo "$SERVICE_NAME is already running ..."
fi
;;
stop)
if [ -f $PID_PATH_NAME ]; then
PID=$(cat $PID_PATH_NAME);
echo "$SERVICE_NAME stopping ..."
kill $PID;
echo "$SERVICE_NAME stopped ..."
rm $PID_PATH_NAME
else
echo "$SERVICE_NAME is not running ..."
fi
;;
restart)
if [ -f $PID_PATH_NAME ]; then
PID=$(cat $PID_PATH_NAME);
echo "$SERVICE_NAME stopping ...";
kill $PID;
echo "$SERVICE_NAME stopped ...";
rm $PID_PATH_NAME
echo "$SERVICE_NAME starting ..."
/usr/local/bin/node $PATH_TO_INDEX
echo "$SERVICE_NAME started ..."
else
echo "$SERVICE_NAME is not running ..."
fi ;;
esac

29
epaper-ui/.editorconfig Normal file
View File

@@ -0,0 +1,29 @@
# EditorConfig helps developers define and maintain consistent
# coding styles between different editors and IDEs
# editorconfig.org
root = true
[*]
# Change these settings to your own preference
indent_style = space
indent_size = 2
# We recommend you to keep these unchanged
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
[*.json]
indent_size = 2
[*.{html,js,md}]
block_comment_start = /**
block_comment = *
block_comment_end = */

23
epaper-ui/.gitignore vendored Normal file
View File

@@ -0,0 +1,23 @@
## editors
/.idea
/.vscode
## system files
.DS_Store
## npm
/node_modules/
/npm-debug.log
## testing
/coverage/
## temp folders
/.tmp/
# build
/_site/
/dist/
/out-tsc/
storybook-static

21
epaper-ui/LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 paper-dashboard
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

30
epaper-ui/README.OW.md Normal file
View File

@@ -0,0 +1,30 @@
<p align="center">
<img width="200" src="https://open-wc.org/hero.png"></img>
</p>
## Open-wc Starter App
[![Built with open-wc recommendations](https://img.shields.io/badge/built%20with-open--wc-blue.svg)](https://github.com/open-wc)
## Quickstart
To get started:
```sh
npm init @open-wc
# requires node 10 & npm 6 or higher
```
## Scripts
- `start` runs your app for development, reloading on file changes
- `start:build` runs your app after it has been built using the build command
- `build` builds your app and outputs it in your `dist` directory
- `test` runs your test suite with Web Test Runner
- `lint` runs the linter for your project
## Tooling configs
For most of the tools, the configuration is in the `package.json` to reduce the amount of files in your project.
If you customize the configuration a lot, you can consider moving them to individual files.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1 @@
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="bolt" class="svg-inline--fa fa-bolt fa-w-10" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path fill="currentColor" d="M296 160H180.6l42.6-129.8C227.2 15 215.7 0 200 0H56C44 0 33.8 8.9 32.2 20.8l-32 240C-1.7 275.2 9.5 288 24 288h118.7L96.6 482.5c-3.6 15.2 8 29.5 23.3 29.5 8.4 0 16.4-4.4 20.8-12l176-304c9.3-15.9-2.2-36-20.7-36z"></path></svg>

After

Width:  |  Height:  |  Size: 437 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -0,0 +1 @@
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="fire-alt" class="svg-inline--fa fa-fire-alt fa-w-14" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M323.56 51.2c-20.8 19.3-39.58 39.59-56.22 59.97C240.08 73.62 206.28 35.53 168 0 69.74 91.17 0 209.96 0 281.6 0 408.85 100.29 512 224 512s224-103.15 224-230.4c0-53.27-51.98-163.14-124.44-230.4zm-19.47 340.65C282.43 407.01 255.72 416 226.86 416 154.71 416 96 368.26 96 290.75c0-38.61 24.31-72.63 72.79-130.75 6.93 7.98 98.83 125.34 98.83 125.34l58.63-66.88c4.14 6.85 7.91 13.55 11.27 19.97 27.35 52.19 15.81 118.97-33.43 153.42z"></path></svg>

After

Width:  |  Height:  |  Size: 662 B

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="tint" class="svg-inline--fa fa-tint fa-w-11" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 352 512"><path fill="currentColor" d="M205.22 22.09c-7.94-28.78-49.44-30.12-58.44 0C100.01 179.85 0 222.72 0 333.91 0 432.35 78.72 512 176 512s176-79.65 176-178.09c0-111.75-99.79-153.34-146.78-311.82zM176 448c-61.75 0-112-50.25-112-112 0-8.84 7.16-16 16-16s16 7.16 16 16c0 44.11 35.89 80 80 80 8.84 0 16 7.16 16 16s-7.16 16-16 16z"></path></svg>

After

Width:  |  Height:  |  Size: 520 B

View File

@@ -0,0 +1 @@
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="weight" class="svg-inline--fa fa-weight fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M448 64h-25.98C438.44 92.28 448 125.01 448 160c0 105.87-86.13 192-192 192S64 265.87 64 160c0-34.99 9.56-67.72 25.98-96H64C28.71 64 0 92.71 0 128v320c0 35.29 28.71 64 64 64h384c35.29 0 64-28.71 64-64V128c0-35.29-28.71-64-64-64zM256 320c88.37 0 160-71.63 160-160S344.37 0 256 0 96 71.63 96 160s71.63 160 160 160zm-.3-151.94l33.58-78.36c3.5-8.17 12.94-11.92 21.03-8.41 8.12 3.48 11.88 12.89 8.41 21l-33.67 78.55C291.73 188 296 197.45 296 208c0 22.09-17.91 40-40 40s-40-17.91-40-40c0-21.98 17.76-39.77 39.7-39.94z"></path></svg>

After

Width:  |  Height:  |  Size: 741 B

View File

@@ -0,0 +1,26 @@
{
"version": 2,
"tags": [
{
"name": "paper-dashboard",
"description": "An application with a title and an action counter",
"properties": [
{
"name": "title",
"type": "String",
"description": "The title of your application",
"default": "Hey there"
},
{
"name": "page",
"type": "String",
"description": "Which page to show",
"default": "main"
}
],
"events": [],
"slots": [],
"cssProperties": []
}
]
}

29
epaper-ui/index.html Normal file
View File

@@ -0,0 +1,29 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="refresh" content="60"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
<meta name="Description" content="A simple paper dashboard">
<link rel="shortcut icon" href="assets/favicon.ico" />
<link href="assets/tailwind-final.css" rel="stylesheet">
<base href="/">
<title>paper-dashboard</title>
</head>
<body>
<paper-dashboard></paper-dashboard>
<script type="module" src="./out-tsc/src/PaperDashboard.js"></script>
<script>
const ws = new WebSocket('ws://localhost:8080');
ws.addEventListener('open', () => {
setTimeout(() => ws.send('render'), 10000);
setInterval( () => {ws.send('render')}, 300000);
});
</script>
</body>
</html>

21358
epaper-ui/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

87
epaper-ui/package.json Normal file
View File

@@ -0,0 +1,87 @@
{
"devDependencies": {
"@open-wc/building-rollup": "^1.0.0",
"@open-wc/eslint-config": "^4.2.0",
"@open-wc/testing": "^2.0.0",
"@typescript-eslint/eslint-plugin": "^2.20.0",
"@typescript-eslint/parser": "^2.20.0",
"@web/dev-server": "^0.1.1",
"@web/test-runner": "^0.11.5",
"autoprefixer": "^10.2.1",
"concurrently": "^5.3.0",
"deepmerge": "^4.2.2",
"eslint": "^6.1.0",
"eslint-config-prettier": "^6.11.0",
"husky": "^1.0.0",
"lint-staged": "^10.0.0",
"postcss": "^8.2.4",
"prettier": "^2.0.4",
"rimraf": "^2.6.3",
"rollup": "^2.3.4",
"rollup-plugin-copy": "^3.3.0",
"tailwindcss": "^2.0.2",
"tailwindcss-cli": "^0.1.2",
"tslib": "^2.0.3",
"typescript": "^4.1.3"
},
"scripts": {
"lint": "eslint --ext .ts,.html . --ignore-path .gitignore && prettier \"**/*.ts\" --check --ignore-path .gitignore",
"format": "eslint --ext .ts,.html . --fix --ignore-path .gitignore && prettier \"**/*.ts\" --write --ignore-path .gitignore",
"test": "tsc && wtr --coverage",
"test:watch": "tsc && concurrently -k -r \"tsc --watch --preserveWatchOutput\" \"wtr --watch\"",
"build": "rimraf dist && tsc && rollup -c rollup.config.js",
"start:build": "npm run build && web-dev-server --root-dir dist --app-index index.html --open --compatibility none",
"start": "tsc && concurrently -k -r \"tsc --watch --preserveWatchOutput\" \"wds\"",
"css": "npx tailwindcss-cli@latest build ./tailwind.css -o assets/tailwind-final.css",
"dist": "rm -rf ../static/*; cp -rf dist/* ../static/"
},
"name": "paper-dashboard",
"version": "0.0.0",
"description": "Webcomponent paper-dashboard following open-wc recommendations",
"author": "paper-dashboard",
"license": "MIT",
"dependencies": {
"lit-element": "^2.0.1",
"lit-html": "^1.0.0"
},
"eslintConfig": {
"parser": "@typescript-eslint/parser",
"extends": [
"@open-wc/eslint-config",
"eslint-config-prettier"
],
"plugins": [
"@typescript-eslint"
],
"rules": {
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": [
"error"
],
"import/no-unresolved": "off",
"import/extensions": [
"error",
"always",
{
"ignorePackages": true
}
]
}
},
"prettier": {
"singleQuote": true,
"arrowParens": "avoid"
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"*.ts": [
"eslint --fix",
"prettier --write",
"git add"
]
}
}

View File

@@ -0,0 +1,39 @@
import merge from 'deepmerge';
// use createSpaConfig for bundling a Single Page App
import { createSpaConfig } from '@open-wc/building-rollup';
import copy from 'rollup-plugin-copy';
// use createBasicConfig to do regular JS to JS bundling
// import { createBasicConfig } from '@open-wc/building-rollup';
const baseConfig = createSpaConfig({
// use the outputdir option to modify where files are output
// outputDir: 'dist',
// if you need to support older browsers, such as IE11, set the legacyBuild
// option to generate an additional build just for this browser
// legacyBuild: true,
// development mode creates a non-minified build for debugging or development
developmentMode: process.env.ROLLUP_WATCH === 'true',
// set to true to inject the service worker registration into your index.html
injectServiceWorker: false,
});
export default merge(baseConfig, {
// if you use createSpaConfig, you can use your index.html as entrypoint,
// any <script type="module"> inside will be bundled by rollup
input: './index.html',
// alternatively, you can use your JS as entrypoint for rollup and
// optionally set a HTML template manually
// input: './app.js',
plugins: [
copy({
targets: [{ src: 'assets/**/*', dest: 'dist/assets' }],
// set flatten to false to preserve folder structure
flatten: false,
}),
],
});

View File

@@ -0,0 +1,51 @@
import {until} from 'lit-html/directives/until';
import { html } from 'lit-element';
import { YoloLitElement } from './YoloLitElement.js';
import { NetworkMixin } from './NetworkMixin.js';
const calendar = "https://docs.google.com/spreadsheets/d/e/2PACX-1vTPX3UqKW4tMPhj6M18f-6cR73IkIpMblbK3i2sodtFCoRNkDwAbhvFaU4PgBPBE1krJmy11dw1EzyT/pub?gid=0&single=true&output=csv"
const monthNames = ["January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"];
interface CalendarEvent{
when: string;
what: string;
where: string;
}
export class CalendarData extends NetworkMixin(YoloLitElement) {
async getEvents() {
const result = await this.httpText(calendar);
const eventsAsArray = result.split(/\r?\n/).map(l => l.split(','));
const events = eventsAsArray.map(e => { return {when: e[0], what: e[1], where: e[2]}});
return events.slice(0, 7);
}
render() {
return html`
${until(this.getEvents().then( events => html`
<div class="ml-4 h-full flex flex-col justify-around">
${events.map( (event : CalendarEvent) =>
html`
<div class="flex">
<div class="w-1/3 text-base font-extrabold">
${(new Date(event.when)).getDate()} ${monthNames[(new Date(event.when)).getMonth()].slice(0,1)}. ${(new Date(event.when)).getHours()}:${(new Date(event.when)).getMinutes()<10?'0':''}${(new Date(event.when)).getMinutes()}
</div>
<div class="w-2/3 text-base font-bold">${event.what}</div>
</div>`
)}
</div>
`
))}
`;
}
}
customElements.define('calendar-events', CalendarData);

25
epaper-ui/src/DateInfo.ts Normal file
View File

@@ -0,0 +1,25 @@
import { html } from 'lit-element';
import { YoloLitElement } from './YoloLitElement.js';
const monthNames = ["January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"];
export class DateInfo extends YoloLitElement {
render() {
const now = new Date();
return html`
<div class="h-full flex flex-col">
<div class="h-3/5 font-bold text-4xl text-center flex items-center justify-center">
${now.getHours()}:${now.getMinutes()<10?'0':''}${now.getMinutes()}
</div>
<div class="h-2/5 flex font-bold justify-center">
${now.getDate()} ${monthNames[now.getMonth()]}
</div>
</div>
`;
}
}
customElements.define('date-info', DateInfo);

View File

@@ -0,0 +1,61 @@
import {until} from 'lit-html/directives/until';
import { html } from 'lit-element';
import { YoloLitElement } from './YoloLitElement.js';
import { NetworkMixin } from './NetworkMixin.js';
const energySheet = "https://docs.google.com/spreadsheets/d/e/2PACX-1vTo1q9NO4daxpvY77c1UGTgAai9LIEsf5QmCPU13IatzIzx5a68Jr5EL8MUzKpDob55Qo1vy5CkQpYE/pub?gid=1686054259&single=true&output=csv";
interface EnergyInfoData{
lastMeasurement: number;
previsionkWh: string;
previsionGJ: string;
previsionm3: string;
trendkWh: string;
trendGJ: string;
trendm3: string;
}
export class EnergyInfo extends NetworkMixin(YoloLitElement) {
async getEnergy() {
const energyRaw = (await this.httpText(energySheet)).split(',');
const energyInfo = {
lastMeasurement: energyRaw[0],
previsionkWh: parseInt(energyRaw[1], 10),
previsionGJ: parseInt(energyRaw[2], 10),
previsionm3: parseInt(energyRaw[3], 10),
trendkWh: parseInt(energyRaw[4], 10),
trendGJ: parseInt(energyRaw[5], 10),
trendm3: parseInt(energyRaw[6 ], 10),
}
return energyInfo;
}
render() {
return html`
<div class="h-full flex flex justify-around">
${until(this.getEnergy().then( energyInfo => html`
<div class="font-bold text-xl text-center flex items-center justify-center">
<img class="h-8 mr-2" alt="a drop of water" src="assets/bolt-solid.svg">
<p class="" >${energyInfo.trendkWh > 0 ? html`+` : html``} ${energyInfo.trendkWh}%</p>
</div>
<div class="font-bold text-xl text-center flex items-center justify-center">
<img class="h-8 mr-2" alt="a drop of water" src="assets/fire-alt-solid.svg">
<p>${energyInfo.trendGJ > 0 ? html`+` : html``} ${energyInfo.trendGJ}%</p>
</div>
<div class="font-bold text-xl text-center flex items-center justify-center">
<img class="h-8 mr-2" alt="a drop of water" src="assets/tint-solid.svg">
<p>${energyInfo.trendm3 > 0 ? html`+` : html``} ${energyInfo.trendm3}%</p>
</div>
`
))}
</div>
`;
}
}
customElements.define('energy-info', EnergyInfo);

View File

@@ -0,0 +1,22 @@
declare type Constructor<T> = {
new (...args: any[]): T
}
export function NetworkMixin<B extends Constructor<HTMLElement>>(baseClass: B) {
return class extends baseClass {
// eslint-disable-next-line class-methods-use-this
async httpJson<T>(request: RequestInfo): Promise<T> {
const response = await fetch(request);
const body = await response.json();
return body;
}
// eslint-disable-next-line class-methods-use-this
async httpText<T>(request: RequestInfo): Promise<String> {
const response = await fetch(request);
const body = await response.text();
return body;
}
}
}

View File

@@ -0,0 +1,40 @@
import { html, css, property } from 'lit-element';
import { YoloLitElement } from './YoloLitElement.js';
import './DateInfo.js'
import './WeatherData.js';
import './WeeklyMenus.js';
import './EnergyInfo.js';
import './CalendarData.js';
import './WeightInfo.js';
export class PaperDashboard extends YoloLitElement {
@property({ type: String }) title = 'My app';
render() {
return html`
<main class="h-full">
<div class="flex h-1/6">
<date-info class="flex-auto h-full"></date-info>
<weather-data class="flex-auto h-full flex justify-around"></weather-data>
</div>
<div class="flex h-4/6 mt-2 mb-2">
<weekly-menus class="w-1/2 h-full"></weekly-menus>
<div class="h-full flex-grow-0 flex items-center justify-center">
<div class=" h-1/2 border-2 border-black"></div>
</div>
<calendar-events class="w-1/2 h-full flex-auto"></calendar-events>
</div>
<div class="h-1/6 flex items-center justify-center">
<weight-info class="w-1/5"></weight-info>
<energy-info class="w-4/5"></energy-info>
</div>
</main>
`;
}
}
customElements.define('paper-dashboard', PaperDashboard);

View File

@@ -0,0 +1,55 @@
import { html } from 'lit-element';
import {until} from 'lit-html/directives/until';
import { YoloLitElement } from './YoloLitElement.js';
import './WeatherDay.js';
import {NetworkMixin} from './NetworkMixin.js';
const weatherApi = "https://api.openweathermap.org/data/2.5/onecall?exclude=hourly,minutely&lat=52.046680&lon=5.079170&APPID=ee80728351da55e61e612558832978e4"
interface IWeatherResponse {
current: IWeatherPoint;
daily: Array<IWeatherPointDaily>;
}
interface IWeatherPointDaily {
feels_like: IWeatherFeelsLikeDaily;
weather: Array<IWeather>;
}
interface IWeatherFeelsLikeDaily {
day: number
}
interface IWeatherPoint {
feels_like: number;
weather: Array<IWeather>;
}
interface IWeather {
icon : string;
description: string;
}
export class WeatherData extends NetworkMixin(YoloLitElement) {
async getWeather() {
const result = await this.httpJson<IWeatherResponse>(weatherApi);
return result;
}
render() {
const currentDay = (current: IWeatherPoint) => html`<weather-day .temperature=${current.feels_like} .icon=${current.weather[0].icon}></weather-day>`;
const allDays = (days: Array<IWeatherPointDaily>) => html`${days.map((day: IWeatherPointDaily) => html`<weather-day .temperature=${day.feels_like.day} .icon=${day.weather[0].icon}></weather-day>`)}`;
return html`
${until(this.getWeather().then( res => html`
${currentDay(res.current)}
${allDays(res.daily)}
`
))}
`;
}
}
customElements.define('weather-data', WeatherData);

View File

@@ -0,0 +1,25 @@
import { html, css, property } from 'lit-element';
import { YoloLitElement } from './YoloLitElement.js';
const toKelvin = 273.15;
export class WeatherDay extends YoloLitElement {
@property({ type: Number }) temperature = 0.0 ;
@property({ type: String }) icon = "";
static styles = css``;
render() {
return html`
<div class="flex flex-col h-full justify-around">
<p class="font-bold text-center mt-2">${Math.round(this.temperature - toKelvin)}°C</p>
<img style="filter:brightness(0);" src="https://openweathermap.org/img/wn/${this.icon}.png" alt=${this.icon}>
</div>
`;
}
}
customElements.define('weather-day', WeatherDay);

View File

@@ -0,0 +1,48 @@
import {until} from 'lit-html/directives/until';
import { html } from 'lit-element';
import { YoloLitElement } from './YoloLitElement.js';
import { NetworkMixin } from './NetworkMixin.js';
const menusSheet = "https://docs.google.com/spreadsheets/d/e/2PACX-1vTQFqToleR71JZahgIYAcIsieLFd4sugFLsDMUoVHUMLV8UoqUv4QctkO1lzUU_2Eh0ZzaLAbtEUZUH/pub?gid=0&single=true&output=csv";
interface MenuData{
day: string;
lunch: string;
dinner: string;
}
export class WeeklyMenus extends NetworkMixin(YoloLitElement) {
async getMenus() {
const result = await this.httpText(menusSheet);
const menusAsArray = result.split(/\r?\n/).map(l => l.split(','));
const menus = menusAsArray.map(m => { return {day:m[0], lunch: m[1], dinner: m[2]}});
return menus;
}
render() {
return html`
<div class="h-full flex flex-col justify-evenly">
${until(this.getMenus().then( menus => html`
${menus.map( (menu : MenuData) =>
html`<div class="flex">
<div class="ml-4 w-1/3 text-base font-extrabold">${menu.day}</div>
<div class="ml-5 w-2/3">
<div class="text-base font-bold">${menu.lunch}</div>
<div class="text-base font-bold">${menu.dinner}</div>
</div>
</div>
`
)}
`
))}
</div>
`;
}
}
customElements.define('weekly-menus', WeeklyMenus);

View File

@@ -0,0 +1,32 @@
import {until} from 'lit-html/directives/until';
import { html } from 'lit-element';
import { YoloLitElement } from './YoloLitElement.js';
import { NetworkMixin } from './NetworkMixin.js';
const weightSheet = "https://docs.google.com/spreadsheets/d/e/2PACX-1vSdO0GF46JK4LZhxXyuH6HPFtHSHaMmE91yD3WJj1zDHW99K_cL__e9Hnbh_ATvEIQ_D1daxYXXttyC/pub?gid=0&single=true&output=csv";
export class WeightInfo extends NetworkMixin(YoloLitElement) {
async getWeight() {
const weight = await this.httpText(weightSheet);
return weight;
}
render() {
return html`
<div class="h-full flex flex-col justify-around">
${until(this.getWeight().then( weight => html`
<div class="font-bold text-xl text-center flex items-center justify-center">
<img class="h-8 mr-2" alt="a scale" src="assets/weight-solid.svg">
<p>${weight}kg</p>
</div>
`
))}
</div>
`;
}
}
customElements.define('weight-info', WeightInfo);

View File

@@ -0,0 +1,7 @@
import { LitElement } from 'lit-element';
export class YoloLitElement extends LitElement {
createRenderRoot(){
return this;
}
}

View File

@@ -0,0 +1,3 @@
import { PaperDashboard } from './PaperDashboard.js';
customElements.define('paper-dashboard', PaperDashboard);

42
epaper-ui/tailwind.css Normal file
View File

@@ -0,0 +1,42 @@
/* ./tailwind.css */
@tailwind base;
@tailwind components;
@font-face {
font-family: "PFAdamantPro";
src: url("assets/PFAdamantPro.ttf") format("ttf");
}
@font-face {
font-family: "Sabon";
src: url("assets/Sabon_Roman.ttf") format("ttf");
}
@font-face {
font-family: "SourceCodePro";
src: url("assets/SourceCodePro-Regular.ttf") format("ttf");
}
@font-face {
font-family: "JetBrainsMono";
src: url("assets/JetBrainsMono-Regular.ttf") format("ttf");
}
@font-face {
font-family: "Palatino";
src: url("assets/Palatino.ttf") format("ttf");
}
html,body,p,input,textarea,h1,h2, div {
font-family: 'PFAdamantPro';
}
body {
width:800px;
max-width: 800px;
height: 480px;
max-height: 480px;
}
@tailwind utilities;

View File

@@ -0,0 +1,21 @@
import { html, fixture, expect } from '@open-wc/testing';
import { PaperDashboard } from '../src/PaperDashboard.js';
import '../src/paper-dashboard.js';
describe('PaperDashboard', () => {
let element: PaperDashboard;
beforeEach(async () => {
element = await fixture(html`<paper-dashboard></paper-dashboard>`);
});
it('renders a h1', () => {
const h1 = element.shadowRoot!.querySelector('h1')!;
expect(h1).to.exist;
expect(h1.textContent).to.equal('My app');
});
it('passes the a11y audit', async () => {
await expect(element).shadowDom.to.be.accessible();
});
});

19
epaper-ui/tsconfig.json Normal file
View File

@@ -0,0 +1,19 @@
{
"compilerOptions": {
"target": "es2018",
"module": "esnext",
"moduleResolution": "node",
"noEmitOnError": true,
"lib": ["es2017", "dom"],
"strict": true,
"esModuleInterop": false,
"allowSyntheticDefaultImports": true,
"experimentalDecorators": true,
"importHelpers": true,
"outDir": "out-tsc",
"sourceMap": true,
"inlineSources": true,
"rootDir": "./"
},
"include": ["**/*.ts"]
}

View File

@@ -0,0 +1,29 @@
// import { hmrPlugin, presets } from '@open-wc/dev-server-hmr';
/** Use Hot Module replacement by adding --hmr to the start command */
const hmr = process.argv.includes('--hmr');
export default /** @type {import('@web/dev-server').DevServerConfig} */ ({
nodeResolve: true,
open: '/',
watch: !hmr,
port: 8082,
/** Compile JS for older browsers. Requires @web/dev-server-esbuild plugin */
// esbuildTarget: 'auto'
/** Set appIndex to enable SPA routing */
// appIndex: 'demo/index.html',
/** Confgure bare import resolve plugin */
// nodeResolve: {
// exportConditions: ['browser', 'development']
// },
plugins: [
/** Use Hot Module Replacement by uncommenting. Requires @open-wc/dev-server-hmr plugin */
// hmr && hmrPlugin({ exclude: ['**/*/node_modules/**/*'], presets: [presets.litElement] }),
],
// See documentation for all available options
});

View File

@@ -0,0 +1,30 @@
// import { playwrightLauncher } from '@web/test-runner-playwright';
export default /** @type {import("@web/test-runner").TestRunnerConfig} */ ({
files: 'out-tsc/test/**/*.test.js',
nodeResolve: true,
port: 8082,
/** Compile JS for older browsers. Requires @web/dev-server-esbuild plugin */
// esbuildTarget: 'auto',
/** Confgure bare import resolve plugin */
// nodeResolve: {
// exportConditions: ['browser', 'development']
// },
/** Amount of browsers to run concurrently */
// concurrentBrowsers: 2,
/** Amount of test files per browser to test concurrently */
// concurrency: 1,
/** Browsers to run tests on */
// browsers: [
// playwrightLauncher({ product: 'chromium' }),
// playwrightLauncher({ product: 'firefox' }),
// playwrightLauncher({ product: 'webkit' }),
// ],
// See documentation for all available options
});

4
index.js Normal file
View File

@@ -0,0 +1,4 @@
const { init, devices } = require('epaperjs');
init(devices.waveshare7in5v2Horizontal);

3
netlify.toml Normal file
View File

@@ -0,0 +1,3 @@
[build]
publish = "static/"
command = "npm run build"

2625
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

27
package.json Normal file
View File

@@ -0,0 +1,27 @@
{
"name": "epaper-dashboard",
"version": "1.0.0",
"description": "Runner for my epaper dashboard",
"main": "index.js",
"scripts": {
"node-engine": "node -v",
"build": "cd epaper-ui; npm run css; npm run build; npm run dist",
"test": "echo \"Error: no test specified\" && exit 1"
},
"engines": {
"node": ">=10"
},
"repository": {
"type": "git",
"url": "git+https://github.com/jlengrand/epaper-dashboard.git"
},
"author": "Julien Lengrand-Lambert",
"license": "ISC",
"bugs": {
"url": "https://github.com/jlengrand/epaper-dashboard/issues"
},
"homepage": "https://github.com/jlengrand/epaper-dashboard#readme",
"dependencies": {
"epaperjs": "^1.3.3"
}
}

15
service/dashboard.service Normal file
View File

@@ -0,0 +1,15 @@
[Unit]
Description=Epaper dashboard
[Service]
User=pi
WorkingDirectory=/home/pi/epaper-dashboard
ExecStart=/home/pi/epaper-dashboard/dashboard.sh start
ExecStop=/home/pi/epaper-dashboard/dashboard.sh stop
ExecReload=/home/pi/epaper-dashboard/dashboard.sh restart
SuccessExitStatus=143
TimeoutStopSec=10
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target

Binary file not shown.

Binary file not shown.

BIN
static/assets/Palatino.ttf Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1 @@
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="bolt" class="svg-inline--fa fa-bolt fa-w-10" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path fill="currentColor" d="M296 160H180.6l42.6-129.8C227.2 15 215.7 0 200 0H56C44 0 33.8 8.9 32.2 20.8l-32 240C-1.7 275.2 9.5 288 24 288h118.7L96.6 482.5c-3.6 15.2 8 29.5 23.3 29.5 8.4 0 16.4-4.4 20.8-12l176-304c9.3-15.9-2.2-36-20.7-36z"></path></svg>

After

Width:  |  Height:  |  Size: 437 B

BIN
static/assets/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -0,0 +1 @@
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="fire-alt" class="svg-inline--fa fa-fire-alt fa-w-14" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M323.56 51.2c-20.8 19.3-39.58 39.59-56.22 59.97C240.08 73.62 206.28 35.53 168 0 69.74 91.17 0 209.96 0 281.6 0 408.85 100.29 512 224 512s224-103.15 224-230.4c0-53.27-51.98-163.14-124.44-230.4zm-19.47 340.65C282.43 407.01 255.72 416 226.86 416 154.71 416 96 368.26 96 290.75c0-38.61 24.31-72.63 72.79-130.75 6.93 7.98 98.83 125.34 98.83 125.34l58.63-66.88c4.14 6.85 7.91 13.55 11.27 19.97 27.35 52.19 15.81 118.97-33.43 153.42z"></path></svg>

After

Width:  |  Height:  |  Size: 662 B

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="tint" class="svg-inline--fa fa-tint fa-w-11" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 352 512"><path fill="currentColor" d="M205.22 22.09c-7.94-28.78-49.44-30.12-58.44 0C100.01 179.85 0 222.72 0 333.91 0 432.35 78.72 512 176 512s176-79.65 176-178.09c0-111.75-99.79-153.34-146.78-311.82zM176 448c-61.75 0-112-50.25-112-112 0-8.84 7.16-16 16-16s16 7.16 16 16c0 44.11 35.89 80 80 80 8.84 0 16 7.16 16 16s-7.16 16-16 16z"></path></svg>

After

Width:  |  Height:  |  Size: 520 B

View File

@@ -0,0 +1 @@
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="weight" class="svg-inline--fa fa-weight fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M448 64h-25.98C438.44 92.28 448 125.01 448 160c0 105.87-86.13 192-192 192S64 265.87 64 160c0-34.99 9.56-67.72 25.98-96H64C28.71 64 0 92.71 0 128v320c0 35.29 28.71 64 64 64h384c35.29 0 64-28.71 64-64V128c0-35.29-28.71-64-64-64zM256 320c88.37 0 160-71.63 160-160S344.37 0 256 0 96 71.63 96 160s71.63 160 160 160zm-.3-151.94l33.58-78.36c3.5-8.17 12.94-11.92 21.03-8.41 8.12 3.48 11.88 12.89 8.41 21l-33.67 78.55C291.73 188 296 197.45 296 208c0 22.09-17.91 40-40 40s-40-17.91-40-40c0-21.98 17.76-39.77 39.7-39.94z"></path></svg>

After

Width:  |  Height:  |  Size: 741 B

1
static/c0737020.js Normal file

File diff suppressed because one or more lines are too long

1
static/index.html Normal file
View File

@@ -0,0 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="refresh" content="60"><meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover"><meta name="Description" content="A simple paper dashboard"><link rel="shortcut icon" href="assets/favicon.ico"><link href="assets/tailwind-final.css" rel="stylesheet"><base href="/"><title>paper-dashboard</title><link rel="preload" href="./c0737020.js" as="script" crossorigin="anonymous"></head><body><paper-dashboard></paper-dashboard><script>const ws=new WebSocket("ws://localhost:8080");ws.addEventListener("open",()=>{setTimeout(()=>ws.send("render"),1e4),setInterval(()=>{ws.send("render")},3e5)})</script><script type="module" src="./c0737020.js"></script></body></html>

2
static/sw.js Normal file
View File

@@ -0,0 +1,2 @@
if(!self.define){const e=e=>{"require"!==e&&(e+=".js");let r=Promise.resolve();return s[e]||(r=new Promise(async r=>{if("document"in self){const s=document.createElement("script");s.src=e,document.head.appendChild(s),s.onload=r}else importScripts(e),r()})),r.then(()=>{if(!s[e])throw new Error(`Module ${e} didnt register its module`);return s[e]})},r=(r,s)=>{Promise.all(r.map(e)).then(e=>s(1===e.length?e[0]:e))},s={require:Promise.resolve(r)};self.define=(r,t,i)=>{s[r]||(s[r]=Promise.resolve().then(()=>{let s={};const n={uri:location.origin+r.slice(1)};return Promise.all(t.map(r=>{switch(r){case"exports":return s;case"module":return n;default:return e(r)}})).then(e=>{const r=i(...e);return s.default||(s.default=r),s})}))}}define("./sw.js",["./workbox-80efdfd1"],(function(e){"use strict";e.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"c0737020.js",revision:"ba034c33bc1e655c7a3db57ccc558a24"},{url:"index.html",revision:"a63454ad38c319cf08eda926873da204"}],{}),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("/index.html"))),e.registerRoute("polyfills/*.js",new e.CacheFirst,"GET")}));
//# sourceMappingURL=sw.js.map

1
static/sw.js.map Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"sw.js","sources":["../../../../../private/var/folders/0x/xhvbsmgn36z1t2jltptz27yc0000gn/T/9095901c8719ae9cf98d3833b954be97/sw.js"],"sourcesContent":["import {registerRoute as workbox_routing_registerRoute} from '/Users/jlengrand/Developer/epaper-dashboard-blog/epaper-ui/node_modules/workbox-routing/registerRoute.mjs';\nimport {CacheFirst as workbox_strategies_CacheFirst} from '/Users/jlengrand/Developer/epaper-dashboard-blog/epaper-ui/node_modules/workbox-strategies/CacheFirst.mjs';\nimport {skipWaiting as workbox_core_skipWaiting} from '/Users/jlengrand/Developer/epaper-dashboard-blog/epaper-ui/node_modules/workbox-core/skipWaiting.mjs';\nimport {clientsClaim as workbox_core_clientsClaim} from '/Users/jlengrand/Developer/epaper-dashboard-blog/epaper-ui/node_modules/workbox-core/clientsClaim.mjs';\nimport {precacheAndRoute as workbox_precaching_precacheAndRoute} from '/Users/jlengrand/Developer/epaper-dashboard-blog/epaper-ui/node_modules/workbox-precaching/precacheAndRoute.mjs';\nimport {NavigationRoute as workbox_routing_NavigationRoute} from '/Users/jlengrand/Developer/epaper-dashboard-blog/epaper-ui/node_modules/workbox-routing/NavigationRoute.mjs';\nimport {createHandlerBoundToURL as workbox_precaching_createHandlerBoundToURL} from '/Users/jlengrand/Developer/epaper-dashboard-blog/epaper-ui/node_modules/workbox-precaching/createHandlerBoundToURL.mjs';/**\n * Welcome to your Workbox-powered service worker!\n *\n * You'll need to register this file in your web app.\n * See https://goo.gl/nhQhGp\n *\n * The rest of the code is auto-generated. Please don't update this file\n * directly; instead, make changes to your Workbox build configuration\n * and re-run your build process.\n * See https://goo.gl/2aRDsh\n */\n\n\n\n\n\n\n\n\nworkbox_core_skipWaiting();\n\nworkbox_core_clientsClaim();\n\n\n/**\n * The precacheAndRoute() method efficiently caches and responds to\n * requests for URLs in the manifest.\n * See https://goo.gl/S9QRab\n */\nworkbox_precaching_precacheAndRoute([\n {\n \"url\": \"c0737020.js\",\n \"revision\": \"ba034c33bc1e655c7a3db57ccc558a24\"\n },\n {\n \"url\": \"index.html\",\n \"revision\": \"a63454ad38c319cf08eda926873da204\"\n }\n], {});\n\nworkbox_routing_registerRoute(new workbox_routing_NavigationRoute(workbox_precaching_createHandlerBoundToURL(\"/index.html\")));\n\n\nworkbox_routing_registerRoute(\"polyfills/*.js\", new workbox_strategies_CacheFirst(), 'GET');\n\n\n\n\n"],"names":["workbox_routing_NavigationRoute","workbox_precaching_createHandlerBoundToURL","workbox_strategies_CacheFirst"],"mappings":"k1BAmCoC,CAClC,KACS,uBACK,oCAEd,KACS,sBACK,qCAEb,oBAE2B,IAAIA,kBAAgCC,0BAA2C,iCAG/E,iBAAkB,IAAIC,aAAiC"}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long