Merge pull request #9 from eugene-serb/dev

Dev
This commit is contained in:
Eugene Serb 2022-08-09 18:27:07 +03:00 committed by GitHub
commit 064ccc3475
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
73 changed files with 1410 additions and 585 deletions

View File

@ -2,3 +2,4 @@
last 2 versions
not dead
not ie 11

View File

@ -1,18 +1,19 @@
module.exports = {
root: true,
env: {
node: true
node: true,
},
'extends': [
'plugin:vue/vue3-essential',
'eslint:recommended',
'@vue/typescript/recommended'
'@vue/typescript/recommended',
],
parserOptions: {
ecmaVersion: 2020
ecmaVersion: 2020,
},
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off'
}
}
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
},
};

1
.gitignore vendored
View File

@ -353,7 +353,6 @@ MigrationBackup/
node_modules
/dist
# local env files
.env.local
.env.*.local

View File

@ -672,3 +672,4 @@ may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.

View File

@ -1,8 +1,18 @@
# Wavelovers
Wavelovers in ***VueJS***, ***Typescript***, ***Javascript***, ***HTML***, ***CSS*** and ***SCSS*** **[[rep](https://github.com/eugene-serb/wavelovers/), [site](https://wavelovers.ru/)]**.
Wavelovers links: **[[rep](https://github.com/eugene-serb/wavelovers/), [site](https://wavelovers.ru/)]**.
This is Wavelovers, which can make a vibrating massager out of a gamepad. It has 16 free vibration patterns to play with.
This is Wavelovers, a gamepad and gamepad vibration test tool that can also make a vibration massager out of a gamepad. It has 16 free vibration patterns to play with.
Tech Stack:
***Vue.js***, ***Vuex***, ***Vue Router***, ***Typescript***, ***Javascript***, ***HTML***, ***CSS***, ***SCSS***, ***ESLint***, ***Babel***.
Commands:<br />
1. npm install Project setup.<br />
2. npm run serve Compiles and hot-reloads for development.<br />
3. npm run build Compiles and minifies for production.<br />
4. npm run lint Lints and fixes files.<br />
Catalogs structure:<br />
***/docs/*** production build. <br />
***/ (root)*** dev files.

View File

@ -1,5 +1,6 @@
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}
'@vue/cli-plugin-babel/preset',
],
};

View File

@ -672,3 +672,4 @@ may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.

View File

@ -1,8 +1,18 @@
# Wavelovers
Wavelovers in ***VueJS***, ***Typescript***, ***Javascript***, ***HTML***, ***CSS*** and ***SCSS*** **[[rep](https://github.com/eugene-serb/wavelovers/), [site](https://wavelovers.ru/)]**.
Wavelovers links: **[[rep](https://github.com/eugene-serb/wavelovers/), [site](https://wavelovers.ru/)]**.
This is Wavelovers, which can make a vibrating massager out of a gamepad. It has 16 free vibration patterns to play with.
This is Wavelovers, a gamepad and gamepad vibration test tool that can also make a vibration massager out of a gamepad. It has 16 free vibration patterns to play with.
Tech Stack:
***Vue.js***, ***Vuex***, ***Vue Router***, ***Typescript***, ***Javascript***, ***HTML***, ***CSS***, ***SCSS***, ***ESLint***, ***Babel***.
Commands:<br />
1. npm install Project setup.<br />
2. npm run serve Compiles and hot-reloads for development.<br />
3. npm run build Compiles and minifies for production.<br />
4. npm run lint Lints and fixes files.<br />
Catalogs structure:<br />
***/docs/*** production build. <br />
***/ (root)*** dev files.

View File

@ -1,62 +1,121 @@
[
{
"name": "Dotted Weak",
"name": "Constant Weak",
"type": "Simple",
"icon": "😌",
"icon": "😏",
"pattern": [
{
"startDelay": 200,
"duration": 100,
"startDelay": 0,
"duration": 1000,
"weakMagnitude": 1.0,
"strongMagnitude": 0.0
}
]
},
{
"name": "Dotted Strong",
"name": "Constant Strong",
"type": "Simple",
"icon": "😉",
"icon": "🤩",
"pattern": [
{
"startDelay": 200,
"duration": 100,
"startDelay": 0,
"duration": 1000,
"weakMagnitude": 0.0,
"strongMagnitude": 1.0
}
]
},
{
"name": "Dotted AC",
"name": "Constant Max",
"type": "Simple",
"icon": "🤨",
"icon": "😍",
"pattern": [
{
"startDelay": 0,
"duration": 1000,
"weakMagnitude": 1.0,
"strongMagnitude": 1.0
}
]
},
{
"name": "Constant AC",
"type": "Complex",
"icon": "😵",
"pattern": [
{
"startDelay": 0,
"duration": 1000,
"weakMagnitude": 1.0,
"strongMagnitude": 0.0
},
{
"startDelay": 0,
"duration": 1000,
"weakMagnitude": 0.0,
"strongMagnitude": 1.0
}
]
},
{
"name": "Long Dashed Weak",
"type": "Simple",
"icon": "😋",
"pattern": [
{
"startDelay": 200,
"duration": 100,
"duration": 500,
"weakMagnitude": 1.0,
"strongMagnitude": 0.0
}
]
},
{
"name": "Long Dashed Strong",
"type": "Simple",
"icon": "😜",
"pattern": [
{
"startDelay": 100,
"duration": 500,
"weakMagnitude": 0.0,
"strongMagnitude": 1.0
}
]
},
{
"name": "Long Dashed Max",
"type": "Simple",
"icon": "🤪",
"pattern": [
{
"startDelay": 200,
"duration": 500,
"weakMagnitude": 1.0,
"strongMagnitude": 1.0
}
]
},
{
"name": "Long Dashed AC",
"type": "Complex",
"icon": "😝",
"pattern": [
{
"startDelay": 200,
"duration": 500,
"weakMagnitude": 1.0,
"strongMagnitude": 0.0
},
{
"startDelay": 200,
"duration": 100,
"duration": 500,
"weakMagnitude": 0.0,
"strongMagnitude": 1.0
}
]
},
{
"name": "Dotted Max",
"type": "Simple",
"icon": "🙃",
"pattern": [
{
"startDelay": 200,
"duration": 100,
"weakMagnitude": 1.0,
"strongMagnitude": 1.0
}
]
},
{
"name": "Short Dashed Weak",
"type": "Simple",
@ -84,8 +143,21 @@
]
},
{
"name": "Short Dashed AC",
"name": "Short Dashed Max",
"type": "Simple",
"icon": "😊",
"pattern": [
{
"startDelay": 200,
"duration": 250,
"weakMagnitude": 1.0,
"strongMagnitude": 1.0
}
]
},
{
"name": "Short Dashed AC",
"type": "Complex",
"icon": "🤤",
"pattern": [
{
@ -103,132 +175,61 @@
]
},
{
"name": "Short Dashed Max",
"name": "Dotted Weak",
"type": "Simple",
"icon": "😊",
"icon": "😌",
"pattern": [
{
"startDelay": 200,
"duration": 250,
"weakMagnitude": 1.0,
"strongMagnitude": 1.0
}
]
},
{
"name": "Long Dashed Weak",
"type": "Simple",
"icon": "😋",
"pattern": [
{
"startDelay": 200,
"duration": 500,
"duration": 100,
"weakMagnitude": 1.0,
"strongMagnitude": 0.0
}
]
},
{
"name": "Long Dashed Strong",
"name": "Dotted Strong",
"type": "Simple",
"icon": "😜",
"icon": "😉",
"pattern": [
{
"startDelay": 100,
"duration": 500,
"startDelay": 200,
"duration": 100,
"weakMagnitude": 0.0,
"strongMagnitude": 1.0
}
]
},
{
"name": "Long Dashed AC",
"name": "Dotted Max",
"type": "Simple",
"icon": "😝",
"icon": "🙃",
"pattern": [
{
"startDelay": 200,
"duration": 500,
"duration": 100,
"weakMagnitude": 1.0,
"strongMagnitude": 1.0
}
]
},
{
"name": "Dotted AC",
"type": "Complex",
"icon": "🤨",
"pattern": [
{
"startDelay": 200,
"duration": 100,
"weakMagnitude": 1.0,
"strongMagnitude": 0.0
},
{
"startDelay": 200,
"duration": 500,
"duration": 100,
"weakMagnitude": 0.0,
"strongMagnitude": 1.0
}
]
},
{
"name": "Long Dashed Max",
"type": "Simple",
"icon": "🤪",
"pattern": [
{
"startDelay": 200,
"duration": 500,
"weakMagnitude": 1.0,
"strongMagnitude": 1.0
}
]
},
{
"name": "Constant Weak",
"type": "Simple",
"icon": "😏",
"pattern": [
{
"startDelay": 0,
"duration": 1000,
"weakMagnitude": 1.0,
"strongMagnitude": 0.0
}
]
},
{
"name": "Constant Strong",
"type": "Simple",
"icon": "🤩",
"pattern": [
{
"startDelay": 0,
"duration": 1000,
"weakMagnitude": 0.0,
"strongMagnitude": 1.0
}
]
},
{
"name": "Constant AC",
"type": "Simple",
"icon": "😵",
"pattern": [
{
"startDelay": 0,
"duration": 1000,
"weakMagnitude": 1.0,
"strongMagnitude": 0.0
},
{
"startDelay": 0,
"duration": 1000,
"weakMagnitude": 0.0,
"strongMagnitude": 1.0
}
]
},
{
"name": "Constant Max",
"type": "Simple",
"icon": "😍",
"pattern": [
{
"startDelay": 0,
"duration": 1000,
"weakMagnitude": 1.0,
"strongMagnitude": 1.0
}
]
}
]

1
docs/css/46.30c3638a.css Normal file
View File

@ -0,0 +1 @@
.manual-form{display:flex;flex-direction:column-reverse;justify-content:space-between;gap:16px}.manual-form__input{display:grid;grid-template-columns:1fr;align-items:center}.manual-form__buttons{display:flex;flex-direction:row;justify-content:space-between;gap:32px}.manual-form__button{width:100%}@media only screen and (min-width:540px){.manual-form{display:flex;flex-direction:column;gap:32px}.manual-form__input{display:grid;grid-template-columns:1fr 1fr}}

View File

@ -0,0 +1 @@
.output-gamepad{width:100%;padding:16px;border:2px solid var(--color-border);border-radius:var(--number-border-radius);display:flex;flex-direction:column;justify-content:space-between;gap:16px}.gamepad-group{display:grid;grid-template-columns:repeat(5,1fr)}.gamepad-group>div{display:flex;flex-direction:column;justify-content:space-between;gap:8px}.pressed{background-color:var(--color-link-hover);color:var(--color-background)}

View File

@ -1 +0,0 @@
.pattern-item{width:100%;height:48px;padding:8px;border-radius:var(--number-border-radius);background:var(--color-pattern-button);display:flex;flex-direction:row;justify-content:flex-start;gap:16px;align-items:center;text-align:center;overflow:hidden;cursor:default}@media only screen and (min-width:540px){.pattern-item{width:200px}}.pattern-item ::-moz-selection{background-color:transparent}.pattern-item ::selection{background-color:transparent}.pattern-item_selected{background:var(--color-b)}.pattern-item__icon{font-size:24px}.pattern-item__name{font-size:14px;white-space:nowrap;overflow:hidden;color:var(--color-pattern-text)}.pattern-list{margin-bottom:16px;padding:32px;border-radius:var(--number-border-radius);background:var(--color-content-item-background);display:flex;flex-direction:row;justify-content:space-around;flex-wrap:wrap;gap:32px}.list-item{max-width:100%;padding:16px;border:4px solid var(--color-b);border-radius:4px;justify-content:space-between}.list-item,.list-item__info{display:flex;flex-direction:column}.list-item__info{gap:16px}.list-item_selected .list-item__info span{color:var(--color-white)}.device-list{flex-direction:row;justify-content:space-around;gap:16px}.device-list,.message{margin-bottom:16px;padding:32px;border-radius:var(--number-border-radius);background:var(--color-content-item-background);display:flex}.message{width:100%;flex-direction:column;justify-content:center;text-align:center;font-size:16px}@media only screen and (min-width:540px){.message{font-size:24px}}.wavelovers{display:flex;flex-direction:column-reverse;justify-content:flex-start;gap:16px}@media only screen and (min-width:540px){.wavelovers{flex-direction:column}}

View File

@ -0,0 +1 @@
.navigation-list{display:flex;flex-direction:row;justify-content:flex-start;gap:16px}.navigation-item.router-link-active,.navigation-item.router-link-exact-active{border-bottom:2px solid var(--color-link-hover);color:var(--color-link-hover);transition:all .5s ease;text-decoration:none}.list-item{max-width:100%;padding:16px;border:4px solid var(--color-b);border-radius:4px;justify-content:space-between}.list-item,.list-item__info{display:flex;flex-direction:column}.list-item__info{gap:16px}.list-item_selected .list-item__info span{color:var(--color-white)}.device-list{display:flex;flex-direction:row;justify-content:space-around;gap:16px}.message{width:100%;display:flex;flex-direction:column;justify-content:center;text-align:center;font-size:16px}@media only screen and (min-width:540px){.message{font-size:24px}}.pattern-item{width:100%;height:50px;padding:8px;border-radius:var(--number-border-radius);background:var(--color-pattern-button);display:flex;flex-direction:row;justify-content:flex-start;gap:8px;align-items:center;text-align:center;overflow:hidden;cursor:pointer}@media only screen and (min-width:540px){.pattern-item{width:200px}}.pattern-item ::-moz-selection{background-color:transparent}.pattern-item ::selection{background-color:transparent}.pattern-item_selected{background:var(--color-b)}.pattern-item__icon{font-size:24px}.pattern-item__info-container{display:flex;flex-direction:column;justify-content:space-between;text-align:left}.pattern-item__name{font-size:16px}.pattern-item__name,.pattern-item__type{white-space:nowrap;overflow:hidden;color:var(--color-pattern-text)}.pattern-item__type{font-size:12px}.pattern-list{display:flex;flex-direction:row;justify-content:space-around;flex-wrap:wrap;gap:16px}@media only screen and (min-width:540px){.pattern-list{display:flex;gap:32px}}

View File

@ -1,6 +1,6 @@
/* ------------------------------ */
/* Wavelovers styles */
/* version: dated 2022.07.25 */
/* version: dated 2022.08.08 */
/* author: Eugene Serb */
/* ------------------------------ */
@ -205,7 +205,7 @@ fieldset {
padding: 8px;
}
button, input, textarea, select {
button, textarea, select, input {
padding: 4px 8px;
border: 2px solid var(--color-link);
border-radius: var(--number-border-radius);
@ -215,7 +215,6 @@ button, input, textarea, select {
line-height: 1.382em;
white-space: nowrap;
}
button:hover, input:hover,
textarea:hover, select:hover {
border: 2px solid var(--color-link-hover);
@ -234,6 +233,114 @@ option {
color: var(--color-white);
}
input[type=range] {
width: 100%;
margin: 8px 0;
padding: 4px 0;
border: 0px solid var(--color-link);
-webkit-appearance: none;
}
input[type=range]:hover {
margin: 8px 0;
padding: 4px 0;
border: 0px solid var(--color-link-hover);
}
input[type=range]:focus {
outline: none;
}
input[type=range]::-webkit-slider-runnable-track {
width: 100%;
height: 8px;
cursor: pointer;
box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d;
background: var(--color-b);
border-radius: 8px;
border: 0px solid #000101;
}
input[type=range]::-webkit-slider-thumb {
box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d;
border: 0px solid #000000;
height: 16px;
width: 16px;
border-radius: 8px;
background: var(--color-a);
cursor: pointer;
-webkit-appearance: none;
margin-top: -4px;
}
input[type=range]:focus::-webkit-slider-runnable-track {
background: var(--color-b);
}
input[type=range]::-moz-range-track {
width: 100%;
height: 8px;
cursor: pointer;
animate: 0.2s;
box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d;
background: var(--color-b);
border-radius: 8px;
border: 0px solid #000101;
}
input[type=range]::-moz-range-thumb {
box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d;
border: 0px solid #000000;
height: 16px;
width: 16px;
border-radius: 8px;
background: var(--color-a);
cursor: pointer;
}
input[type=range]::-ms-track {
width: 100%;
height: 8px;
cursor: pointer;
animate: 0.2s;
background: transparent;
border-color: transparent;
border-width: 8px 0;
color: transparent;
}
input[type=range]::-ms-fill-lower {
background: var(--color-b);
border: 0px solid #000101;
border-radius: 8px;
box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d;
}
input[type=range]::-ms-fill-upper {
background: var(--color-b);
border: 0px solid #000101;
border-radius: 8px;
box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d;
}
input[type=range]::-ms-thumb {
box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d;
border: 0px solid #000000;
height: 16px;
width: 16px;
border-radius: 8px;
background: var(--color-a);
cursor: pointer;
}
input[type=range]:focus::-ms-fill-lower {
background: var(--color-b);
}
input[type=range]:focus::-ms-fill-upper {
background: var(--color-b);
}
/* ------ */
/* TABLES */
/* ------ */
@ -306,7 +413,7 @@ table, th, td {
/* ------ */
.header {
border-bottom: 32px solid var(--color-header-borderline);
border-bottom: 8px solid var(--color-header-borderline);
background: var(--color-header-background);
}
@ -324,7 +431,7 @@ table, th, td {
}
.header-wrapper {
padding-top: 64px;
padding-top: 32px;
padding-bottom: 16px;
}
@ -340,7 +447,7 @@ table, th, td {
}
.menu-wrapper {
margin-top: 32px;
margin-top: 16px;
align-self: center;
}
@ -369,6 +476,23 @@ table, th, td {
color: var(--color-header-navigation-link-hover);
}
@media only screen and (min-width: 540px) {
.header {
border-bottom: 32px solid var(--color-header-borderline);
background: var(--color-header-background);
}
.header-wrapper {
padding-top: 64px;
padding-bottom: 16px;
}
.menu-wrapper {
margin-top: 32px;
align-self: center;
}
}
@media only screen and (min-width: 720px) {
.header-wrapper {
display: flex;
@ -436,9 +560,16 @@ table, th, td {
.page {
flex-grow: 1;
margin-top: 32px;
margin-bottom: 32px;
}
@media only screen and (min-width: 540px) {
.page {
margin-top: 64px;
margin-bottom: 64px;
}
}
/* ---- */
/* POST */
@ -474,7 +605,7 @@ table, th, td {
.content-item {
margin-bottom: 16px;
padding: 32px;
padding: 16px;
border-radius: var(--number-border-radius);
background: var(--color-content-item-background);
}
@ -484,6 +615,12 @@ table, th, td {
text-align: center;
}
@media only screen and (min-width: 540px) {
.content-item {
padding: 32px;
}
}
/* ----- */
/* PAGES */
/* ----- */

11
docs/diagnostic.html Normal file
View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en-us" dir="ltr" xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Wavelovers Redirect</title>
<meta charset="UTF-8" />
<meta http-equiv="refresh" content="0; URL=https://wavelovers.ru/?diagnostic" />
</head>
<body>
</body>
</html>

View File

@ -112,7 +112,7 @@
<div class="content-item">
<h2 class="content-item__header">Troubleshooting</h2>
<span>If you are having difficulty detecting a gamepad by the browser, you can use the utility </span>
<a href="https://eugene-serb.github.io/gamepad-master/" target="_blank">Gamepad Master</a><br /><br />
<a href="https://wavelovers.ru/?diagnostic" target="_blank">Wavelovers Diagnostic</a><br /><br />
<dl>
<dt>The app does not see my device.</dt>
<dd>Make sure you have a chromium-based browser, then update the app and reconnect your device.</dd>

View File

@ -15,4 +15,4 @@
webvisor: true
});</script><style>[v-cloak] {
display: none;
}</style><script defer="defer" src="/js/chunk-vendors.d42e1256.js"></script><script defer="defer" src="/js/app.5a58d0e1.js"></script><link href="/css/app.a72a8a93.css" rel="stylesheet"></head><body><header class="header"><div class="header-wrapper container"><div class="logo-wrapper"><span class="logo-wrapper__logo" translate="no">Wavelovers</span></div><nav class="menu-wrapper"><ul class="navigation"><li class="navigation__item"><a href="/" target="_self" class="navigation__link">Home</a></li><li class="navigation__item"><a href="/faq.html" target="_self" class="navigation__link">FAQ</a></li><li class="navigation__item"><a href="/about.html" target="_self" class="navigation__link">About</a></li><li class="navigation__item"><a href="/donate.html" target="_self" class="navigation__link">Donate</a></li></ul></nav></div></header><main class="page container"><h1 class="visually-hidden">Wavelovers</h1><div id="app" v-cloak></div></main><footer class="footer"><div class="footer-wrapper container"><div class="annotation"><span class="annotation__text">© 2022 Wavelovers. Content licensed under </span><a href="https://wavelovers.ru/LICENSE.md" target="_blank">GNU General Public License v3.0</a><br><span class="annotation__text">This site is open source. </span><a href="https://github.com/eugene-serb/wavelovers/" target="_blank">Improve this page.</a></div><div class="annotation created-by"><span class="annotation__text">Created by</span><a href="https://eugene-serb.github.io/" target="_blank" translate="no">Eugene Serb</a></div></div></footer><noscript>You need to enable JavaScript to run this app.</noscript><noscript><div><img src="https://mc.yandex.ru/watch/89252711" style="position:absolute; left:-9999px;" alt=""/></div></noscript></body></html>
}</style><script defer="defer" src="/js/chunk-vendors.248cd14b.js"></script><script defer="defer" src="/js/app.26b99067.js"></script><link href="/css/app.b1ea1061.css" rel="stylesheet"></head><body><header class="header"><div class="header-wrapper container"><div class="logo-wrapper"><span class="logo-wrapper__logo" translate="no">Wavelovers</span></div><nav class="menu-wrapper"><ul class="navigation"><li class="navigation__item"><a href="/" target="_self" class="navigation__link">Home</a></li><li class="navigation__item"><a href="/faq.html" target="_self" class="navigation__link">FAQ</a></li><li class="navigation__item"><a href="/about.html" target="_self" class="navigation__link">About</a></li><li class="navigation__item"><a href="/donate.html" target="_self" class="navigation__link">Donate</a></li></ul></nav></div></header><main class="page container"><h1 class="visually-hidden">Wavelovers</h1><div id="app" v-cloak></div></main><footer class="footer"><div class="footer-wrapper container"><div class="annotation"><span class="annotation__text">© 2022 Wavelovers. Content licensed under </span><a href="https://wavelovers.ru/LICENSE.md" target="_blank">GNU General Public License v3.0</a><br><span class="annotation__text">This site is open source. </span><a href="https://github.com/eugene-serb/wavelovers/" target="_blank">Improve this page.</a></div><div class="annotation created-by"><span class="annotation__text">Created by</span><a href="https://eugene-serb.github.io/" target="_blank" translate="no">Eugene Serb</a></div></div></footer><noscript>You need to enable JavaScript to run this app.</noscript><noscript><div><img src="https://mc.yandex.ru/watch/89252711" style="position:absolute; left:-9999px;" alt=""/></div></noscript></body></html>

2
docs/js/46.c7a9f83c.js Normal file
View File

@ -0,0 +1,2 @@
"use strict";(self["webpackChunkwavelovers"]=self["webpackChunkwavelovers"]||[]).push([[46],{9046:function(a,t,n){n.r(t),n.d(t,{default:function(){return S}});var e=n(3396);function u(a,t,n,u,r,l){const s=(0,e.up)("AppManual");return(0,e.wg)(),(0,e.j4)(s)}var r=n(9242);const l={class:"content-item app-manual"},s={class:"manual-form"},o={class:"manual-form__input"},i=(0,e._)("span",null,"Start Delay (ms)",-1),p={class:"manual-form__input"},d=(0,e._)("span",null,"Duration (ms)",-1),m={class:"manual-form__input"},c=(0,e._)("span",null,"Weak Magnitude",-1),_={class:"manual-form__input"},g=(0,e._)("span",null,"Strong Magnitude",-1),f={class:"manual-form__buttons"};function M(a,t,n,u,M,w){return(0,e.wg)(),(0,e.iD)("div",l,[(0,e._)("fieldset",s,[(0,e._)("label",o,[i,(0,e.wy)((0,e._)("input",{"onUpdate:modelValue":t[0]||(t[0]=t=>a.startDelay=t),type:"number",placeholder:"Start Delay",min:"0",max:"1000",step:"25",required:""},null,512),[[r.nr,a.startDelay]])]),(0,e._)("label",p,[d,(0,e.wy)((0,e._)("input",{"onUpdate:modelValue":t[1]||(t[1]=t=>a.duration=t),type:"number",placeholder:"Duration",min:"0",max:"1000",step:"25",required:""},null,512),[[r.nr,a.duration]])]),(0,e._)("label",m,[c,(0,e.wy)((0,e._)("input",{"onUpdate:modelValue":t[2]||(t[2]=t=>a.weakMagnitude=t),type:"range",placeholder:"Weak Magnitude",min:"0.0",max:"1.0",step:"0.01",required:""},null,512),[[r.nr,a.weakMagnitude]])]),(0,e._)("label",_,[g,(0,e.wy)((0,e._)("input",{"onUpdate:modelValue":t[3]||(t[3]=t=>a.strongMagnitude=t),type:"range",placeholder:"Strong Magnitude",min:"0.0",max:"1.0",step:"0.01",required:""},null,512),[[r.nr,a.strongMagnitude]])]),(0,e._)("div",f,[(0,e._)("button",{onClick:t[4]||(t[4]=(...t)=>a.start&&a.start(...t)),class:"manual-form__button"},"Start"),(0,e._)("button",{onClick:t[5]||(t[5]=(...t)=>a.stop&&a.stop(...t)),class:"manual-form__button"},"Stop")])])])}var w=n(1746),h=(0,e.aZ)({name:"AppManual",data:()=>({startDelay:250,duration:250,weakMagnitude:1,strongMagnitude:1}),methods:{createPatternUnit:function(){const a=[{startDelay:this.startDelay,duration:this.duration,weakMagnitude:this.weakMagnitude,strongMagnitude:this.strongMagnitude}];return a},start:function(){w.Z.dispatch("startCustom",this.createPatternUnit())},stop:function(){w.Z.dispatch("reset")}}}),y=n(89);const b=(0,y.Z)(h,[["render",M]]);var k=b,v=(0,e.aZ)({name:"ManualView",components:{AppManual:k}});const D=(0,y.Z)(v,[["render",u]]);var S=D}}]);
//# sourceMappingURL=46.c7a9f83c.js.map

File diff suppressed because one or more lines are too long

2
docs/js/554.0d3dfa8b.js Normal file
View File

@ -0,0 +1,2 @@
"use strict";(self["webpackChunkwavelovers"]=self["webpackChunkwavelovers"]||[]).push([[554],{4554:function(a,t,e){e.r(t),e.d(t,{default:function(){return F}});var s=e(3396);function n(a,t,e,n,u,i){const p=(0,s.up)("AppDiagnostic");return(0,s.wg)(),(0,s.j4)(p)}const u={key:0,class:"content-item"};function i(a,t,e,n,i,p){const d=(0,s.up)("DiagnosticItem");return a.gamepads.length>0?((0,s.wg)(),(0,s.iD)("div",u,[((0,s.wg)(!0),(0,s.iD)(s.HY,null,(0,s.Ko)(a.gamepads,(t=>((0,s.wg)(),(0,s.j4)(d,{key:t.id,gamepad:t,timestamp:a.timestamp},null,8,["gamepad","timestamp"])))),128))])):(0,s.kq)("",!0)}var p=e(1746),d=e(7139);const o={class:"output-gamepad"},l={class:"gamepad-group"};function m(a,t,e,n,u,i){return(0,s.wg)(),(0,s.iD)("div",o,[(0,s._)("h3",null,"#"+(0,d.zw)(a.gamepad.unit.index+1)+". "+(0,d.zw)(a.gamepad.unit.id),1),(0,s._)("div",l,[(0,s._)("div",null,[(0,s._)("span",{class:(0,d.C_)([1===a.gamepad.unit.buttons[0].value?"pressed":""])},"A: "+(0,d.zw)(a.gamepad.unit.buttons[0].value.toFixed(2)),3),(0,s._)("span",{class:(0,d.C_)([1===a.gamepad.unit.buttons[1].value?"pressed":""])},"B: "+(0,d.zw)(a.gamepad.unit.buttons[1].value.toFixed(2)),3),(0,s._)("span",{class:(0,d.C_)([1===a.gamepad.unit.buttons[2].value?"pressed":""])},"X: "+(0,d.zw)(a.gamepad.unit.buttons[2].value.toFixed(2)),3),(0,s._)("span",{class:(0,d.C_)([1===a.gamepad.unit.buttons[3].value?"pressed":""])},"Y: "+(0,d.zw)(a.gamepad.unit.buttons[3].value.toFixed(2)),3)]),(0,s._)("div",null,[(0,s._)("span",{class:(0,d.C_)([1===a.gamepad.unit.buttons[4].value?"pressed":""])},"LB: "+(0,d.zw)(a.gamepad.unit.buttons[4].value.toFixed(2)),3),(0,s._)("span",{class:(0,d.C_)([1===a.gamepad.unit.buttons[5].value?"pressed":""])},"RB: "+(0,d.zw)(a.gamepad.unit.buttons[5].value.toFixed(2)),3),(0,s._)("span",{class:(0,d.C_)([1===a.gamepad.unit.buttons[6].value?"pressed":""])},"LT: "+(0,d.zw)(a.gamepad.unit.buttons[6].value.toFixed(2)),3),(0,s._)("span",{class:(0,d.C_)([1===a.gamepad.unit.buttons[7].value?"pressed":""])},"RT: "+(0,d.zw)(a.gamepad.unit.buttons[7].value.toFixed(2)),3)]),(0,s._)("div",null,[(0,s._)("span",{class:(0,d.C_)([1===a.gamepad.unit.buttons[8].value?"pressed":""])},"Back: "+(0,d.zw)(a.gamepad.unit.buttons[8].value.toFixed(2)),3),(0,s._)("span",{class:(0,d.C_)([1===a.gamepad.unit.buttons[9].value?"pressed":""])},"Start: "+(0,d.zw)(a.gamepad.unit.buttons[9].value.toFixed(2)),3),(0,s._)("span",{class:(0,d.C_)([1===a.gamepad.unit.buttons[10].value?"pressed":""])},"Left Stick: "+(0,d.zw)(a.gamepad.unit.buttons[10].value.toFixed(2)),3),(0,s._)("span",{class:(0,d.C_)([1===a.gamepad.unit.buttons[11].value?"pressed":""])},"Right Stick: "+(0,d.zw)(a.gamepad.unit.buttons[11].value.toFixed(2)),3)]),(0,s._)("div",null,[(0,s._)("span",{class:(0,d.C_)([1===a.gamepad.unit.buttons[12].value?"pressed":""])},"Forward: "+(0,d.zw)(a.gamepad.unit.buttons[12].value.toFixed(2)),3),(0,s._)("span",{class:(0,d.C_)([1===a.gamepad.unit.buttons[13].value?"pressed":""])},"Backward: "+(0,d.zw)(a.gamepad.unit.buttons[13].value.toFixed(2)),3),(0,s._)("span",{class:(0,d.C_)([1===a.gamepad.unit.buttons[14].value?"pressed":""])},"Left: "+(0,d.zw)(a.gamepad.unit.buttons[14].value.toFixed(2)),3),(0,s._)("span",{class:(0,d.C_)([1===a.gamepad.unit.buttons[15].value?"pressed":""])},"Right: "+(0,d.zw)(a.gamepad.unit.buttons[15].value.toFixed(2)),3)]),(0,s._)("div",null,[(0,s._)("span",null,"Left Stick X: "+(0,d.zw)(a.gamepad.unit.axes[0]?a.gamepad.unit.axes[0].toFixed(2):"missing"),1),(0,s._)("span",null,"Left Stick Y: "+(0,d.zw)(a.gamepad.unit.axes[1]?a.gamepad.unit.axes[1].toFixed(2):"missing"),1),(0,s._)("span",null,"Right Stick X: "+(0,d.zw)(a.gamepad.unit.axes[2]?a.gamepad.unit.axes[2].toFixed(2):"missing"),1),(0,s._)("span",null,"Right Stick Y: "+(0,d.zw)(a.gamepad.unit.axes[3]?a.gamepad.unit.axes[3].toFixed(2):"missing"),1)])]),(0,s._)("span",null,"Vibration Actuator: "+(0,d.zw)(a.gamepad.unit.vibrationActuator?"Available":"missing"),1)])}var g=(0,s.aZ)({name:"DiagnosticItem",props:{gamepad:{type:Object},timestamp:{type:Number}}}),r=e(89);const c=(0,r.Z)(g,[["render",m]]);var v=c,_=(0,s.aZ)({name:"AppDiagnostic",components:{DiagnosticItem:v},data:()=>({timestamp:0,interval:0}),computed:{gamepads:function(){const a=this.timestamp,t=p.Z.getters.gamepads;return t.forEach((t=>{t.interval=a})),t}},methods:{updateTimestamp:function(){this.timestamp=Date.now()}},mounted(){this.interval=setInterval(this.updateTimestamp,1)},unmounted(){clearInterval(this.interval)}});const b=(0,r.Z)(_,[["render",i]]);var w=b,x=(0,s.aZ)({name:"DiagnosticView",components:{AppDiagnostic:w}});const z=(0,r.Z)(x,[["render",n]]);var F=z}}]);
//# sourceMappingURL=554.0d3dfa8b.js.map

File diff suppressed because one or more lines are too long

2
docs/js/567.1165d9e5.js Normal file
View File

@ -0,0 +1,2 @@
"use strict";(self["webpackChunkwavelovers"]=self["webpackChunkwavelovers"]||[]).push([[567],{7567:function(n,e,t){t.r(e),t.d(e,{default:function(){return i}});var u=t(3396);const r={class:"content-item"},a=(0,u._)("h2",null,"404. Page not Found...",-1);function o(n,e,t,o,c,s){const l=(0,u.up)("center");return(0,u.wg)(),(0,u.iD)("div",r,[(0,u.Wm)(l,null,{default:(0,u.w5)((()=>[a])),_:1})])}var c=(0,u.aZ)({name:"NotFoundView"}),s=t(89);const l=(0,s.Z)(c,[["render",o]]);var i=l}}]);
//# sourceMappingURL=567.1165d9e5.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"js/567.1165d9e5.js","mappings":"8KAEA,MAAMA,EAAa,CAAEC,MAAO,gBACtBC,GAA0BC,EAAAA,EAAAA,GAAoB,KAAM,KAAM,0BAA2B,GAErF,SAAUC,EAAOC,EAAUC,EAAYC,EAAYC,EAAYC,EAAWC,GAC9E,MAAMC,GAAoBC,EAAAA,EAAAA,IAAkB,UAE5C,OAAQC,EAAAA,EAAAA,OAAcC,EAAAA,EAAAA,IAAoB,MAAOd,EAAY,EAC3De,EAAAA,EAAAA,IAAaJ,EAAmB,KAAM,CACpCK,SAASC,EAAAA,EAAAA,KAAS,IAAM,CACtBf,KAEFgB,EAAG,KAGR,CCbG,OAAeC,EAAAA,EAAAA,IAAgB,CAC3BC,KAAM,iB,QCCd,MAAMC,GAA2B,OAAgB,EAAQ,CAAC,CAAC,SAASjB,KAEpE,O","sources":["webpack://wavelovers/./src/views/NotFoundView.vue?e76c","webpack://wavelovers/./src/views/NotFoundView.vue?6f3f","webpack://wavelovers/./src/views/NotFoundView.vue"],"sourcesContent":["import { createElementVNode as _createElementVNode, resolveComponent as _resolveComponent, withCtx as _withCtx, createVNode as _createVNode, openBlock as _openBlock, createElementBlock as _createElementBlock } from \"vue\"\n\nconst _hoisted_1 = { class: \"content-item\" }\nconst _hoisted_2 = /*#__PURE__*/_createElementVNode(\"h2\", null, \"404. Page not Found...\", -1)\n\nexport function render(_ctx: any,_cache: any,$props: any,$setup: any,$data: any,$options: any) {\n const _component_center = _resolveComponent(\"center\")!\n\n return (_openBlock(), _createElementBlock(\"div\", _hoisted_1, [\n _createVNode(_component_center, null, {\n default: _withCtx(() => [\n _hoisted_2\n ]),\n _: 1\n })\n ]))\n}","\r\n import { defineComponent } from 'vue';\r\n\r\n export default defineComponent({\r\n name: 'NotFoundView',\r\n });\r\n","import { render } from \"./NotFoundView.vue?vue&type=template&id=e1bb3c6a&ts=true\"\nimport script from \"./NotFoundView.vue?vue&type=script&lang=ts\"\nexport * from \"./NotFoundView.vue?vue&type=script&lang=ts\"\n\nimport exportComponent from \"E:\\\\Sources\\\\Repos\\\\wavelovers\\\\node_modules\\\\vue-loader\\\\dist\\\\exportHelper.js\"\nconst __exports__ = /*#__PURE__*/exportComponent(script, [['render',render]])\n\nexport default __exports__"],"names":["_hoisted_1","class","_hoisted_2","_createElementVNode","render","_ctx","_cache","$props","$setup","$data","$options","_component_center","_resolveComponent","_openBlock","_createElementBlock","_createVNode","default","_withCtx","_","defineComponent","name","__exports__"],"sourceRoot":""}

2
docs/js/app.26b99067.js Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

11
docs/manual.html Normal file
View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en-us" dir="ltr" xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Wavelovers Redirect</title>
<meta charset="UTF-8" />
<meta http-equiv="refresh" content="0; URL=https://wavelovers.ru/?manual" />
</head>
<body>
</body>
</html>

View File

@ -2,25 +2,25 @@
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://wavelovers.ru/</loc>
<lastmod>2022-08-06</lastmod>
<lastmod>2022-08-09</lastmod>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://wavelovers.ru/faq.html</loc>
<lastmod>2022-08-06</lastmod>
<lastmod>2022-08-09</lastmod>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://wavelovers.ru/about.html</loc>
<lastmod>2022-08-06</lastmod>
<lastmod>2022-08-09</lastmod>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://wavelovers.ru/donate.html</loc>
<lastmod>2022-08-06</lastmod>
<lastmod>2022-08-09</lastmod>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>

View File

@ -2,7 +2,7 @@
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<sitemap>
<loc>https://wavelovers.ru/sitemap-internal.xml</loc>
<lastmod>2022-08-06</lastmod>
<lastmod>2022-08-09</lastmod>
</sitemap>
</sitemapindex>

264
package-lock.json generated
View File

@ -11,6 +11,7 @@
"dependencies": {
"core-js": "^3.8.3",
"vue": "^3.2.13",
"vue-router": "^4.0.3",
"vuex": "^4.0.0"
},
"devDependencies": {
@ -18,6 +19,7 @@
"@typescript-eslint/parser": "^5.4.0",
"@vue/cli-plugin-babel": "~5.0.0",
"@vue/cli-plugin-eslint": "~5.0.0",
"@vue/cli-plugin-router": "~5.0.0",
"@vue/cli-plugin-typescript": "~5.0.0",
"@vue/cli-plugin-vuex": "~5.0.0",
"@vue/cli-service": "~5.0.0",
@ -2217,9 +2219,9 @@
"dev": true
},
"node_modules/@types/node": {
"version": "18.6.4",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.6.4.tgz",
"integrity": "sha512-I4BD3L+6AWiUobfxZ49DlU43gtI+FTHSv9pE2Zekg6KjMpre4ByusaljW3vYSLJrvQ1ck1hUaeVu8HVlY3vzHg==",
"version": "18.6.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.6.5.tgz",
"integrity": "sha512-Xjt5ZGUa5WusGZJ4WJPbOT8QOqp6nDynVFRKcUt32bOgvXEoc6o085WNkYTMO7ifAj2isEfQQ2cseE+wT6jsRw==",
"dev": true
},
"node_modules/@types/normalize-package-data": {
@ -2296,14 +2298,14 @@
}
},
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "5.32.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.32.0.tgz",
"integrity": "sha512-CHLuz5Uz7bHP2WgVlvoZGhf0BvFakBJKAD/43Ty0emn4wXWv5k01ND0C0fHcl/Im8Td2y/7h44E9pca9qAu2ew==",
"version": "5.33.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.33.0.tgz",
"integrity": "sha512-jHvZNSW2WZ31OPJ3enhLrEKvAZNyAFWZ6rx9tUwaessTc4sx9KmgMNhVcqVAl1ETnT5rU5fpXTLmY9YvC1DCNg==",
"dev": true,
"dependencies": {
"@typescript-eslint/scope-manager": "5.32.0",
"@typescript-eslint/type-utils": "5.32.0",
"@typescript-eslint/utils": "5.32.0",
"@typescript-eslint/scope-manager": "5.33.0",
"@typescript-eslint/type-utils": "5.33.0",
"@typescript-eslint/utils": "5.33.0",
"debug": "^4.3.4",
"functional-red-black-tree": "^1.0.1",
"ignore": "^5.2.0",
@ -2329,14 +2331,14 @@
}
},
"node_modules/@typescript-eslint/parser": {
"version": "5.32.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.32.0.tgz",
"integrity": "sha512-IxRtsehdGV9GFQ35IGm5oKKR2OGcazUoiNBxhRV160iF9FoyuXxjY+rIqs1gfnd+4eL98OjeGnMpE7RF/NBb3A==",
"version": "5.33.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.33.0.tgz",
"integrity": "sha512-cgM5cJrWmrDV2KpvlcSkelTBASAs1mgqq+IUGKJvFxWrapHpaRy5EXPQz9YaKF3nZ8KY18ILTiVpUtbIac86/w==",
"dev": true,
"dependencies": {
"@typescript-eslint/scope-manager": "5.32.0",
"@typescript-eslint/types": "5.32.0",
"@typescript-eslint/typescript-estree": "5.32.0",
"@typescript-eslint/scope-manager": "5.33.0",
"@typescript-eslint/types": "5.33.0",
"@typescript-eslint/typescript-estree": "5.33.0",
"debug": "^4.3.4"
},
"engines": {
@ -2356,13 +2358,13 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
"version": "5.32.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.32.0.tgz",
"integrity": "sha512-KyAE+tUON0D7tNz92p1uetRqVJiiAkeluvwvZOqBmW9z2XApmk5WSMV9FrzOroAcVxJZB3GfUwVKr98Dr/OjOg==",
"version": "5.33.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.33.0.tgz",
"integrity": "sha512-/Jta8yMNpXYpRDl8EwF/M8It2A9sFJTubDo0ATZefGXmOqlaBffEw0ZbkbQ7TNDK6q55NPHFshGBPAZvZkE8Pw==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.32.0",
"@typescript-eslint/visitor-keys": "5.32.0"
"@typescript-eslint/types": "5.33.0",
"@typescript-eslint/visitor-keys": "5.33.0"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@ -2373,12 +2375,12 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
"version": "5.32.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.32.0.tgz",
"integrity": "sha512-0gSsIhFDduBz3QcHJIp3qRCvVYbqzHg8D6bHFsDMrm0rURYDj+skBK2zmYebdCp+4nrd9VWd13egvhYFJj/wZg==",
"version": "5.33.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.33.0.tgz",
"integrity": "sha512-2zB8uEn7hEH2pBeyk3NpzX1p3lF9dKrEbnXq1F7YkpZ6hlyqb2yZujqgRGqXgRBTHWIUG3NGx/WeZk224UKlIA==",
"dev": true,
"dependencies": {
"@typescript-eslint/utils": "5.32.0",
"@typescript-eslint/utils": "5.33.0",
"debug": "^4.3.4",
"tsutils": "^3.21.0"
},
@ -2399,9 +2401,9 @@
}
},
"node_modules/@typescript-eslint/types": {
"version": "5.32.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.32.0.tgz",
"integrity": "sha512-EBUKs68DOcT/EjGfzywp+f8wG9Zw6gj6BjWu7KV/IYllqKJFPlZlLSYw/PTvVyiRw50t6wVbgv4p9uE2h6sZrQ==",
"version": "5.33.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.33.0.tgz",
"integrity": "sha512-nIMt96JngB4MYFYXpZ/3ZNU4GWPNdBbcB5w2rDOCpXOVUkhtNlG2mmm8uXhubhidRZdwMaMBap7Uk8SZMU/ppw==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@ -2412,13 +2414,13 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
"version": "5.32.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.32.0.tgz",
"integrity": "sha512-ZVAUkvPk3ITGtCLU5J4atCw9RTxK+SRc6hXqLtllC2sGSeMFWN+YwbiJR9CFrSFJ3w4SJfcWtDwNb/DmUIHdhg==",
"version": "5.33.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.33.0.tgz",
"integrity": "sha512-tqq3MRLlggkJKJUrzM6wltk8NckKyyorCSGMq4eVkyL5sDYzJJcMgZATqmF8fLdsWrW7OjjIZ1m9v81vKcaqwQ==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.32.0",
"@typescript-eslint/visitor-keys": "5.32.0",
"@typescript-eslint/types": "5.33.0",
"@typescript-eslint/visitor-keys": "5.33.0",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
@ -2439,15 +2441,15 @@
}
},
"node_modules/@typescript-eslint/utils": {
"version": "5.32.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.32.0.tgz",
"integrity": "sha512-W7lYIAI5Zlc5K082dGR27Fczjb3Q57ECcXefKU/f0ajM5ToM0P+N9NmJWip8GmGu/g6QISNT+K6KYB+iSHjXCQ==",
"version": "5.33.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.33.0.tgz",
"integrity": "sha512-JxOAnXt9oZjXLIiXb5ZIcZXiwVHCkqZgof0O8KPgz7C7y0HS42gi75PdPlqh1Tf109M0fyUw45Ao6JLo7S5AHw==",
"dev": true,
"dependencies": {
"@types/json-schema": "^7.0.9",
"@typescript-eslint/scope-manager": "5.32.0",
"@typescript-eslint/types": "5.32.0",
"@typescript-eslint/typescript-estree": "5.32.0",
"@typescript-eslint/scope-manager": "5.33.0",
"@typescript-eslint/types": "5.33.0",
"@typescript-eslint/typescript-estree": "5.33.0",
"eslint-scope": "^5.1.1",
"eslint-utils": "^3.0.0"
},
@ -2463,12 +2465,12 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
"version": "5.32.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.32.0.tgz",
"integrity": "sha512-S54xOHZgfThiZ38/ZGTgB2rqx51CMJ5MCfVT2IplK4Q7hgzGfe0nLzLCcenDnc/cSjP568hdeKfeDcBgqNHD/g==",
"version": "5.33.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.33.0.tgz",
"integrity": "sha512-/XsqCzD4t+Y9p5wd9HZiptuGKBlaZO5showwqODii5C0nZawxWLF+Q6k5wYHBrQv96h6GYKyqqMHCSTqta8Kiw==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.32.0",
"@typescript-eslint/types": "5.33.0",
"eslint-visitor-keys": "^3.3.0"
},
"engines": {
@ -5184,9 +5186,9 @@
"dev": true
},
"node_modules/electron-to-chromium": {
"version": "1.4.211",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.211.tgz",
"integrity": "sha512-BZSbMpyFQU0KBJ1JG26XGeFI3i4op+qOYGxftmZXFZoHkhLgsSv4DHDJfl8ogII3hIuzGt51PaZ195OVu0yJ9A==",
"version": "1.4.212",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.212.tgz",
"integrity": "sha512-LjQUg1SpLj2GfyaPDVBUHdhmlDU1vDB4f0mJWSGkISoXQrn5/lH3ECPCuo2Bkvf6Y30wO+b69te+rZK/llZmjg==",
"dev": true
},
"node_modules/emoji-regex": {
@ -8218,14 +8220,14 @@
}
},
"node_modules/object.assign": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz",
"integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==",
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.3.tgz",
"integrity": "sha512-ZFJnX3zltyjcYJL0RoCJuzb+11zWGyaDbjgxZbdV7rFEcHQuYxrZqhow67aA7xpes6LhojyFDaBKAFfogQrikA==",
"dev": true,
"dependencies": {
"call-bind": "^1.0.0",
"define-properties": "^1.1.3",
"has-symbols": "^1.0.1",
"call-bind": "^1.0.2",
"define-properties": "^1.1.4",
"has-symbols": "^1.0.3",
"object-keys": "^1.1.1"
},
"engines": {
@ -8638,14 +8640,14 @@
}
},
"node_modules/portfinder": {
"version": "1.0.28",
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz",
"integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==",
"version": "1.0.29",
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.29.tgz",
"integrity": "sha512-Z5+DarHWCKlufshB9Z1pN95oLtANoY5Wn9X3JGELGyQ6VhEcBfT2t+1fGUBq7MwUant6g/mqowH+4HifByPbiQ==",
"dev": true,
"dependencies": {
"async": "^2.6.2",
"debug": "^3.1.1",
"mkdirp": "^0.5.5"
"async": "^2.6.4",
"debug": "^3.2.7",
"mkdirp": "^0.5.6"
},
"engines": {
"node": ">= 0.12.0"
@ -8661,9 +8663,9 @@
}
},
"node_modules/postcss": {
"version": "8.4.14",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz",
"integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==",
"version": "8.4.16",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.16.tgz",
"integrity": "sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==",
"funding": [
{
"type": "opencollective",
@ -11156,6 +11158,20 @@
"node": ">=8"
}
},
"node_modules/vue-router": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.1.3.tgz",
"integrity": "sha512-XvK81bcYglKiayT7/vYAg/f36ExPC4t90R/HIpzrZ5x+17BOWptXLCrEPufGgZeuq68ww4ekSIMBZY1qdUdfjA==",
"dependencies": {
"@vue/devtools-api": "^6.1.4"
},
"funding": {
"url": "https://github.com/sponsors/posva"
},
"peerDependencies": {
"vue": "^3.2.0"
}
},
"node_modules/vue-style-loader": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.3.tgz",
@ -13576,9 +13592,9 @@
"dev": true
},
"@types/node": {
"version": "18.6.4",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.6.4.tgz",
"integrity": "sha512-I4BD3L+6AWiUobfxZ49DlU43gtI+FTHSv9pE2Zekg6KjMpre4ByusaljW3vYSLJrvQ1ck1hUaeVu8HVlY3vzHg==",
"version": "18.6.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.6.5.tgz",
"integrity": "sha512-Xjt5ZGUa5WusGZJ4WJPbOT8QOqp6nDynVFRKcUt32bOgvXEoc6o085WNkYTMO7ifAj2isEfQQ2cseE+wT6jsRw==",
"dev": true
},
"@types/normalize-package-data": {
@ -13655,14 +13671,14 @@
}
},
"@typescript-eslint/eslint-plugin": {
"version": "5.32.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.32.0.tgz",
"integrity": "sha512-CHLuz5Uz7bHP2WgVlvoZGhf0BvFakBJKAD/43Ty0emn4wXWv5k01ND0C0fHcl/Im8Td2y/7h44E9pca9qAu2ew==",
"version": "5.33.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.33.0.tgz",
"integrity": "sha512-jHvZNSW2WZ31OPJ3enhLrEKvAZNyAFWZ6rx9tUwaessTc4sx9KmgMNhVcqVAl1ETnT5rU5fpXTLmY9YvC1DCNg==",
"dev": true,
"requires": {
"@typescript-eslint/scope-manager": "5.32.0",
"@typescript-eslint/type-utils": "5.32.0",
"@typescript-eslint/utils": "5.32.0",
"@typescript-eslint/scope-manager": "5.33.0",
"@typescript-eslint/type-utils": "5.33.0",
"@typescript-eslint/utils": "5.33.0",
"debug": "^4.3.4",
"functional-red-black-tree": "^1.0.1",
"ignore": "^5.2.0",
@ -13672,52 +13688,52 @@
}
},
"@typescript-eslint/parser": {
"version": "5.32.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.32.0.tgz",
"integrity": "sha512-IxRtsehdGV9GFQ35IGm5oKKR2OGcazUoiNBxhRV160iF9FoyuXxjY+rIqs1gfnd+4eL98OjeGnMpE7RF/NBb3A==",
"version": "5.33.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.33.0.tgz",
"integrity": "sha512-cgM5cJrWmrDV2KpvlcSkelTBASAs1mgqq+IUGKJvFxWrapHpaRy5EXPQz9YaKF3nZ8KY18ILTiVpUtbIac86/w==",
"dev": true,
"requires": {
"@typescript-eslint/scope-manager": "5.32.0",
"@typescript-eslint/types": "5.32.0",
"@typescript-eslint/typescript-estree": "5.32.0",
"@typescript-eslint/scope-manager": "5.33.0",
"@typescript-eslint/types": "5.33.0",
"@typescript-eslint/typescript-estree": "5.33.0",
"debug": "^4.3.4"
}
},
"@typescript-eslint/scope-manager": {
"version": "5.32.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.32.0.tgz",
"integrity": "sha512-KyAE+tUON0D7tNz92p1uetRqVJiiAkeluvwvZOqBmW9z2XApmk5WSMV9FrzOroAcVxJZB3GfUwVKr98Dr/OjOg==",
"version": "5.33.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.33.0.tgz",
"integrity": "sha512-/Jta8yMNpXYpRDl8EwF/M8It2A9sFJTubDo0ATZefGXmOqlaBffEw0ZbkbQ7TNDK6q55NPHFshGBPAZvZkE8Pw==",
"dev": true,
"requires": {
"@typescript-eslint/types": "5.32.0",
"@typescript-eslint/visitor-keys": "5.32.0"
"@typescript-eslint/types": "5.33.0",
"@typescript-eslint/visitor-keys": "5.33.0"
}
},
"@typescript-eslint/type-utils": {
"version": "5.32.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.32.0.tgz",
"integrity": "sha512-0gSsIhFDduBz3QcHJIp3qRCvVYbqzHg8D6bHFsDMrm0rURYDj+skBK2zmYebdCp+4nrd9VWd13egvhYFJj/wZg==",
"version": "5.33.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.33.0.tgz",
"integrity": "sha512-2zB8uEn7hEH2pBeyk3NpzX1p3lF9dKrEbnXq1F7YkpZ6hlyqb2yZujqgRGqXgRBTHWIUG3NGx/WeZk224UKlIA==",
"dev": true,
"requires": {
"@typescript-eslint/utils": "5.32.0",
"@typescript-eslint/utils": "5.33.0",
"debug": "^4.3.4",
"tsutils": "^3.21.0"
}
},
"@typescript-eslint/types": {
"version": "5.32.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.32.0.tgz",
"integrity": "sha512-EBUKs68DOcT/EjGfzywp+f8wG9Zw6gj6BjWu7KV/IYllqKJFPlZlLSYw/PTvVyiRw50t6wVbgv4p9uE2h6sZrQ==",
"version": "5.33.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.33.0.tgz",
"integrity": "sha512-nIMt96JngB4MYFYXpZ/3ZNU4GWPNdBbcB5w2rDOCpXOVUkhtNlG2mmm8uXhubhidRZdwMaMBap7Uk8SZMU/ppw==",
"dev": true
},
"@typescript-eslint/typescript-estree": {
"version": "5.32.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.32.0.tgz",
"integrity": "sha512-ZVAUkvPk3ITGtCLU5J4atCw9RTxK+SRc6hXqLtllC2sGSeMFWN+YwbiJR9CFrSFJ3w4SJfcWtDwNb/DmUIHdhg==",
"version": "5.33.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.33.0.tgz",
"integrity": "sha512-tqq3MRLlggkJKJUrzM6wltk8NckKyyorCSGMq4eVkyL5sDYzJJcMgZATqmF8fLdsWrW7OjjIZ1m9v81vKcaqwQ==",
"dev": true,
"requires": {
"@typescript-eslint/types": "5.32.0",
"@typescript-eslint/visitor-keys": "5.32.0",
"@typescript-eslint/types": "5.33.0",
"@typescript-eslint/visitor-keys": "5.33.0",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
@ -13726,26 +13742,26 @@
}
},
"@typescript-eslint/utils": {
"version": "5.32.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.32.0.tgz",
"integrity": "sha512-W7lYIAI5Zlc5K082dGR27Fczjb3Q57ECcXefKU/f0ajM5ToM0P+N9NmJWip8GmGu/g6QISNT+K6KYB+iSHjXCQ==",
"version": "5.33.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.33.0.tgz",
"integrity": "sha512-JxOAnXt9oZjXLIiXb5ZIcZXiwVHCkqZgof0O8KPgz7C7y0HS42gi75PdPlqh1Tf109M0fyUw45Ao6JLo7S5AHw==",
"dev": true,
"requires": {
"@types/json-schema": "^7.0.9",
"@typescript-eslint/scope-manager": "5.32.0",
"@typescript-eslint/types": "5.32.0",
"@typescript-eslint/typescript-estree": "5.32.0",
"@typescript-eslint/scope-manager": "5.33.0",
"@typescript-eslint/types": "5.33.0",
"@typescript-eslint/typescript-estree": "5.33.0",
"eslint-scope": "^5.1.1",
"eslint-utils": "^3.0.0"
}
},
"@typescript-eslint/visitor-keys": {
"version": "5.32.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.32.0.tgz",
"integrity": "sha512-S54xOHZgfThiZ38/ZGTgB2rqx51CMJ5MCfVT2IplK4Q7hgzGfe0nLzLCcenDnc/cSjP568hdeKfeDcBgqNHD/g==",
"version": "5.33.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.33.0.tgz",
"integrity": "sha512-/XsqCzD4t+Y9p5wd9HZiptuGKBlaZO5showwqODii5C0nZawxWLF+Q6k5wYHBrQv96h6GYKyqqMHCSTqta8Kiw==",
"dev": true,
"requires": {
"@typescript-eslint/types": "5.32.0",
"@typescript-eslint/types": "5.33.0",
"eslint-visitor-keys": "^3.3.0"
}
},
@ -15786,9 +15802,9 @@
"dev": true
},
"electron-to-chromium": {
"version": "1.4.211",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.211.tgz",
"integrity": "sha512-BZSbMpyFQU0KBJ1JG26XGeFI3i4op+qOYGxftmZXFZoHkhLgsSv4DHDJfl8ogII3hIuzGt51PaZ195OVu0yJ9A==",
"version": "1.4.212",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.212.tgz",
"integrity": "sha512-LjQUg1SpLj2GfyaPDVBUHdhmlDU1vDB4f0mJWSGkISoXQrn5/lH3ECPCuo2Bkvf6Y30wO+b69te+rZK/llZmjg==",
"dev": true
},
"emoji-regex": {
@ -18062,14 +18078,14 @@
"dev": true
},
"object.assign": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz",
"integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==",
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.3.tgz",
"integrity": "sha512-ZFJnX3zltyjcYJL0RoCJuzb+11zWGyaDbjgxZbdV7rFEcHQuYxrZqhow67aA7xpes6LhojyFDaBKAFfogQrikA==",
"dev": true,
"requires": {
"call-bind": "^1.0.0",
"define-properties": "^1.1.3",
"has-symbols": "^1.0.1",
"call-bind": "^1.0.2",
"define-properties": "^1.1.4",
"has-symbols": "^1.0.3",
"object-keys": "^1.1.1"
}
},
@ -18378,14 +18394,14 @@
}
},
"portfinder": {
"version": "1.0.28",
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz",
"integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==",
"version": "1.0.29",
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.29.tgz",
"integrity": "sha512-Z5+DarHWCKlufshB9Z1pN95oLtANoY5Wn9X3JGELGyQ6VhEcBfT2t+1fGUBq7MwUant6g/mqowH+4HifByPbiQ==",
"dev": true,
"requires": {
"async": "^2.6.2",
"debug": "^3.1.1",
"mkdirp": "^0.5.5"
"async": "^2.6.4",
"debug": "^3.2.7",
"mkdirp": "^0.5.6"
},
"dependencies": {
"debug": {
@ -18400,9 +18416,9 @@
}
},
"postcss": {
"version": "8.4.14",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz",
"integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==",
"version": "8.4.16",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.16.tgz",
"integrity": "sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==",
"requires": {
"nanoid": "^3.3.4",
"picocolors": "^1.0.0",
@ -20187,6 +20203,14 @@
}
}
},
"vue-router": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.1.3.tgz",
"integrity": "sha512-XvK81bcYglKiayT7/vYAg/f36ExPC4t90R/HIpzrZ5x+17BOWptXLCrEPufGgZeuq68ww4ekSIMBZY1qdUdfjA==",
"requires": {
"@vue/devtools-api": "^6.1.4"
}
},
"vue-style-loader": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.3.tgz",

View File

@ -23,6 +23,7 @@
"dependencies": {
"core-js": "^3.8.3",
"vue": "^3.2.13",
"vue-router": "^4.0.3",
"vuex": "^4.0.0"
},
"devDependencies": {
@ -30,6 +31,7 @@
"@typescript-eslint/parser": "^5.4.0",
"@vue/cli-plugin-babel": "~5.0.0",
"@vue/cli-plugin-eslint": "~5.0.0",
"@vue/cli-plugin-router": "~5.0.0",
"@vue/cli-plugin-typescript": "~5.0.0",
"@vue/cli-plugin-vuex": "~5.0.0",
"@vue/cli-service": "~5.0.0",
@ -41,3 +43,4 @@
"typescript": "~4.5.5"
}
}

View File

@ -672,3 +672,4 @@ may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.

View File

@ -1,8 +1,18 @@
# Wavelovers
Wavelovers in ***VueJS***, ***Typescript***, ***Javascript***, ***HTML***, ***CSS*** and ***SCSS*** **[[rep](https://github.com/eugene-serb/wavelovers/), [site](https://wavelovers.ru/)]**.
Wavelovers links: **[[rep](https://github.com/eugene-serb/wavelovers/), [site](https://wavelovers.ru/)]**.
This is Wavelovers, which can make a vibrating massager out of a gamepad. It has 16 free vibration patterns to play with.
This is Wavelovers, a gamepad and gamepad vibration test tool that can also make a vibration massager out of a gamepad. It has 16 free vibration patterns to play with.
Tech Stack:
***Vue.js***, ***Vuex***, ***Vue Router***, ***Typescript***, ***Javascript***, ***HTML***, ***CSS***, ***SCSS***, ***ESLint***, ***Babel***.
Commands:<br />
1. npm install Project setup.<br />
2. npm run serve Compiles and hot-reloads for development.<br />
3. npm run build Compiles and minifies for production.<br />
4. npm run lint Lints and fixes files.<br />
Catalogs structure:<br />
***/docs/*** production build. <br />
***/ (root)*** dev files.

View File

@ -1,62 +1,121 @@
[
{
"name": "Dotted Weak",
"name": "Constant Weak",
"type": "Simple",
"icon": "😌",
"icon": "😏",
"pattern": [
{
"startDelay": 200,
"duration": 100,
"startDelay": 0,
"duration": 1000,
"weakMagnitude": 1.0,
"strongMagnitude": 0.0
}
]
},
{
"name": "Dotted Strong",
"name": "Constant Strong",
"type": "Simple",
"icon": "😉",
"icon": "🤩",
"pattern": [
{
"startDelay": 200,
"duration": 100,
"startDelay": 0,
"duration": 1000,
"weakMagnitude": 0.0,
"strongMagnitude": 1.0
}
]
},
{
"name": "Dotted AC",
"name": "Constant Max",
"type": "Simple",
"icon": "🤨",
"icon": "😍",
"pattern": [
{
"startDelay": 0,
"duration": 1000,
"weakMagnitude": 1.0,
"strongMagnitude": 1.0
}
]
},
{
"name": "Constant AC",
"type": "Complex",
"icon": "😵",
"pattern": [
{
"startDelay": 0,
"duration": 1000,
"weakMagnitude": 1.0,
"strongMagnitude": 0.0
},
{
"startDelay": 0,
"duration": 1000,
"weakMagnitude": 0.0,
"strongMagnitude": 1.0
}
]
},
{
"name": "Long Dashed Weak",
"type": "Simple",
"icon": "😋",
"pattern": [
{
"startDelay": 200,
"duration": 100,
"duration": 500,
"weakMagnitude": 1.0,
"strongMagnitude": 0.0
}
]
},
{
"name": "Long Dashed Strong",
"type": "Simple",
"icon": "😜",
"pattern": [
{
"startDelay": 100,
"duration": 500,
"weakMagnitude": 0.0,
"strongMagnitude": 1.0
}
]
},
{
"name": "Long Dashed Max",
"type": "Simple",
"icon": "🤪",
"pattern": [
{
"startDelay": 200,
"duration": 500,
"weakMagnitude": 1.0,
"strongMagnitude": 1.0
}
]
},
{
"name": "Long Dashed AC",
"type": "Complex",
"icon": "😝",
"pattern": [
{
"startDelay": 200,
"duration": 500,
"weakMagnitude": 1.0,
"strongMagnitude": 0.0
},
{
"startDelay": 200,
"duration": 100,
"duration": 500,
"weakMagnitude": 0.0,
"strongMagnitude": 1.0
}
]
},
{
"name": "Dotted Max",
"type": "Simple",
"icon": "🙃",
"pattern": [
{
"startDelay": 200,
"duration": 100,
"weakMagnitude": 1.0,
"strongMagnitude": 1.0
}
]
},
{
"name": "Short Dashed Weak",
"type": "Simple",
@ -84,8 +143,21 @@
]
},
{
"name": "Short Dashed AC",
"name": "Short Dashed Max",
"type": "Simple",
"icon": "😊",
"pattern": [
{
"startDelay": 200,
"duration": 250,
"weakMagnitude": 1.0,
"strongMagnitude": 1.0
}
]
},
{
"name": "Short Dashed AC",
"type": "Complex",
"icon": "🤤",
"pattern": [
{
@ -103,132 +175,61 @@
]
},
{
"name": "Short Dashed Max",
"name": "Dotted Weak",
"type": "Simple",
"icon": "😊",
"icon": "😌",
"pattern": [
{
"startDelay": 200,
"duration": 250,
"weakMagnitude": 1.0,
"strongMagnitude": 1.0
}
]
},
{
"name": "Long Dashed Weak",
"type": "Simple",
"icon": "😋",
"pattern": [
{
"startDelay": 200,
"duration": 500,
"duration": 100,
"weakMagnitude": 1.0,
"strongMagnitude": 0.0
}
]
},
{
"name": "Long Dashed Strong",
"name": "Dotted Strong",
"type": "Simple",
"icon": "😜",
"icon": "😉",
"pattern": [
{
"startDelay": 100,
"duration": 500,
"startDelay": 200,
"duration": 100,
"weakMagnitude": 0.0,
"strongMagnitude": 1.0
}
]
},
{
"name": "Long Dashed AC",
"name": "Dotted Max",
"type": "Simple",
"icon": "😝",
"icon": "🙃",
"pattern": [
{
"startDelay": 200,
"duration": 500,
"duration": 100,
"weakMagnitude": 1.0,
"strongMagnitude": 1.0
}
]
},
{
"name": "Dotted AC",
"type": "Complex",
"icon": "🤨",
"pattern": [
{
"startDelay": 200,
"duration": 100,
"weakMagnitude": 1.0,
"strongMagnitude": 0.0
},
{
"startDelay": 200,
"duration": 500,
"duration": 100,
"weakMagnitude": 0.0,
"strongMagnitude": 1.0
}
]
},
{
"name": "Long Dashed Max",
"type": "Simple",
"icon": "🤪",
"pattern": [
{
"startDelay": 200,
"duration": 500,
"weakMagnitude": 1.0,
"strongMagnitude": 1.0
}
]
},
{
"name": "Constant Weak",
"type": "Simple",
"icon": "😏",
"pattern": [
{
"startDelay": 0,
"duration": 1000,
"weakMagnitude": 1.0,
"strongMagnitude": 0.0
}
]
},
{
"name": "Constant Strong",
"type": "Simple",
"icon": "🤩",
"pattern": [
{
"startDelay": 0,
"duration": 1000,
"weakMagnitude": 0.0,
"strongMagnitude": 1.0
}
]
},
{
"name": "Constant AC",
"type": "Simple",
"icon": "😵",
"pattern": [
{
"startDelay": 0,
"duration": 1000,
"weakMagnitude": 1.0,
"strongMagnitude": 0.0
},
{
"startDelay": 0,
"duration": 1000,
"weakMagnitude": 0.0,
"strongMagnitude": 1.0
}
]
},
{
"name": "Constant Max",
"type": "Simple",
"icon": "😍",
"pattern": [
{
"startDelay": 0,
"duration": 1000,
"weakMagnitude": 1.0,
"strongMagnitude": 1.0
}
]
}
]

View File

@ -1,6 +1,6 @@
/* ------------------------------ */
/* Wavelovers styles */
/* version: dated 2022.07.25 */
/* version: dated 2022.08.08 */
/* author: Eugene Serb */
/* ------------------------------ */
@ -205,7 +205,7 @@ fieldset {
padding: 8px;
}
button, input, textarea, select {
button, textarea, select, input {
padding: 4px 8px;
border: 2px solid var(--color-link);
border-radius: var(--number-border-radius);
@ -215,7 +215,6 @@ button, input, textarea, select {
line-height: 1.382em;
white-space: nowrap;
}
button:hover, input:hover,
textarea:hover, select:hover {
border: 2px solid var(--color-link-hover);
@ -234,6 +233,114 @@ option {
color: var(--color-white);
}
input[type=range] {
width: 100%;
margin: 8px 0;
padding: 4px 0;
border: 0px solid var(--color-link);
-webkit-appearance: none;
}
input[type=range]:hover {
margin: 8px 0;
padding: 4px 0;
border: 0px solid var(--color-link-hover);
}
input[type=range]:focus {
outline: none;
}
input[type=range]::-webkit-slider-runnable-track {
width: 100%;
height: 8px;
cursor: pointer;
box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d;
background: var(--color-b);
border-radius: 8px;
border: 0px solid #000101;
}
input[type=range]::-webkit-slider-thumb {
box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d;
border: 0px solid #000000;
height: 16px;
width: 16px;
border-radius: 8px;
background: var(--color-a);
cursor: pointer;
-webkit-appearance: none;
margin-top: -4px;
}
input[type=range]:focus::-webkit-slider-runnable-track {
background: var(--color-b);
}
input[type=range]::-moz-range-track {
width: 100%;
height: 8px;
cursor: pointer;
animate: 0.2s;
box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d;
background: var(--color-b);
border-radius: 8px;
border: 0px solid #000101;
}
input[type=range]::-moz-range-thumb {
box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d;
border: 0px solid #000000;
height: 16px;
width: 16px;
border-radius: 8px;
background: var(--color-a);
cursor: pointer;
}
input[type=range]::-ms-track {
width: 100%;
height: 8px;
cursor: pointer;
animate: 0.2s;
background: transparent;
border-color: transparent;
border-width: 8px 0;
color: transparent;
}
input[type=range]::-ms-fill-lower {
background: var(--color-b);
border: 0px solid #000101;
border-radius: 8px;
box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d;
}
input[type=range]::-ms-fill-upper {
background: var(--color-b);
border: 0px solid #000101;
border-radius: 8px;
box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d;
}
input[type=range]::-ms-thumb {
box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d;
border: 0px solid #000000;
height: 16px;
width: 16px;
border-radius: 8px;
background: var(--color-a);
cursor: pointer;
}
input[type=range]:focus::-ms-fill-lower {
background: var(--color-b);
}
input[type=range]:focus::-ms-fill-upper {
background: var(--color-b);
}
/* ------ */
/* TABLES */
/* ------ */
@ -306,7 +413,7 @@ table, th, td {
/* ------ */
.header {
border-bottom: 32px solid var(--color-header-borderline);
border-bottom: 8px solid var(--color-header-borderline);
background: var(--color-header-background);
}
@ -324,7 +431,7 @@ table, th, td {
}
.header-wrapper {
padding-top: 64px;
padding-top: 32px;
padding-bottom: 16px;
}
@ -340,7 +447,7 @@ table, th, td {
}
.menu-wrapper {
margin-top: 32px;
margin-top: 16px;
align-self: center;
}
@ -369,6 +476,23 @@ table, th, td {
color: var(--color-header-navigation-link-hover);
}
@media only screen and (min-width: 540px) {
.header {
border-bottom: 32px solid var(--color-header-borderline);
background: var(--color-header-background);
}
.header-wrapper {
padding-top: 64px;
padding-bottom: 16px;
}
.menu-wrapper {
margin-top: 32px;
align-self: center;
}
}
@media only screen and (min-width: 720px) {
.header-wrapper {
display: flex;
@ -436,9 +560,16 @@ table, th, td {
.page {
flex-grow: 1;
margin-top: 32px;
margin-bottom: 32px;
}
@media only screen and (min-width: 540px) {
.page {
margin-top: 64px;
margin-bottom: 64px;
}
}
/* ---- */
/* POST */
@ -474,7 +605,7 @@ table, th, td {
.content-item {
margin-bottom: 16px;
padding: 32px;
padding: 16px;
border-radius: var(--number-border-radius);
background: var(--color-content-item-background);
}
@ -484,6 +615,12 @@ table, th, td {
text-align: center;
}
@media only screen and (min-width: 540px) {
.content-item {
padding: 32px;
}
}
/* ----- */
/* PAGES */
/* ----- */

11
public/diagnostic.html Normal file
View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en-us" dir="ltr" xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Wavelovers Redirect</title>
<meta charset="UTF-8" />
<meta http-equiv="refresh" content="0; URL=https://wavelovers.ru/?diagnostic" />
</head>
<body>
</body>
</html>

View File

@ -112,7 +112,7 @@
<div class="content-item">
<h2 class="content-item__header">Troubleshooting</h2>
<span>If you are having difficulty detecting a gamepad by the browser, you can use the utility </span>
<a href="https://eugene-serb.github.io/gamepad-master/" target="_blank">Gamepad Master</a><br /><br />
<a href="https://wavelovers.ru/?diagnostic" target="_blank">Wavelovers Diagnostic</a><br /><br />
<dl>
<dt>The app does not see my device.</dt>
<dd>Make sure you have a chromium-based browser, then update the app and reconnect your device.</dd>

11
public/manual.html Normal file
View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en-us" dir="ltr" xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Wavelovers Redirect</title>
<meta charset="UTF-8" />
<meta http-equiv="refresh" content="0; URL=https://wavelovers.ru/?manual" />
</head>
<body>
</body>
</html>

View File

@ -2,25 +2,25 @@
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://wavelovers.ru/</loc>
<lastmod>2022-08-06</lastmod>
<lastmod>2022-08-09</lastmod>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://wavelovers.ru/faq.html</loc>
<lastmod>2022-08-06</lastmod>
<lastmod>2022-08-09</lastmod>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://wavelovers.ru/about.html</loc>
<lastmod>2022-08-06</lastmod>
<lastmod>2022-08-09</lastmod>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://wavelovers.ru/donate.html</loc>
<lastmod>2022-08-06</lastmod>
<lastmod>2022-08-09</lastmod>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>

View File

@ -2,7 +2,7 @@
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<sitemap>
<loc>https://wavelovers.ru/sitemap-internal.xml</loc>
<lastmod>2022-08-06</lastmod>
<lastmod>2022-08-09</lastmod>
</sitemap>
</sitemapindex>

View File

@ -1,15 +1,48 @@
<template>
<WaveloversApp />
<div class="wavelovers">
<NavigationList />
<router-view />
<GamepadList v-if="gamepads.length > 0"
:gamepads="gamepads" />
<MessageItem v-else>Press any gamepad button or connect a new gamepad to vibrate.</MessageItem>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import WaveloversApp from '@/components/WaveloversApp.vue';
import store from '@/store/index';
import NavigationList from '@/components/NavigationList.vue';
import GamepadList from '@/components/GamepadList.vue';
import MessageItem from '@/components/MessageItem.vue';
import Vibrator from '@/models/Vibrator';
export default defineComponent({
name: 'App',
components: {
WaveloversApp: WaveloversApp,
NavigationList: NavigationList,
GamepadList: GamepadList,
MessageItem: MessageItem,
},
computed: {
gamepads: function (): Vibrator[] {
return store.getters.gamepads as Vibrator[];
},
},
methods: {
addEventListeners(): void {
window.addEventListener('gamepadconnected', (event: GamepadEvent) => store.dispatch('addGamepad', event));
window.addEventListener('gamepaddisconnected', (event: GamepadEvent) => store.dispatch('deleteGamepad', event));
},
removeEventListeners(): void {
window.removeEventListener('gamepadconnected', (event: GamepadEvent) => store.dispatch('addGamepad', event));
window.removeEventListener('gamepaddisconnected', (event: GamepadEvent) => store.dispatch('deleteGamepad', event));
},
},
mounted() {
this.addEventListeners();
},
unmounted() {
this.removeEventListeners();
},
});
</script>

View File

@ -0,0 +1,50 @@
<template>
<div v-if="gamepads.length > 0" class="content-item">
<DiagnosticItem v-for="gamepad in gamepads"
:key="gamepad.id"
:gamepad="gamepad"
:timestamp="timestamp" />
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import store from '@/store/index';
import Vibrator from '@/models/Vibrator';
import DiagnosticItem from '@/components/DiagnosticItem.vue';
export default defineComponent({
name: 'AppDiagnostic',
components: {
DiagnosticItem: DiagnosticItem,
},
data: () => {
return {
timestamp: 0 as number,
interval: 0 as number,
};
},
computed: {
gamepads: function (): Vibrator[] {
const timestamp: number = this.timestamp;
const result: Vibrator[] = store.getters.gamepads as Vibrator[];
result.forEach((item) => {
item.interval = timestamp;
})
return result;
},
},
methods: {
updateTimestamp: function (): void {
this.timestamp = Date.now();
},
},
mounted() {
this.interval = setInterval(this.updateTimestamp, 1);
},
unmounted() {
clearInterval(this.interval);
},
});
</script>

View File

@ -0,0 +1,109 @@
<template>
<div class="content-item app-manual">
<fieldset class="manual-form">
<label class="manual-form__input">
<span>Start Delay (ms)</span>
<input v-model="startDelay"
type="number" placeholder="Start Delay"
min="0" max="1000" step="25" required />
</label>
<label class="manual-form__input">
<span>Duration (ms)</span>
<input v-model="duration"
type="number" placeholder="Duration"
min="0" max="1000" step="25" required />
</label>
<label class="manual-form__input">
<span>Weak Magnitude</span>
<input v-model="weakMagnitude"
type="range" placeholder="Weak Magnitude"
min="0.0" max="1.0" step="0.01" required />
</label>
<label class="manual-form__input">
<span>Strong Magnitude</span>
<input v-model="strongMagnitude"
type="range" placeholder="Strong Magnitude"
min="0.0" max="1.0" step="0.01" required />
</label>
<div class="manual-form__buttons">
<button @click="start" class="manual-form__button">Start</button>
<button @click="stop" class="manual-form__button">Stop</button>
</div>
</fieldset>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import store from '@/store/index';
import TPatternUnit from '@/models/TPatternUnit';
export default defineComponent({
name: 'AppManual',
data: () => {
return {
startDelay: 250 as number,
duration: 250 as number,
weakMagnitude: 1 as number,
strongMagnitude: 1 as number,
};
},
methods: {
createPatternUnit: function (): TPatternUnit[] {
const patternUnit: TPatternUnit[] = [{
startDelay: this.startDelay,
duration: this.duration,
weakMagnitude: this.weakMagnitude,
strongMagnitude: this.strongMagnitude,
}];
return patternUnit as TPatternUnit[];
},
start: function (): void {
store.dispatch('startCustom', this.createPatternUnit());
},
stop: function (): void {
store.dispatch('reset');
},
},
});
</script>
<style lang="scss">
.manual-form {
display: flex;
flex-direction: column-reverse;
justify-content: space-between;
gap: 16px;
}
.manual-form__input {
display: grid;
grid-template-columns: 1fr;
align-items: center;
}
.manual-form__buttons {
display: flex;
flex-direction: row;
justify-content: space-between;
gap: 32px;
}
.manual-form__button {
width: 100%;
}
@media only screen and (min-width: 540px) {
.manual-form {
display: flex;
flex-direction: column;
gap: 32px;
}
.manual-form__input {
display: grid;
grid-template-columns: 1fr 1fr;
}
}
</style>

View File

@ -0,0 +1,46 @@
<template>
<div class="app-patterns">
<PatternList v-if="patterns.length > 0"
:patterns="patterns"
:mode="mode"
:isActive="isActive"
@change="change" />
<MessageItem v-else>Loading...</MessageItem>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import store from '@/store/index';
import PatternList from '@/components/PatternList.vue';
import MessageItem from '@/components/MessageItem.vue';
import TPattern from '@/models/TPattern';
export default defineComponent({
name: 'AppPatterns',
components: {
PatternList: PatternList,
MessageItem: MessageItem,
},
computed: {
patterns: function (): TPattern[] {
return store.getters.patterns as TPattern[];
},
mode: function (): number {
return store.getters.mode as number;
},
isActive: function (): boolean {
return store.getters.isActive as boolean;
},
},
methods: {
change(index: number): void {
store.dispatch('change', index as number);
},
},
mounted() {
store.dispatch('loadPatterns');
},
});
</script>

View File

@ -0,0 +1,101 @@
<template>
<div class="output-gamepad">
<h3>#{{ gamepad.unit.index + 1 }}. {{ gamepad.unit.id }}</h3>
<div class="gamepad-group">
<div>
<span :class="[ gamepad.unit.buttons[0].value === 1 ? 'pressed' : '' ]"
>A: {{ gamepad.unit.buttons[0].value.toFixed(2) }}</span>
<span :class="[gamepad.unit.buttons[1].value === 1 ? 'pressed' : '' ]"
>B: {{ gamepad.unit.buttons[1].value.toFixed(2) }}</span>
<span :class="[ gamepad.unit.buttons[2].value === 1 ? 'pressed' : '' ]"
>X: {{ gamepad.unit.buttons[2].value.toFixed(2) }}</span>
<span :class="[ gamepad.unit.buttons[3].value === 1 ? 'pressed' : '' ]"
>Y: {{ gamepad.unit.buttons[3].value.toFixed(2) }}</span>
</div>
<div>
<span :class="[ gamepad.unit.buttons[4].value === 1 ? 'pressed' : '' ]"
>LB: {{ gamepad.unit.buttons[4].value.toFixed(2) }}</span>
<span :class="[ gamepad.unit.buttons[5].value === 1 ? 'pressed' : '' ]"
>RB: {{ gamepad.unit.buttons[5].value.toFixed(2) }}</span>
<span :class="[ gamepad.unit.buttons[6].value === 1 ? 'pressed' : '' ]"
>LT: {{ gamepad.unit.buttons[6].value.toFixed(2) }}</span>
<span :class="[ gamepad.unit.buttons[7].value === 1 ? 'pressed' : '' ]"
>RT: {{ gamepad.unit.buttons[7].value.toFixed(2) }}</span>
</div>
<div>
<span :class="[ gamepad.unit.buttons[8].value === 1 ? 'pressed' : '' ]"
>Back: {{ gamepad.unit.buttons[8].value.toFixed(2) }}</span>
<span :class="[ gamepad.unit.buttons[9].value === 1 ? 'pressed' : '' ]"
>Start: {{ gamepad.unit.buttons[9].value.toFixed(2) }}</span>
<span :class="[ gamepad.unit.buttons[10].value === 1 ? 'pressed' : '' ]"
>Left Stick: {{gamepad.unit.buttons[10].value.toFixed(2) }}</span>
<span :class="[ gamepad.unit.buttons[11].value === 1 ? 'pressed' : '' ]"
>Right Stick: {{ gamepad.unit.buttons[11].value.toFixed(2) }}</span>
</div>
<div>
<span :class="[ gamepad.unit.buttons[12].value === 1 ? 'pressed' : '' ]"
>Forward: {{ gamepad.unit.buttons[12].value.toFixed(2) }}</span>
<span :class="[ gamepad.unit.buttons[13].value === 1 ? 'pressed' : '' ]"
>Backward: {{ gamepad.unit.buttons[13].value.toFixed(2) }}</span>
<span :class="[ gamepad.unit.buttons[14].value === 1 ? 'pressed' : '' ]"
>Left: {{ gamepad.unit.buttons[14].value.toFixed(2) }}</span>
<span :class="[ gamepad.unit.buttons[15].value === 1 ? 'pressed' : '' ]"
>Right: {{ gamepad.unit.buttons[15].value.toFixed(2) }}</span>
</div>
<div>
<span>Left Stick X: {{ gamepad.unit.axes[0] ? gamepad.unit.axes[0].toFixed(2) : 'missing' }}</span>
<span>Left Stick Y: {{ gamepad.unit.axes[1] ? gamepad.unit.axes[1].toFixed(2) : 'missing' }}</span>
<span>Right Stick X: {{ gamepad.unit.axes[2] ? gamepad.unit.axes[2].toFixed(2) : 'missing' }}</span>
<span>Right Stick Y: {{ gamepad.unit.axes[3] ? gamepad.unit.axes[3].toFixed(2) : 'missing' }}</span>
</div>
</div>
<span>Vibration Actuator: {{ gamepad.unit.vibrationActuator ? 'Available' : 'missing' }}</span>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
name: 'DiagnosticItem',
props: {
gamepad: {
type: Object,
},
timestamp: {
type: Number,
},
},
});
</script>
<style lang="scss">
.output-gamepad {
width: 100%;
padding: 16px;
border: 2px solid var(--color-border);
border-radius: var(--number-border-radius);
display: flex;
flex-direction: column;
justify-content: space-between;
gap: 16px;
}
.gamepad-group {
display: grid;
grid-template-columns: repeat(5, 1fr);
}
.gamepad-group > div {
display: flex;
flex-direction: column;
justify-content: space-between;
gap: 8px;
}
.pressed {
background-color: var(--color-link-hover);
color: var(--color-background);
}
</style>

View File

@ -1,5 +1,5 @@
<template>
<div class="device-list">
<div class="content-item device-list">
<GamepadItem v-for="gamepad in gamepads"
:key="gamepad.id"
v-text="gamepad.unit.id" />
@ -25,10 +25,6 @@
<style lang="scss">
.device-list {
margin-bottom: 16px;
padding: 32px;
border-radius: var(--number-border-radius);
background: var(--color-content-item-background);
display: flex;
flex-direction: row;
justify-content: space-around;

View File

@ -1,5 +1,5 @@
<template>
<div class="message">
<div class="content-item message">
<span>
<slot></slot>
</span>
@ -17,10 +17,6 @@
<style lang="scss">
.message {
width: 100%;
margin-bottom: 16px;
padding: 32px;
border-radius: var(--number-border-radius);
background: var(--color-content-item-background);
display: flex;
flex-direction: column;
justify-content: center;

View File

@ -0,0 +1,33 @@
<template>
<div class="content-item navigation-list">
<router-link to="/manual" class="navigation-item">Manual</router-link>
<router-link to="/" class="navigation-item">Patterns</router-link>
<router-link to="/diagnostic" class="navigation-item">Diagnostic</router-link>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
name: 'NavigationList',
});
</script>
<style lang="scss">
.navigation-list {
display: flex;
flex-direction: row;
justify-content: flex-start;
gap: 16px;
}
.navigation-item.router-link-active,
.navigation-item.router-link-exact-active {
border-bottom: 2px solid var(--color-link-hover);
color: var(--color-link-hover);
transition: all 0.5s ease;
text-decoration: none;
}
</style>

View File

@ -6,8 +6,12 @@
]">
<span class="pattern-item__icon"
v-text="pattern.icon"></span>
<div class="pattern-item__info-container">
<span class="pattern-item__name"
v-text="pattern.name"></span>
<span class="pattern-item__type"
v-text="pattern.type"></span>
</div>
</div>
</template>
@ -41,18 +45,18 @@
<style lang="scss">
.pattern-item {
width: 100%;
height: 48px;
height: 50px;
padding: 8px;
border-radius: var(--number-border-radius);
background: var(--color-pattern-button);
display: flex;
flex-direction: row;
justify-content: flex-start;
gap: 16px;
gap: 8px;
align-items: center;
text-align: center;
overflow: hidden;
cursor: default;
cursor: pointer;
}
@media only screen and (min-width: 540px) {
@ -73,8 +77,22 @@
font-size: 24px;
}
.pattern-item__info-container {
display: flex;
flex-direction: column;
justify-content: space-between;
text-align: left;
}
.pattern-item__name {
font-size: 14px;
font-size: 16px;
white-space: nowrap;
overflow: hidden;
color: var(--color-pattern-text);
}
.pattern-item__type {
font-size: 12px;
white-space: nowrap;
overflow: hidden;
color: var(--color-pattern-text);

View File

@ -1,5 +1,5 @@
<template>
<div class="pattern-list">
<div class="content-item pattern-list">
<PatternItem v-for="(pattern, index) in patterns"
:key="pattern.name"
:pattern="pattern"
@ -40,15 +40,18 @@
<style lang="scss">
.pattern-list {
margin-bottom: 16px;
padding: 32px;
border-radius: var(--number-border-radius);
background: var(--color-content-item-background);
display: flex;
flex-direction: row;
justify-content: space-around;
flex-wrap: wrap;
gap: 16px;
}
@media only screen and (min-width: 540px) {
.pattern-list {
display: flex;
gap: 32px;
}
}
</style>

View File

@ -1,82 +0,0 @@
<template>
<div class="wavelovers">
<PatternList v-if="patterns.length > 0"
:patterns="patterns"
:mode="mode"
:isActive="isActive"
@change="change" />
<MessageItem v-else>Loading...</MessageItem>
<GamepadList v-if="gamepads.length > 0"
:gamepads="gamepads" />
<MessageItem v-else>Press any gamepad button or connect a new gamepad to vibrate.</MessageItem>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import PatternList from '@/components/PatternList.vue';
import GamepadList from '@/components/GamepadList.vue';
import MessageItem from '@/components/MessageItem.vue';
import TPattern from '@/models/TPattern';
import Vibrator from '@/models/Vibrator';
import store from '@/store/index';
export default defineComponent({
name: 'WaveloversApp',
components: {
PatternList: PatternList,
GamepadList: GamepadList,
MessageItem: MessageItem,
},
computed: {
gamepads: function (): Vibrator[] {
return store.getters.gamepads as Vibrator[];
},
patterns: function (): TPattern[] {
return store.getters.patterns as TPattern[];
},
mode: function (): number {
return store.getters.mode as number;
},
isActive: function (): boolean {
return store.getters.isActive as boolean;
},
},
methods: {
addEventListeners(): void {
window.addEventListener('gamepadconnected', (event: GamepadEvent) => store.dispatch('addGamepad', event));
window.addEventListener('gamepaddisconnected', (event: GamepadEvent) => store.dispatch('deleteGamepad', event));
},
removeEventListeners(): void {
window.removeEventListener('gamepadconnected', (event: GamepadEvent) => store.dispatch('addGamepad', event));
window.removeEventListener('gamepaddisconnected', (event: GamepadEvent) => store.dispatch('deleteGamepad', event));
},
change(index: number): void {
store.dispatch('change', index as number);
},
},
mounted() {
store.dispatch('loadPatterns');
this.addEventListeners();
},
unmounted() {
this.removeEventListeners();
},
});
</script>
<style lang="scss">
.wavelovers {
display: flex;
flex-direction: column-reverse;
justify-content: flex-start;
gap: 16px;
}
@media only screen and (min-width: 540px) {
.wavelovers {
flex-direction: column;
}
}
</style>

View File

@ -1,5 +1,7 @@
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';
createApp(App).use(store).mount('#app');
createApp(App).use(store).use(router).mount('#app');

View File

@ -1,10 +1,14 @@
import IVibrationActuator from '@/models/IVibrationActuator';
import IGamepadButton from '@/models/IGamepadButton';
interface IGamepad {
id: string;
index: number;
timestamp: number;
connected: boolean;
readonly id: string;
readonly index: number;
readonly timestamp: number;
readonly connected: boolean;
readonly mapping: string;
readonly axes: number[];
readonly buttons: IGamepadButton[];
vibrationActuator: IVibrationActuator;
}

View File

@ -0,0 +1,8 @@
interface IGamepadButton {
readonly pressed: boolean;
readonly touched: boolean;
readonly value: number;
}
export default IGamepadButton;

View File

@ -1,7 +1,7 @@
import IGamepad from '@/models/IGamepad';
interface IGamepadEvent {
gamepad: IGamepad;
readonly gamepad: IGamepad;
}
export default IGamepadEvent;

View File

@ -1,7 +1,7 @@
import TPatternUnit from '@/models/TPatternUnit';
interface IVibrationActuator {
type: string;
readonly type: string;
reset(): void;
playEffect(mode: string, pattern: TPatternUnit): void;
}

View File

@ -6,7 +6,7 @@ interface IVibrator {
readonly canVibrate: boolean;
isVibrating: boolean;
unit: IGamepad;
pattern: TPatternUnit[];
interval: number;
update(): void;
reset(): void;
vibrate(pattern: TPatternUnit[]): void;

View File

@ -7,19 +7,20 @@ class Vibrator implements IVibrator {
readonly canVibrate: boolean;
isVibrating: boolean;
unit: IGamepad;
pattern: TPatternUnit[];
interval: number;
constructor(unit: IGamepad) {
this.unit = unit;
this.id = Date.now();
this.canVibrate = (this.unit.vibrationActuator) ? true : false;
this.isVibrating = false;
this.pattern = [];
this.update = this.update.bind(this);
this.interval = setInterval(this.update, 1);
}
update(): void {
const gamepads = navigator.getGamepads();
this.unit = <IGamepad><unknown>gamepads[this.unit.index];
this.unit = gamepads[this.unit.index] as unknown as IGamepad;
}
reset(): void {
@ -29,13 +30,12 @@ class Vibrator implements IVibrator {
async vibrate(pattern: TPatternUnit[]) {
this.isVibrating = true;
this.pattern = pattern;
const offsetTime = 10;
while (this.isVibrating === true) {
for (let i = 0; i < this.pattern.length; i++) {
for (let i = 0; i < pattern.length; i++) {
if (this.isVibrating === true) {
this.unit.vibrationActuator.playEffect('dual-rumble', this.pattern[i]);
await this.sleep(this.pattern[i].startDelay + this.pattern[i].duration);
this.unit.vibrationActuator.playEffect('dual-rumble', pattern[i]);
await this.sleep(pattern[i].startDelay + pattern[i].duration - offsetTime);
} else {
return;
}

37
src/router/index.ts Normal file
View File

@ -0,0 +1,37 @@
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';
import PatternsView from '@/views/PatternsView.vue';
const routes: Array<RouteRecordRaw> = [
{
path: '/',
name: 'patterns-view',
component: PatternsView,
},
{
path: '/manual',
name: 'manual-view',
component: () => import('@/views/ManualView.vue'),
},
{
path: '/diagnostic',
name: 'diagnostic-view',
component: () => import('@/views/DiagnosticView.vue'),
},
{
path: '/404',
name: '404',
component: () => import('@/views/NotFoundView.vue'),
},
{
path: '/:catchAll(.*)',
redirect: '/404',
},
];
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes,
});
export default router;

9
src/shims-vue.d.ts vendored
View File

@ -1,6 +1,7 @@
/* eslint-disable */
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}
import type { DefineComponent } from 'vue';
const component: DefineComponent<{}, {}, any>;
export default component;
};

View File

@ -2,6 +2,7 @@ import { createStore, Store } from 'vuex';
import IRootState from './models/IRootState';
import MGamepads from '@/store/modules/MGamepads';
import MPatterns from '@/store/modules/MPatterns';
import TPatternUnit from '../models/TPatternUnit';
const store: Store<IRootState> = createStore({
state: () => ({
@ -25,16 +26,10 @@ const store: Store<IRootState> = createStore({
},
},
actions: {
setMode: function (
context,
index: number
): void {
setMode: function (context, index: number): void {
context.commit('setMode', index as number);
},
setIsActive: function (
context,
isActive: boolean
): void {
setIsActive: function (context, isActive: boolean): void {
context.commit('setIsActive', isActive as boolean);
},
change: function (context, index: number): void {
@ -46,11 +41,20 @@ const store: Store<IRootState> = createStore({
}
if (context.getters.isActive === true) {
context.dispatch('reset');
context.dispatch('vibrate');
context.dispatch(
'vibrate',
context.getters.patterns[context.getters.mode].pattern
);
} else {
context.dispatch('reset');
}
},
startCustom: function (context, pattern: TPatternUnit[]): void {
context.dispatch('setIsActive', false);
context.dispatch('setMode', 0);
context.dispatch('reset');
context.dispatch('vibrate', pattern);
},
},
modules: {
MGamepads: MGamepads,

View File

@ -46,10 +46,11 @@ const MGamepads: Module<IGamepadsState, IRootState> = {
});
},
vibrate: function (
context: ActionContext<IGamepadsState, IRootState>
context: ActionContext<IGamepadsState, IRootState>,
pattern: TPatternUnit[]
): void {
context.getters.gamepads.forEach((gamepad: Vibrator) => {
gamepad.vibrate(context.getters.patterns[context.getters.mode].pattern as TPatternUnit[]);
gamepad.vibrate(pattern);
});
},
reset: function (

View File

@ -0,0 +1,16 @@
<template>
<AppDiagnostic />
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import AppDiagnostic from '@/components/AppDiagnostic.vue';
export default defineComponent({
name: 'DiagnosticView',
components: {
AppDiagnostic: AppDiagnostic,
},
});
</script>

16
src/views/ManualView.vue Normal file
View File

@ -0,0 +1,16 @@
<template>
<AppManual />
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import AppManual from '@/components/AppManual.vue';
export default defineComponent({
name: 'ManualView',
components: {
AppManual: AppManual,
},
});
</script>

View File

@ -0,0 +1,16 @@
<template>
<div class="content-item">
<center>
<h2>404. Page not Found...</h2>
</center>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
name: 'NotFoundView',
});
</script>

View File

@ -0,0 +1,16 @@
<template>
<AppPatterns />
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import AppPatterns from '@/components/AppPatterns.vue';
export default defineComponent({
name: 'PatternsView',
components: {
AppPatterns: AppPatterns,
},
});
</script>

View File

@ -38,3 +38,4 @@
"node_modules"
]
}

View File

@ -1,4 +1,5 @@
const { defineConfig } = require('@vue/cli-service')
const { defineConfig } = require('@vue/cli-service');
module.exports = defineConfig({
transpileDependencies: true
})
transpileDependencies: true,
});