Compare commits
10 commits
ab4c7aa005
...
7de32bd704
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7de32bd704 | ||
|
|
360d9ebb50 | ||
|
|
a681d78c86 | ||
|
|
731fa830e8 | ||
|
|
77849b518e | ||
|
|
679226eb4d | ||
|
|
91b3473f4b | ||
|
|
b0d1f29a83 | ||
|
|
3ddb5b69e6 | ||
|
|
14412ea138 |
76
COMMITLINT.md
Normal file
76
COMMITLINT.md
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
# Commit Messages Format
|
||||||
|
|
||||||
|
This project uses the (conventional commit specification)[https://www.conventionalcommits.org/en/v1.0.0/#specification] for consistent commit messages.
|
||||||
|
|
||||||
|
All commit messages should have the following form:
|
||||||
|
|
||||||
|
```
|
||||||
|
<type>: <description>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Fix
|
||||||
|
|
||||||
|
A fix (PATCH in semantic versioning) looks like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
fix: correct minor typos in code
|
||||||
|
```
|
||||||
|
|
||||||
|
## Feature
|
||||||
|
|
||||||
|
A new feature (MINOR in semantic versioning) looks like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
feat: add catalan language
|
||||||
|
```
|
||||||
|
|
||||||
|
## Breaking Change
|
||||||
|
|
||||||
|
Breaking changes can be indicated by either appending a "!" to the type:
|
||||||
|
|
||||||
|
```
|
||||||
|
refactor!: drop support for Node 6
|
||||||
|
```
|
||||||
|
|
||||||
|
Or adding "BREAKING CHANGE" to the commit message body text:
|
||||||
|
|
||||||
|
```
|
||||||
|
refactor!: drop support for Node 6
|
||||||
|
|
||||||
|
BREAKING CHANGE: refactor to use JavaScript features not available in Node 6.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Available Types
|
||||||
|
|
||||||
|
In addition to "fix" and "feat" the following types are allowed:
|
||||||
|
build:, chore:, ci:, docs:, style:, refactor:, perf:, test:
|
||||||
|
|
||||||
|
Install commitlint:
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install --save-dev @commitlint/{config-conventional,cli}
|
||||||
|
```
|
||||||
|
|
||||||
|
or via yarn:
|
||||||
|
|
||||||
|
```
|
||||||
|
yarn add @commitlint/{config-conventional,cli}
|
||||||
|
```
|
||||||
|
|
||||||
|
Create a commitlint.config.js file:
|
||||||
|
|
||||||
|
```
|
||||||
|
echo "module.exports = {extends: ['@commitlint/config-conventional']}" > commitlint.config.js
|
||||||
|
```
|
||||||
|
|
||||||
|
Add husky to package.json:
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"husky": {
|
||||||
|
"hooks": {
|
||||||
|
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
21
LICENSE
Normal file
21
LICENSE
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2021 Nicola Zambello
|
||||||
|
|
||||||
|
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.
|
||||||
56
README.md
Normal file
56
README.md
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
# Walk-up alarm
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Alarm clock ringing until you walk out of the bed.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
See it in action:
|
||||||
|
<a href="https://nzambello.github.io/walk-up-alarm/" target="_blank" rel="noopener noreferrer">
|
||||||
|
nzambello.github.io/walk-up-alarm
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<p>It's a <a href="https://en.wikipedia.org/wiki/Progressive_web_application" target="_blank" rel="noopener noreferrer">PWA</a>. Install it on your device!</p>
|
||||||
|
<br />
|
||||||
|
<a href="https://nzambello.github.io/walk-up-alarm/" target="_blank" rel="noopener noreferrer">
|
||||||
|
<img src="./public/walk-up-alarm.svg" width="200" alt="Walk-up logo" />
|
||||||
|
</a>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
## Screenshots
|
||||||
|
|
||||||
|
<p float="left">
|
||||||
|
<img src="./screenshots/start.png" title="Start page" height="450" />
|
||||||
|
<img src="./screenshots/clock-alarm-set.png" title="Alarm set, show clock" height="450" />
|
||||||
|
<img src="./screenshots/alarm-playing.png" title="Alarm playing" height="450" />
|
||||||
|
</p>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run the app
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn dev
|
||||||
|
```
|
||||||
|
|
||||||
|
### Build the app
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn build
|
||||||
|
yarn preview
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run tests
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn test
|
||||||
|
```
|
||||||
|
|
||||||
|
## Contributions
|
||||||
|
|
||||||
|
Please follow our [convention](COMMITLINT.md) on commits format.
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
<meta name="description" content="Alarm clock deactivating after walking">
|
<meta name="description" content="Alarm clock deactivating after walking">
|
||||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png" sizes="180x180">
|
<link rel="apple-touch-icon" href="/apple-touch-icon.png" sizes="180x180">
|
||||||
<link rel="mask-icon" href="/favicon.svg" color="#FFFFFF">
|
<link rel="mask-icon" href="/favicon.svg" color="#FFFFFF">
|
||||||
<meta name="theme-color" content="#2979FF">
|
<meta name="theme-color" content="#3E3D42">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
"geolib": "^3.3.3",
|
"geolib": "^3.3.3",
|
||||||
"react": "^17.0.0",
|
"react": "^17.0.0",
|
||||||
"react-dom": "^17.0.0",
|
"react-dom": "^17.0.0",
|
||||||
|
"react-helmet": "^6.1.0",
|
||||||
"ui-neumorphism": "^1.1.3",
|
"ui-neumorphism": "^1.1.3",
|
||||||
"use-position": "^1.0.0",
|
"use-position": "^1.0.0",
|
||||||
"use-stay-awake": "^0.1.7"
|
"use-stay-awake": "^0.1.7"
|
||||||
|
|
@ -28,6 +29,7 @@
|
||||||
"@release-it/conventional-changelog": "^3.3.0",
|
"@release-it/conventional-changelog": "^3.3.0",
|
||||||
"@types/react": "^17.0.0",
|
"@types/react": "^17.0.0",
|
||||||
"@types/react-dom": "^17.0.0",
|
"@types/react-dom": "^17.0.0",
|
||||||
|
"@types/react-helmet": "^6.1.4",
|
||||||
"@types/use-position": "^0.0.0",
|
"@types/use-position": "^0.0.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.7.0",
|
"@typescript-eslint/eslint-plugin": "^5.7.0",
|
||||||
"@typescript-eslint/parser": "^5.7.0",
|
"@typescript-eslint/parser": "^5.7.0",
|
||||||
|
|
|
||||||
BIN
public/pwa-192x192.png
Normal file
BIN
public/pwa-192x192.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3 KiB |
BIN
public/pwa-512x512.png
Normal file
BIN
public/pwa-512x512.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.7 KiB |
|
|
@ -1,19 +0,0 @@
|
||||||
{
|
|
||||||
"name": "",
|
|
||||||
"short_name": "",
|
|
||||||
"icons": [
|
|
||||||
{
|
|
||||||
"src": "/android-chrome-192x192.png",
|
|
||||||
"sizes": "192x192",
|
|
||||||
"type": "image/png"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"src": "/android-chrome-512x512.png",
|
|
||||||
"sizes": "512x512",
|
|
||||||
"type": "image/png"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"theme_color": "#ffffff",
|
|
||||||
"background_color": "#ffffff",
|
|
||||||
"display": "standalone"
|
|
||||||
}
|
|
||||||
BIN
screenshots/alarm-playing.png
Normal file
BIN
screenshots/alarm-playing.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 94 KiB |
BIN
screenshots/clock-alarm-set.png
Normal file
BIN
screenshots/clock-alarm-set.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 84 KiB |
BIN
screenshots/start.png
Normal file
BIN
screenshots/start.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 191 KiB |
53
src/App.tsx
53
src/App.tsx
|
|
@ -1,7 +1,15 @@
|
||||||
import { useCallback, useState, useRef, useEffect } from "react";
|
import { useCallback, useState, useRef, useEffect } from "react";
|
||||||
import { usePosition } from "use-position";
|
import { usePosition } from "use-position";
|
||||||
import { getDistance } from "geolib";
|
import { getDistance } from "geolib";
|
||||||
import { format, parse, differenceInMilliseconds, isMatch } from "date-fns";
|
import {
|
||||||
|
format,
|
||||||
|
parse,
|
||||||
|
differenceInMilliseconds,
|
||||||
|
isMatch,
|
||||||
|
isPast,
|
||||||
|
add,
|
||||||
|
} from "date-fns";
|
||||||
|
import Helmet from "react-helmet";
|
||||||
import useStayAwake from "use-stay-awake";
|
import useStayAwake from "use-stay-awake";
|
||||||
|
|
||||||
import { TextField, Button, Dialog, Card } from "ui-neumorphism";
|
import { TextField, Button, Dialog, Card } from "ui-neumorphism";
|
||||||
|
|
@ -64,7 +72,6 @@ function App() {
|
||||||
resetAlarm();
|
resetAlarm();
|
||||||
} else if (alarmSet) {
|
} else if (alarmSet) {
|
||||||
setHasWalked(false);
|
setHasWalked(false);
|
||||||
audioRef.current?.play();
|
|
||||||
}
|
}
|
||||||
}, [distance, alarmSet]);
|
}, [distance, alarmSet]);
|
||||||
|
|
||||||
|
|
@ -134,10 +141,30 @@ function App() {
|
||||||
return () => clearInterval(interval);
|
return () => clearInterval(interval);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const getThemeColor = (appState: string) => {
|
||||||
|
switch (appState) {
|
||||||
|
case "alarm-playing":
|
||||||
|
return "coral";
|
||||||
|
case "alarm-set":
|
||||||
|
return "#000";
|
||||||
|
case "has-walked":
|
||||||
|
return "teal";
|
||||||
|
default:
|
||||||
|
return "#3E3D42";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const [showResetModal, setResetModal] = useState(false);
|
const [showResetModal, setResetModal] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`App theme--dark ${appState}`}>
|
<div className={`App theme--dark ${appState}`}>
|
||||||
|
<Helmet>
|
||||||
|
<meta name="theme-color" content={getThemeColor(appState)} />
|
||||||
|
<meta
|
||||||
|
name="msapplication-TileColor"
|
||||||
|
content={getThemeColor(appState)}
|
||||||
|
/>
|
||||||
|
</Helmet>
|
||||||
<div className="App-header">
|
<div className="App-header">
|
||||||
{alarmSet && alarm ? (
|
{alarmSet && alarm ? (
|
||||||
<p>
|
<p>
|
||||||
|
|
@ -150,22 +177,6 @@ function App() {
|
||||||
<h1>Walk-up alarm</h1>
|
<h1>Walk-up alarm</h1>
|
||||||
<div className="input-wrapper">
|
<div className="input-wrapper">
|
||||||
<label htmlFor="alarm-time">Set time for the alarm</label>
|
<label htmlFor="alarm-time">Set time for the alarm</label>
|
||||||
{/* <TimeField
|
|
||||||
input={
|
|
||||||
<TextField
|
|
||||||
dark
|
|
||||||
rounded
|
|
||||||
id="alarm-time"
|
|
||||||
className="time-picker"
|
|
||||||
placeholder="08:00"
|
|
||||||
uncontrolled
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
value={alarm ? format(alarm, "HH:mm") : undefined}
|
|
||||||
onChange={(e) => {
|
|
||||||
setAlarm(parse(e.target.value, "HH:mm", new Date()));
|
|
||||||
}}
|
|
||||||
/> */}
|
|
||||||
<TextField
|
<TextField
|
||||||
dark
|
dark
|
||||||
rounded
|
rounded
|
||||||
|
|
@ -174,9 +185,11 @@ function App() {
|
||||||
placeholder="08:00"
|
placeholder="08:00"
|
||||||
value={alarm ? format(alarm, "HH:mm") : undefined}
|
value={alarm ? format(alarm, "HH:mm") : undefined}
|
||||||
onChange={({ value }: { value: string }) => {
|
onChange={({ value }: { value: string }) => {
|
||||||
console.log(value);
|
|
||||||
if (isMatch(value, "HH:mm") || isMatch(value, "H:mm")) {
|
if (isMatch(value, "HH:mm") || isMatch(value, "H:mm")) {
|
||||||
setAlarm(parse(value, "HH:mm", new Date()));
|
const parsedValue = parse(value, "HH:mm", new Date());
|
||||||
|
if (isPast(parsedValue))
|
||||||
|
setAlarm(add(parsedValue, { days: 1 }));
|
||||||
|
else setAlarm(parsedValue);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,42 @@
|
||||||
import { defineConfig } from "vite";
|
import { defineConfig } from "vite";
|
||||||
import react from "@vitejs/plugin-react";
|
import react from "@vitejs/plugin-react";
|
||||||
import { VitePWA } from "vite-plugin-pwa";
|
import { VitePWA, VitePWAOptions } from "vite-plugin-pwa";
|
||||||
|
|
||||||
|
const pwaOptions: Partial<VitePWAOptions> = {
|
||||||
|
registerType: "autoUpdate",
|
||||||
|
includeAssets: [
|
||||||
|
"favicon.svg",
|
||||||
|
"favicon.ico",
|
||||||
|
"robots.txt",
|
||||||
|
"apple-touch-icon.png",
|
||||||
|
],
|
||||||
|
manifest: {
|
||||||
|
name: "Walk-up alarm",
|
||||||
|
short_name: "Walk-up",
|
||||||
|
theme_color: "#3E3D42",
|
||||||
|
icons: [
|
||||||
|
{
|
||||||
|
src: "pwa-192x192.png",
|
||||||
|
sizes: "192x192",
|
||||||
|
type: "image/png",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: "pwa-512x512.png",
|
||||||
|
sizes: "512x512",
|
||||||
|
type: "image/png",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: "pwa-512x512.png",
|
||||||
|
sizes: "512x512",
|
||||||
|
type: "image/png",
|
||||||
|
purpose: "any maskable",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
base: "/walk-up-alarm/",
|
base: "/walk-up-alarm/",
|
||||||
plugins: [
|
plugins: [react(), VitePWA(pwaOptions)],
|
||||||
react(),
|
|
||||||
VitePWA({
|
|
||||||
registerType: "autoUpdate",
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
27
yarn.lock
27
yarn.lock
|
|
@ -1413,6 +1413,13 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/react" "*"
|
"@types/react" "*"
|
||||||
|
|
||||||
|
"@types/react-helmet@^6.1.4":
|
||||||
|
version "6.1.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/react-helmet/-/react-helmet-6.1.4.tgz#3e54a3eb37ba7fb34ffafc64f425be4e68df03b9"
|
||||||
|
integrity sha512-jyx50RNZXVaTGHY3MsoRPNpeiVk8b0XTPgD/O6KHF6COTDnG/+lRjPYvTK5nfWtR3xDOux0w6bHLAsaHo2ZLTA==
|
||||||
|
dependencies:
|
||||||
|
"@types/react" "*"
|
||||||
|
|
||||||
"@types/react@*", "@types/react@^17.0.0":
|
"@types/react@*", "@types/react@^17.0.0":
|
||||||
version "17.0.37"
|
version "17.0.37"
|
||||||
resolved "https://registry.npmjs.org/@types/react/-/react-17.0.37.tgz"
|
resolved "https://registry.npmjs.org/@types/react/-/react-17.0.37.tgz"
|
||||||
|
|
@ -4666,6 +4673,21 @@ react-dom@^17.0.0:
|
||||||
object-assign "^4.1.1"
|
object-assign "^4.1.1"
|
||||||
scheduler "^0.20.2"
|
scheduler "^0.20.2"
|
||||||
|
|
||||||
|
react-fast-compare@^3.1.1:
|
||||||
|
version "3.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb"
|
||||||
|
integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==
|
||||||
|
|
||||||
|
react-helmet@^6.1.0:
|
||||||
|
version "6.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-helmet/-/react-helmet-6.1.0.tgz#a750d5165cb13cf213e44747502652e794468726"
|
||||||
|
integrity sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw==
|
||||||
|
dependencies:
|
||||||
|
object-assign "^4.1.1"
|
||||||
|
prop-types "^15.7.2"
|
||||||
|
react-fast-compare "^3.1.1"
|
||||||
|
react-side-effect "^2.1.0"
|
||||||
|
|
||||||
react-is@^16.8.1:
|
react-is@^16.8.1:
|
||||||
version "16.13.1"
|
version "16.13.1"
|
||||||
resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
|
resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
|
||||||
|
|
@ -4676,6 +4698,11 @@ react-refresh@^0.11.0:
|
||||||
resolved "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz"
|
resolved "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz"
|
||||||
integrity sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==
|
integrity sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==
|
||||||
|
|
||||||
|
react-side-effect@^2.1.0:
|
||||||
|
version "2.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-side-effect/-/react-side-effect-2.1.1.tgz#66c5701c3e7560ab4822a4ee2742dee215d72eb3"
|
||||||
|
integrity sha512-2FoTQzRNTncBVtnzxFOk2mCpcfxQpenBMbk5kSVBg5UcPqV9fRbgY2zhb7GTWWOlpFmAxhClBDlIq8Rsubz1yQ==
|
||||||
|
|
||||||
react-transition-group@^4.4.1:
|
react-transition-group@^4.4.1:
|
||||||
version "4.4.2"
|
version "4.4.2"
|
||||||
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.2.tgz#8b59a56f09ced7b55cbd53c36768b922890d5470"
|
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.2.tgz#8b59a56f09ced7b55cbd53c36768b922890d5470"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue