museria 0.2.49 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/.eslintrc +10 -2
  2. package/.github/workflows/build.yml +3 -3
  3. package/.github/workflows/publish.yml +3 -3
  4. package/README.md +55 -59
  5. package/bin/actions.js +28 -28
  6. package/bin/index.js +4 -4
  7. package/bin/runner.js +1 -1
  8. package/bin/utils.js +6 -2
  9. package/dist/client/museria.client.js +7 -7
  10. package/dist/face/45a265d0f07b31cde85f.ttf +0 -0
  11. package/dist/face/6205fd00fb1b573e9f0f.ttf +0 -0
  12. package/dist/face/8d3cabfc66809162fb4d.woff2 +0 -0
  13. package/dist/face/fb8184add5a3101ad0a3.woff2 +0 -0
  14. package/dist/face/museria.face.js +33 -13
  15. package/dist/face/style.css +13 -11
  16. package/package.json +41 -40
  17. package/src/browser/client/index.js +2 -1
  18. package/src/browser/face/client.js +2 -1
  19. package/src/browser/face/controllers/app/app.html +77 -69
  20. package/src/browser/face/controllers/app/app.js +14 -7
  21. package/src/browser/face/controllers/app/app.scss +2 -22
  22. package/src/browser/face/index.js +3 -3
  23. package/src/browser/face/styles/main.scss +91 -11
  24. package/src/browser/face/styles/vars.scss +0 -1
  25. package/src/client.js +73 -74
  26. package/src/collection/transports/music/index.js +20 -18
  27. package/src/db/transports/database/index.js +7 -5
  28. package/src/db/transports/loki/index.js +30 -25
  29. package/src/errors.js +2 -1
  30. package/src/index.js +8 -6
  31. package/src/node.js +312 -323
  32. package/src/schema.js +27 -29
  33. package/src/server/transports/express/api/butler/controllers.js +7 -10
  34. package/src/server/transports/express/api/butler/routes.js +5 -5
  35. package/src/server/transports/express/api/master/controllers.js +7 -10
  36. package/src/server/transports/express/api/master/routes.js +5 -5
  37. package/src/server/transports/express/api/node/controllers.js +52 -61
  38. package/src/server/transports/express/api/node/routes.js +10 -10
  39. package/src/server/transports/express/api/routes.js +1 -1
  40. package/src/server/transports/express/api/slave/controllers.js +7 -10
  41. package/src/server/transports/express/api/slave/routes.js +6 -6
  42. package/src/server/transports/express/client/controllers.js +40 -61
  43. package/src/server/transports/express/client/routes.js +33 -39
  44. package/src/server/transports/express/controllers.js +10 -21
  45. package/src/server/transports/express/index.js +23 -20
  46. package/src/server/transports/express/midds.js +67 -67
  47. package/src/server/transports/express/routes.js +12 -12
  48. package/src/utils.js +175 -184
  49. package/test/client.js +311 -305
  50. package/test/db/database.js +32 -28
  51. package/test/db/loki.js +78 -74
  52. package/test/group.js +161 -156
  53. package/test/index.js +20 -10
  54. package/test/node.js +461 -460
  55. package/test/routes.js +404 -399
  56. package/test/server/express.js +35 -31
  57. package/test/services.js +25 -18
  58. package/test/tools.js +8 -6
  59. package/test/utils.js +236 -234
  60. package/webpack.client.js +9 -7
  61. package/webpack.face.js +8 -6
  62. package/dist/face/fa-brands-400.eot +0 -0
  63. package/dist/face/fa-brands-400.svg +0 -3717
  64. package/dist/face/fa-brands-400.ttf +0 -0
  65. package/dist/face/fa-brands-400.woff +0 -0
  66. package/dist/face/fa-brands-400.woff2 +0 -0
  67. package/dist/face/fa-solid-900.eot +0 -0
  68. package/dist/face/fa-solid-900.svg +0 -5034
  69. package/dist/face/fa-solid-900.ttf +0 -0
  70. package/dist/face/fa-solid-900.woff +0 -0
  71. package/dist/face/fa-solid-900.woff2 +0 -0
  72. /package/dist/face/{open-sans.ttf → 17e98b9e5586529b13cc.ttf} +0 -0
  73. /package/dist/face/{proxima-nova.ttf → 326601dfabd91e3f016c.ttf} +0 -0
  74. /package/dist/face/{logo.svg → ee9c6af64aa224827cec.svg} +0 -0
package/package.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "name": "museria",
3
- "version": "0.2.49",
3
+ "version": "0.3.2",
4
4
  "description": "Decentralized music storage",
5
5
  "main": "./src/index.js",
6
+ "type": "module",
6
7
  "bin": {
7
8
  "museria": "./bin/index.js"
8
9
  },
@@ -41,59 +42,59 @@
41
42
  ],
42
43
  "license": "MIT",
43
44
  "devDependencies": {
44
- "@babel/core": "^7.13.15",
45
- "@babel/eslint-parser": "^7.13.14",
46
- "@babel/plugin-transform-runtime": "^7.13.15",
47
- "@babel/preset-env": "^7.13.15",
48
- "babel-loader": "^8.2.2",
49
- "babel-preset-akili": "^2.0.4",
50
- "chai": "^4.2.0",
45
+ "@babel/core": "^7.23.7",
46
+ "@babel/eslint-parser": "^7.23.3",
47
+ "@babel/plugin-transform-runtime": "^7.23.7",
48
+ "@babel/preset-env": "^7.23.8",
49
+ "babel-loader": "^9.1.3",
50
+ "babel-preset-akili": "^2.0.8",
51
+ "chai": "^5.0.0",
51
52
  "cross-env": "^7.0.3",
52
- "css-loader": "^5.0.0",
53
- "css-minimizer-webpack-plugin": "^3.0.2",
54
- "eslint": "^7.0.0",
55
- "eslint-webpack-plugin": "^2.5.3",
56
- "file-loader": "^6.2.0",
57
- "html-loader": "^2.1.2",
58
- "husky": "^4.3.6",
59
- "mini-css-extract-plugin": "^1.3.9",
53
+ "css-loader": "^6.9.0",
54
+ "css-minimizer-webpack-plugin": "^5.0.1",
55
+ "eslint": "^8.56.0",
56
+ "eslint-webpack-plugin": "^4.0.1",
57
+ "html-loader": "^5.0.0",
58
+ "husky": "^4.0.3",
59
+ "mini-css-extract-plugin": "^2.7.7",
60
60
  "mocha": "^10.2.0",
61
- "node-polyfill-webpack-plugin": "^1.0.3",
61
+ "node-polyfill-webpack-plugin": "^3.0.0",
62
62
  "resolve-url-loader": "^5.0.0",
63
- "sass": "^1.43.4",
64
- "sass-loader": "^12.3.0",
65
- "terser-webpack-plugin": "^5.0.0",
66
- "webpack": "^5.31.0",
67
- "webpack-cli": "^4.6.0",
68
- "yargs": "^17.0.0"
63
+ "sass": "^1.69.7",
64
+ "sass-loader": "^14.0.0",
65
+ "terser-webpack-plugin": "^5.3.10",
66
+ "webpack": "^5.89.0",
67
+ "webpack-cli": "^5.1.4"
69
68
  },
70
69
  "dependencies": {
71
- "@fortawesome/fontawesome-free": "^5.15.0",
72
- "akili": "^1.2.22",
70
+ "@fortawesome/fontawesome-free": "^6.5.1",
71
+ "akili": "1.2.37",
73
72
  "base64url": "^3.0.1",
74
- "bootstrap": "^4.5.3",
75
- "chalk": "^4.1.2",
73
+ "bootstrap": "^5.0.0",
74
+ "chalk": "^5.3.0",
76
75
  "emoji-strip": "^1.0.1",
77
- "express": "^4.17.1",
78
- "fs-extra": "^9.0.1",
79
- "lodash": "^4.17.20",
80
- "metastocle": "^0.2.32",
81
- "music-metadata": "^7.13.0",
82
- "node-fetch": "^2.6.1",
83
- "node-id3": "^0.2.2",
76
+ "express": "^4.18.2",
77
+ "fs-extra": "^11.2.0",
78
+ "hasha": "^5.0.0",
79
+ "lodash-es": "^4.17.21",
80
+ "metastocle": "~0.3.10",
81
+ "music-metadata": "^7.14.0",
82
+ "node-fetch": "^3.3.2",
83
+ "node-id3": "^0.2.6",
84
84
  "sanitize-filename": "^1.6.3",
85
85
  "serve-favicon": "^2.5.0",
86
- "sharp": "^0.30.0",
87
- "splaytree": "^3.1.0",
88
- "spreadable": "^0.2.28",
89
- "storacle": "^0.2.28",
90
- "transliteration": "^2.2.0"
86
+ "sharp": "^0.33.2",
87
+ "splaytree": "^3.1.2",
88
+ "spreadable": "~0.3.10",
89
+ "storacle": "~0.3.6",
90
+ "transliteration": "^2.3.5",
91
+ "yargs": "^17.7.2"
91
92
  },
92
93
  "repository": {
93
94
  "type": "git",
94
95
  "url": "https://github.com/ortexx/museria"
95
96
  },
96
97
  "engines": {
97
- "node": ">=10.13.0"
98
+ "node": ">=20.0.0"
98
99
  }
99
100
  }
@@ -1 +1,2 @@
1
- module.exports = require('../../client')();
1
+ import client from "../../client.js";
2
+ export default client();
@@ -1,3 +1,4 @@
1
- import ClientMuseria from '../../../dist/client/museria.client.js';
1
+ import clientMuseria from "../../client.js";
2
+ const ClientMuseria = clientMuseria();
2
3
  const client = new ClientMuseria();
3
4
  export default client;
@@ -62,7 +62,7 @@
62
62
  </a>
63
63
  </header>
64
64
  <div class="content">
65
- <div class="row pt-5 pb-3">
65
+ <div class="row px-4 px-sm-5 pt-5 pb-3">
66
66
  <div class="song-search col-lg-6 col-12 pl-5 pr-5 pr-lg-4 pt-4">
67
67
  <div class="song-search-input input-group input-group-lg">
68
68
  <i hidden="${ this.isFinding }" class="fas fa-search fa-lg"></i>
@@ -135,42 +135,48 @@
135
135
  <div class="invalid-feedback">Title must be like "Artist - Title"</div>
136
136
  </div>
137
137
  <div class="form-group mt-3 w-100">
138
- <div class="custom-file position-relative">
138
+ <div class="custom-file input-group position-relative">
139
139
  <input
140
140
  type="file"
141
- class="${ utils.class({ 'custom-file-input': true, 'is-invalid': this.uploadFormFails.cover }) }"
141
+ class="form-control ${ utils.class({ 'is-invalid': this.uploadFormFails.cover }) }"
142
142
  id="cover-file"
143
143
  on-change="${ this.prepareCover(event.target.files[0]) }"
144
144
  accept="image/jpeg,image/png"
145
145
  >
146
- <div class="invalid-feedback">Cover must be "jpeg" or "png"</div>
146
+ <button class="btn btn-outline-secondary px-3" type="button" id="cover-file-button">Browse</button>
147
147
  <img
148
148
  hidden="${ !this.songUploadInfo.cover }"
149
149
  url="${ this.songUploadInfo.cover }"
150
150
  class="cover-img"
151
151
  >
152
152
  <label
153
- class="custom-file-label ${ utils.class({'cover-label': true, 'with-img': !!this.songUploadInfo.cover}) }"
153
+ class="custom-file-label input-group-text ${ utils.class({'cover-label': true, 'with-img': !!this.songUploadInfo.cover}) }"
154
154
  for="cover-file">
155
155
  ${ this.songUploadInfo.cover? 'Cover is chosen': 'Choose a cover file' }
156
- </label>
156
+ </label>
157
157
  <i
158
158
  hidden="${ !this.songUploadInfo.cover }"
159
159
  on-click="${ this.removeCover() }"
160
160
  class="close-fa cover-remove fas fa-times fa-lg"
161
161
  title="remove the cover"></i>
162
162
  </div>
163
+ <div
164
+ class="invalid-feedback"
165
+ style="display: ${ this.uploadFormFails.cover? 'block': 'none' };"
166
+ >
167
+ Cover must be "jpeg" or "png"
168
+ </div>
163
169
  </div>
164
170
  <div class="form-group mt-3 w-100">
165
- <div class="custom-control custom-checkbox my-1 mr-sm-2">
171
+ <div class="form-check my-1 mr-sm-2">
166
172
  <input
167
173
  type="checkbox"
168
- class="custom-control-input"
174
+ class="form-check-input"
169
175
  id="songHighPriorityCheckbox"
170
176
  checked="${ this.songUploadInfo.controlled }"
171
177
  on-change="${ this.songUploadInfo.controlled = event.target.checked }"
172
178
  >
173
- <label class="custom-control-label" for="songHighPriorityCheckbox">
179
+ <label class="form-check-label" for="songHighPriorityCheckbox">
174
180
  Moderation mode (optional)
175
181
  </label>
176
182
  </div>
@@ -183,17 +189,17 @@
183
189
  on-radio="${ this.songUploadInfo.priority = event.detail }"
184
190
  class="d-flex song-priority"
185
191
  >
186
- <div class="custom-control custom-radio pr-4">
187
- <input type="radio" class="custom-control-input" id="songLowPriority" value="-1">
188
- <label class="custom-control-label" for="songLowPriority">Low priority</label>
192
+ <div class="form-check form-check-inline pr-4">
193
+ <input type="radio" class="form-check-input" id="songLowPriority" value="-1">
194
+ <label class="form-check-label" for="songLowPriority">Low priority</label>
189
195
  </div>
190
- <div class="custom-control custom-radio pr-4">
191
- <input type="radio" class="custom-control-input" id="songNormalPriority" value="0">
192
- <label class="custom-control-label" for="songNormalPriority">Normal priority</label>
196
+ <div class="form-check form-check-inline pr-4">
197
+ <input type="radio" class="form-check-input" id="songNormalPriority" value="0">
198
+ <label class="form-check-label" for="songNormalPriority">Normal priority</label>
193
199
  </div>
194
- <div class="custom-control custom-radio">
195
- <input type="radio" class="custom-control-input" id="songHighPriority" value="1">
196
- <label class="custom-control-label" for="songHighPriority">High priority</label>
200
+ <div class="form-check form-check-inline">
201
+ <input type="radio" class="form-check-input" id="songHighPriority" value="1">
202
+ <label class="form-check-label" for="songHighPriority">High priority</label>
197
203
  </div>
198
204
  </radio>
199
205
  </div>
@@ -209,10 +215,10 @@
209
215
  </div>
210
216
  </div>
211
217
  </div>
212
- <div class="container py-5">
218
+ <div class="container py-4">
213
219
  <div class="row px-2 pb-5">
214
220
  <div class="col-12 text-center">
215
- <ul class="questions">
221
+ <ul class="questions px-0">
216
222
  <li>
217
223
  <div>What is this?</div>
218
224
  <div>It is a decentralized music storage node.</div>
@@ -261,56 +267,58 @@
261
267
  </div>
262
268
  </div>
263
269
  <footer class="footer row">
264
- <div class="container">
265
- <div class="row px-4">
266
- <div class="col-xl-4 col-lg-6 mt-4 px-0 footer-contacts">
267
- <h5>Contacts</h5>
268
- <ul class="flex-column nav">
269
- <li>
270
- <i class="fas fa-envelope" aria-hidden="true"></i>
271
- <a href="mailto:storage@museria.com" target="_blank">
272
- <span class="pl-1">storage@museria.com</span>
273
- </a>
274
- </li>
275
- <li>
276
- <i class="fab fa-github" aria-hidden="true"></i>
277
- <a href="https://github.com/ortexx/" target="_blank">
278
- <span class="pl-1">ortexx</span>
279
- </a>
280
- </li>
281
- </ul>
282
- </div>
283
- <div class="col-xl-4 col-lg-6 mt-4 px-0">
284
- <h5>Information</h5>
285
- <ul class="flex-column nav">
286
- <li>
287
- <i class="fas fa-book-open" aria-hidden="true"></i>
288
- <a href="https://github.com/ortexx/museria/" target="_blank">Documentation</a>
289
- </li>
290
- <li>
291
- <i class="fas fa-globe" aria-hidden="true"></i>
292
- <a href="https://github.com/ortexx/museria-global/" target="_blank">Global network</a>
293
- </li>
294
- <li>
295
- <i class="fas fa-play-circle" aria-hidden="true"></i>
296
- <a href="https://github.com/ortexx/musiphone/" target="_blank">Decentralized player</a>
297
- </li>
298
- </ul>
299
- </div>
300
- <div class="col-xl-4 col-lg-6 mt-4 px-0">
301
- <h5>Donate</h5>
302
- <ul class="flex-column nav">
303
- <li>
304
- <i class="fab fa-btc" aria-hidden="true"></i>
305
- <span>38dyvCmUadqS2HVFEuDBVC3k1a7h6J5gqU</span>
306
- </li>
307
- <li>
308
- <i class="fab fa-ethereum" aria-hidden="true"></i>
309
- <span>0x4e5Ef1b362271523f5c6eDe7a54BDcA9750D81E8</span>
310
- </li>
311
- </ul>
270
+ <div>
271
+ <div class="container">
272
+ <div class="row px-4">
273
+ <div class="col-xl-4 col-lg-6 mt-4 px-0 footer-contacts">
274
+ <h5>Contacts</h5>
275
+ <ul class="flex-column nav">
276
+ <li>
277
+ <i class="fas fa-envelope" aria-hidden="true"></i>
278
+ <a href="mailto:storage@museria.com" target="_blank">
279
+ <span class="pl-1">storage@museria.com</span>
280
+ </a>
281
+ </li>
282
+ <li>
283
+ <i class="fab fa-github" aria-hidden="true"></i>
284
+ <a href="https://github.com/ortexx/" target="_blank">
285
+ <span class="pl-1">ortexx</span>
286
+ </a>
287
+ </li>
288
+ </ul>
289
+ </div>
290
+ <div class="col-xl-4 col-lg-6 mt-4 px-0">
291
+ <h5>Information</h5>
292
+ <ul class="flex-column nav">
293
+ <li>
294
+ <i class="fas fa-book-open" aria-hidden="true"></i>
295
+ <a href="https://github.com/ortexx/museria/" target="_blank">Documentation</a>
296
+ </li>
297
+ <li>
298
+ <i class="fas fa-globe" aria-hidden="true"></i>
299
+ <a href="https://github.com/ortexx/museria-global/" target="_blank">Global network</a>
300
+ </li>
301
+ <li>
302
+ <i class="fas fa-play-circle" aria-hidden="true"></i>
303
+ <a href="https://github.com/ortexx/musiphone/" target="_blank">Decentralized player</a>
304
+ </li>
305
+ </ul>
306
+ </div>
307
+ <div class="col-xl-4 col-lg-6 mt-4 px-0">
308
+ <h5>Donate</h5>
309
+ <ul class="flex-column nav">
310
+ <li>
311
+ <i class="fab fa-btc" aria-hidden="true"></i>
312
+ <span>38dyvCmUadqS2HVFEuDBVC3k1a7h6J5gqU</span>
313
+ </li>
314
+ <li>
315
+ <i class="fab fa-ethereum" aria-hidden="true"></i>
316
+ <span>0x4e5Ef1b362271523f5c6eDe7a54BDcA9750D81E8</span>
317
+ </li>
318
+ </ul>
319
+ </div>
312
320
  </div>
313
321
  </div>
314
- </div>
322
+ </div>
315
323
  </footer>
316
324
  </div>
@@ -1,10 +1,11 @@
1
1
  import './app.scss';
2
2
  import Akili from 'akili';
3
- import router from 'akili/src/services/router';
4
- import client from '../../client';
3
+ import router from 'akili/src/services/router.js';
4
+ import client from '../../client.js';
5
+ import template from './app.html';
5
6
 
6
7
  export default class App extends Akili.Component {
7
- static template = require('./app.html');
8
+ static template = template;
8
9
 
9
10
  static define() {
10
11
  Akili.component('app', this);
@@ -171,22 +172,28 @@ export default class App extends Akili.Component {
171
172
  if(!file) {
172
173
  return;
173
174
  }
174
-
175
+
176
+ if(!file.type.match('image')) {
177
+ this.scope.uploadFormFails.cover = true;
178
+ return;
179
+ }
180
+
175
181
  this.scope.songUploadInfo.coverFile = file;
176
182
  this.scope.songUploadInfo.cover = URL.createObjectURL(file)
177
183
  this.scope.songUploadInfo.fileChanged = true;
184
+ this.scope.uploadFormFails.cover = '';
178
185
  }
179
186
 
180
187
  async removeCover() {
181
188
  this.resetCover();
182
- this.scope.songUploadInfo.fileChanged = true;
189
+ this.scope.songUploadInfo.fileChanged = true;
183
190
  }
184
191
 
185
192
  async resetCover() {
186
- this.scope.uploadFormFails.cover = '';
187
193
  this.scope.songUploadInfo.cover = '';
188
194
  this.scope.songUploadInfo.coverFile = null;
189
- this.scope.uploadFormFails.cover && URL.revokeObjectURL(this.scope.uploadFormFails.cover);
195
+ this.scope.uploadFormFails.cover && URL.revokeObjectURL(this.scope.uploadFormFails.cover);
196
+ this.scope.uploadFormFails.cover = '';
190
197
  }
191
198
 
192
199
  async uploadSong(failed = false) {
@@ -111,6 +111,7 @@
111
111
  text-transform: uppercase;
112
112
  font-weight: bold;
113
113
  text-align: center;
114
+ max-width: 50%;
114
115
 
115
116
  & b {
116
117
  color: $light;
@@ -123,7 +124,7 @@
123
124
  text-transform: uppercase;
124
125
  font-weight: bold;
125
126
  text-decoration: none;
126
-
127
+ width: unset;
127
128
 
128
129
  &-img {
129
130
  display: inline-block;
@@ -250,27 +251,6 @@
250
251
  }
251
252
  }
252
253
 
253
- .cover-img {
254
- object-fit: cover;
255
- height: 2.22em;
256
- width: 2.22em;
257
- position: absolute;
258
- left: 2px;
259
- top: 1px;
260
- z-index: 2;
261
- pointer-events: none;
262
- }
263
-
264
- .cover-remove {
265
- right: 4.5em;
266
- }
267
-
268
- .cover-label {
269
- &.with-img {
270
- padding-left: 3em;
271
- }
272
- }
273
-
274
254
  .upload-preloader-btn {
275
255
  & i {
276
256
  margin-left: 0.3em;
@@ -1,8 +1,8 @@
1
1
  import './styles/main.scss';
2
2
  import Akili from 'akili';
3
- import router from 'akili/src/services/router';
4
- import App from './controllers/app/app';
5
- import client from './client';
3
+ import router from 'akili/src/services/router.js';
4
+ import App from './controllers/app/app.js';
5
+ import client from './client.js';
6
6
 
7
7
  App.define();
8
8
 
@@ -27,35 +27,109 @@ body {
27
27
  color: $pale;
28
28
  }
29
29
 
30
- .custom-file input {
31
- cursor: pointer;
32
- text-indent: -1000px;
33
- }
30
+ .custom-file {
31
+ .cover-img {
32
+ object-fit: cover;
33
+ height: 2.22em;
34
+ width: 2.22em;
35
+ position: absolute;
36
+ left: 2px;
37
+ top: 1px;
38
+ z-index: 2;
39
+ pointer-events: none;
40
+ }
34
41
 
35
- .custom-control-label {
36
- cursor: pointer;
37
- opacity: 0.8;
42
+ .cover-remove {
43
+ right: 5em;
44
+ margin-top: 1px;
45
+ }
38
46
 
39
- &:hover {
40
- opacity: 1;
47
+ .cover-label {
48
+ position: absolute;
49
+ background: none;
50
+ border: none;
51
+
52
+ &.with-img {
53
+ padding-left: 3em;
54
+ }
41
55
  }
56
+
57
+ & input {
58
+ cursor: pointer;
59
+ text-indent: -1000px;
60
+ z-index: 0 !important;
61
+
62
+ &:focus + .btn {
63
+ border-color: $green;
64
+ }
65
+
66
+ &.is-invalid {
67
+ background-image: unset !important;
68
+
69
+ &+ .btn {
70
+ border-color: $red !important;
71
+ }
72
+ }
73
+ }
74
+
75
+ & .btn {
76
+ position: absolute;
77
+ right: 0;
78
+ height: 100%;
79
+ pointer-events: none;
80
+ color: $light;
81
+ text-transform: none;
82
+ font-weight: normal;
83
+ }
84
+ }
85
+
86
+ .form-check-input {
87
+ &[type=checkbox] {
88
+ border-radius: 2px;
89
+ }
90
+
91
+ &, & + .form-check-label {
92
+ cursor: pointer;
93
+ opacity: 0.8;
94
+
95
+ &:hover {
96
+ opacity: 1;
97
+ }
98
+ }
99
+
100
+ &:focus, &:active {
101
+ outline: none !important;
102
+ box-shadow: none !important;
103
+ }
42
104
  }
43
105
 
44
106
  .btn {
45
- padding: 0;
107
+ padding: 0.33em;
46
108
  text-transform: uppercase;
47
109
  font-weight: bold;
110
+ color: white;
48
111
 
49
112
  &:focus, &:active {
50
113
  outline: none !important;
51
114
  box-shadow: none !important;
52
- }
115
+ color: white;
116
+ }
117
+
118
+ &:hover {
119
+ color: white;
120
+ }
53
121
 
54
122
  &[disabled] {
55
123
  cursor: not-allowed;
56
124
  }
57
125
  }
58
126
 
127
+ .btn-primary {
128
+ &:focus, &:active, &:active:focus, &:hover {
129
+ background: $green !important;
130
+ }
131
+ }
132
+
59
133
  a {
60
134
  color: $pale;
61
135
  text-decoration: underline;
@@ -66,6 +140,12 @@ a {
66
140
  }
67
141
  }
68
142
 
143
+ input.form-control {
144
+ &::placeholder {
145
+ color: $gray;
146
+ }
147
+ }
148
+
69
149
  .input-group-lg input[type=text] {
70
150
  padding: 0.42rem 1rem 0.45rem 1rem;
71
151
  height: auto;
@@ -29,4 +29,3 @@ $input-focus-box-shadow: none;
29
29
  $input-disabled-bg: $dark;
30
30
  $custom-file-button-bg: $dark;
31
31
  $custom-file-button-color: $light;
32
-