notherbase-fs 3.1.4 → 3.1.6

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.
@@ -1,5 +1,10 @@
1
1
  import nodemailer from "nodemailer";
2
2
 
3
+ /**
4
+ * Sends an email with a password reset code. WIP
5
+ * @param {String} toEmail Email address to send to.
6
+ * @param {Number} resetToken Token to reset by.
7
+ */
3
8
  const passwordReset = async (toEmail, resetToken) => {
4
9
  var transporter = nodemailer.createTransport({
5
10
  service: 'gmail',
@@ -21,9 +26,14 @@ const passwordReset = async (toEmail, resetToken) => {
21
26
  });
22
27
  };
23
28
 
29
+ /**
30
+ * Sends an email. WIP
31
+ * @param {String} toEmail Email Address to send to.
32
+ * @param {String} subject Subject of the email.
33
+ * @param {String} html Body of the email.
34
+ * @returns
35
+ */
24
36
  const send = async (toEmail, subject, html) => {
25
- console.log("dfhd");
26
-
27
37
  var transporter = nodemailer.createTransport({
28
38
  service: 'gmail',
29
39
  auth: {
@@ -44,5 +54,4 @@ const send = async (toEmail, subject, html) => {
44
54
  });
45
55
  }
46
56
 
47
-
48
57
  export default { passwordReset, send };
package/models/spirit.js CHANGED
@@ -1,6 +1,10 @@
1
1
  import mongoose from "mongoose";
2
2
 
3
+ /**
4
+ * Curated Mongoose.js documents for use in bases.
5
+ */
3
6
  export default class Spirit {
7
+ // The actual Mongoose.js model for accessing the database.
4
8
  static db = mongoose.model('spirits', new mongoose.Schema({
5
9
  _lastUpdate: Number,
6
10
  service: String,
@@ -12,6 +16,14 @@ export default class Spirit {
12
16
  data: {}
13
17
  }));
14
18
 
19
+ /**
20
+ * Builds query objects for Mongoose.js searches.
21
+ * @param {String} service The name of the spirit.
22
+ * @param {Object} data An object with data to query the spirit by.
23
+ * @param {ObjectID} parent The MongoDB id of the parent spirit to search by.
24
+ * @param {ObjectID} id The exact id of the MongoDB document.
25
+ * @returns A query object.
26
+ */
15
27
  static buildQuery = (service, data = null, parent = null, id = null) => {
16
28
  let query = {
17
29
  service: service,
@@ -19,8 +31,7 @@ export default class Spirit {
19
31
  };
20
32
 
21
33
  if (id) query._id = id;
22
-
23
- if (data){
34
+ else if (data){
24
35
  let keys = Object.keys(data);
25
36
  for (let i = 0; i < keys.length; i++) {
26
37
  query[`data.${keys[i]}`] = data[keys[i]];
@@ -30,6 +41,13 @@ export default class Spirit {
30
41
  return query;
31
42
  }
32
43
 
44
+ /**
45
+ * Creates a spirit in the database.
46
+ * @param {String} service The name of the spirit.
47
+ * @param {Object} data An object with data to create the spirit with.
48
+ * @param {ObjectID} parent The MongoDB id of the parent of the spirit to be created.
49
+ * @returns A new user spirit.
50
+ */
33
51
  static create = async (service, data = {}, parent = null) => {
34
52
  let spirit = new Spirit();
35
53
 
@@ -43,14 +61,15 @@ export default class Spirit {
43
61
  return spirit;
44
62
  }
45
63
 
64
+ /**
65
+ * Recalls all spirits in the database with a given name.
66
+ * @param {String} service The name of the spirit.
67
+ * @returns All spirits of the given name.
68
+ */
46
69
  static recallAll = async (service) => {
47
70
  let spirit = new Spirit();
48
71
 
49
- let query = Spirit.buildQuery(service);
50
-
51
- let found = await Spirit.db.find({
52
- service: service
53
- });
72
+ let found = await Spirit.db.find({ service: service });
54
73
 
55
74
  if (found) {
56
75
  spirit.memory = found;
@@ -60,24 +79,36 @@ export default class Spirit {
60
79
  else return null;
61
80
  }
62
81
 
82
+ /**
83
+ * Recalls one spirit from the database or creates a new one.
84
+ * @param {String} service The name of the spirit.
85
+ * @param {ObjectID} parent The MongoDB id of the parent spirit to search by.
86
+ * @param {Object} data An object with data to query the spirit by.
87
+ * @param {ObjectID} id The exact id of the MongoDB document.
88
+ * @returns The spirit found or a new one created in the database..
89
+ */
63
90
  static recallOne = async (service, parent = null, data = {}, id = null) => {
64
91
  let spirit = new Spirit();
65
92
 
66
93
  let query = Spirit.buildQuery(service, data, parent, id);
67
94
 
68
95
  let found = await Spirit.db.findOne(query);
96
+
97
+ if (found) spirit.memory = found;
98
+ else spirit = await Spirit.create(service, {}, parent);
69
99
 
70
- if (found) {
71
- spirit.memory = found;
72
- return spirit;
73
- }
74
- else {
75
- let newSpirit = await Spirit.create(service, {}, parent);
76
- return newSpirit;
77
- }
100
+ return spirit;
78
101
  }
79
102
 
80
- static delete = async (service, data = {}, id = null) => {
103
+ /**
104
+ * Deletes all of the specified spirit.
105
+ * @param {String} service The name of the spirit.
106
+ * @param {Object} data An object with data to query the spirit by.
107
+ * @param {ObjectID} parent The MongoDB id of the parent spirit to search with.
108
+ * @param {ObjectID} id The exact id of the MongoDB document.
109
+ * @returns The number of documents deleted.
110
+ */
111
+ static delete = async (service, data = {}, parent = null, id = null) => {
81
112
  let found = await Spirit.db.deleteMany(Spirit.buildQuery(service, data, id));
82
113
 
83
114
  return found.deletedCount;
@@ -89,6 +120,11 @@ export default class Spirit {
89
120
  };
90
121
  }
91
122
 
123
+ /**
124
+ * Commits new data to a spirit.
125
+ * @param {Object} data Data to save.
126
+ * @returns Updated
127
+ */
92
128
  commit = async (data = this.memory.data) => {
93
129
  this.memory._lastUpdate = Date.now();
94
130
 
package/models/user.js CHANGED
@@ -2,45 +2,61 @@ import Spirit from "./spirit.js";
2
2
  import Item from "./item.js";
3
3
  import bcrypt from "bcrypt";
4
4
 
5
+ /**
6
+ * A user spirit.
7
+ * @extends Spirit
8
+ */
5
9
  export default class User extends Spirit {
10
+ /**
11
+ * Recalls one user from the database.
12
+ * @param {String} email Email address of the user.
13
+ * @param {String} username The user's name.
14
+ * @param {ObjectID} id The MongoDB id of the user.
15
+ * @returns A user found or null.
16
+ */
6
17
  static recallOne = async (email = null, username = null, id = null) => {
7
- let spirit = new User(email, id);
18
+ let user = new User(email, id);
8
19
 
9
20
  let query = null;
10
21
 
11
- if (email) {
12
- query = Spirit.buildQuery("user", { email: email });
22
+ if (id) {
23
+ query = Spirit.buildQuery("user", null, null, id);
13
24
  }
14
25
  else if (username) {
15
26
  query = Spirit.buildQuery("user", { username: username });
16
27
  }
17
- else if (id) {
18
- query = Spirit.buildQuery("user", null, null, id);
28
+ else if (email) {
29
+ query = Spirit.buildQuery("user", { email: email });
19
30
  }
31
+ else return null;
20
32
 
21
- let found = null;
22
-
23
- if (query) found = await Spirit.db.findOne(query);
33
+ let found = await Spirit.db.findOne(query);
24
34
 
25
35
  if (found) {
26
- spirit.memory = found;
27
- spirit.id = found._id;
36
+ user.memory = found;
37
+ user.id = found._id;
38
+ user.email = found.data.email;
28
39
 
29
- return spirit;
40
+ return user;
30
41
  }
31
42
  else return null;
32
43
  }
33
44
 
45
+ /**
46
+ * Creates one user in the database.
47
+ * @param {String} email Email address of the user.
48
+ * @param {String} password The user's ****.
49
+ * @param {String} username The user's name.
50
+ * @returns The user created.
51
+ */
34
52
  static create = async (username, password, email) => {
35
- let spirit = new User(email);
53
+ let user = new User(email);
36
54
 
37
55
  const salt = await bcrypt.genSalt(10);
38
56
  const hash = await bcrypt.hash(password, salt);
39
57
 
40
- spirit.memory = await Spirit.db.create({
41
- route: "/",
58
+ user.memory = await Spirit.db.create({
42
59
  service: "user",
43
- scope: "global",
44
60
  parent: null,
45
61
  _lastUpdate: Date.now(),
46
62
  data: {
@@ -63,9 +79,14 @@ export default class User extends Spirit {
63
79
  }
64
80
  });
65
81
 
66
- return spirit;
82
+ return user;
67
83
  }
68
84
 
85
+ /**
86
+ * Delete a user account.
87
+ * @param {String} email Email address of the account to delete.
88
+ * @returns
89
+ */
69
90
  static delete = async (email) => {
70
91
  let found = await Spirit.db.findAndDelete(Spirit.buildQuery({
71
92
  service: "user",
@@ -81,6 +102,12 @@ export default class User extends Spirit {
81
102
  this.id = id;
82
103
  }
83
104
 
105
+ /**
106
+ * Attempts to offset the user's inventory of a certain item.
107
+ * @param {String} name The item's name.
108
+ * @param {Number} offset The amount to offset by.
109
+ * @returns True if successful.
110
+ */
84
111
  offsetItem = async (name, offset) => {
85
112
  let item = await Item.recallOne(name);
86
113
 
@@ -122,12 +149,24 @@ export default class User extends Spirit {
122
149
  else return false;
123
150
  }
124
151
 
152
+ /**
153
+ * Tests if an attribute meets a requirement.
154
+ * @param {String} check The attribute to check.
155
+ * @param {Number} against The number to meet.
156
+ * @returns
157
+ */
125
158
  checkAttribute = async (check, against) => {
126
159
  let att = this.memory.data.attributes;
127
160
 
128
161
  return att[check] >= against;
129
162
  }
130
163
 
164
+ /**
165
+ * Sets a user's attribute score.
166
+ * @param {String} change The attribute to change.
167
+ * @param {Number} to The number to set it to.
168
+ * @returns Attributes set
169
+ */
131
170
  setAttribute = async (change, to) => {
132
171
  let att = this.memory.data.attributes;
133
172
 
@@ -138,6 +177,12 @@ export default class User extends Spirit {
138
177
  return "Attributes set.";
139
178
  }
140
179
 
180
+ /**
181
+ * Increments a user's attribute by one.
182
+ * @param {String} change The attribute to increment.
183
+ * @param {Number} max The ceiling.
184
+ * @returns The resulting attribute score.
185
+ */
141
186
  incrementAttribute = async (change, max) => {
142
187
  let att = this.memory.data.attributes;
143
188
 
package/notherbase-fs.js CHANGED
@@ -13,6 +13,9 @@ const __dirname = fileURLToPath(new URL('./', import.meta.url));
13
13
  import Creation from "./controllers/creation.js";
14
14
  import SpiritWorld from "./controllers/spirit-world.js";
15
15
 
16
+ /**
17
+ * The engine that runs a nother base.
18
+ */
16
19
  class NotherBaseFS {
17
20
  constructor(contentPath) {
18
21
  this.app = express();
@@ -51,6 +54,7 @@ class NotherBaseFS {
51
54
  saveUninitialized: false
52
55
  }));
53
56
 
57
+ //provide database access and etc to use in routes
54
58
  this.app.use((req, res, next) => {
55
59
  req.db = Models;
56
60
  req.contentPath = contentPath;
@@ -58,10 +62,13 @@ class NotherBaseFS {
58
62
  next();
59
63
  });
60
64
 
65
+ //spirit world routes
61
66
  this.app.use("/s", this.spiritWorld.router);
62
67
 
68
+ //all actual pages
63
69
  this.app.use("/", this.creation.router);
64
70
 
71
+ //start the server
65
72
  this.server.listen(process.env.PORT, function () {
66
73
  console.log(`Server started at ${process.env.PORT}`);
67
74
  this.started = true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "notherbase-fs",
3
- "version": "3.1.4",
3
+ "version": "3.1.6",
4
4
  "description": "Functions to help make developing for NotherBase easier.",
5
5
  "exports": "./notherbase-fs.js",
6
6
  "scripts": {
package/public/js/base.js CHANGED
@@ -1,4 +1,10 @@
1
1
  class Base {
2
+ /**
3
+ * Communes with the user spirit for easy access to those functions.
4
+ * @param {String} route /s/user/[route]
5
+ * @param {Object} data Data to send with the communion.
6
+ * @returns Communion response.
7
+ */
2
8
  static commune = async (route, data = {}) => {
3
9
  let response = await $.post("/s/user/" + route, JSON.stringify(data));
4
10
 
@@ -7,6 +13,9 @@ class Base {
7
13
  return response;
8
14
  }
9
15
 
16
+ /**
17
+ * The player's inventory.
18
+ */
10
19
  #Inventory = class Inventory {
11
20
  constructor() {
12
21
  this.items = [];
@@ -15,6 +24,9 @@ class Base {
15
24
  this.refresh();
16
25
  }
17
26
 
27
+ /**
28
+ * Reloads the inventory.
29
+ */
18
30
  async refresh() {
19
31
  let $list = $(".inventory .item-list");
20
32
 
@@ -42,12 +54,19 @@ class Base {
42
54
  }
43
55
  }
44
56
 
57
+ /**
58
+ * Clears the error on screen.
59
+ */
45
60
  clearError() {
46
61
  let $error = $("#inventory #error");
47
62
 
48
63
  $error.addClass("invisible");
49
64
  }
50
65
 
66
+ /**
67
+ * Shows an error on screen.
68
+ * @param {String} text The error message.
69
+ */
51
70
  setError(text) {
52
71
  let $error = $("#inventory #error");
53
72
 
@@ -56,6 +75,9 @@ class Base {
56
75
  }
57
76
  }
58
77
 
78
+ /**
79
+ * The player's attributes.
80
+ */
59
81
  #PlayerAttributes = class PlayerAttributes {
60
82
  constructor() {
61
83
  this.attributes = [];
@@ -64,6 +86,9 @@ class Base {
64
86
  this.refresh();
65
87
  }
66
88
 
89
+ /**
90
+ * Reloads the player's attributes.
91
+ */
67
92
  async refresh() {
68
93
  let response = await Base.commune("getAttributes", { _lastUpdate: this.lastUpdate });
69
94
  if (response.status === "success") {
@@ -74,6 +99,9 @@ class Base {
74
99
  }
75
100
  }
76
101
 
102
+ /**
103
+ * Renders the attributes.
104
+ */
77
105
  render() {
78
106
  let $content = $(".menu .content#player");
79
107
 
@@ -87,6 +115,9 @@ class Base {
87
115
  }
88
116
  }
89
117
 
118
+ /**
119
+ * Services for the player's account.
120
+ */
90
121
  #AccountServices = class AccountServices {
91
122
  constructor() {
92
123
  this.username = "";
@@ -96,6 +127,9 @@ class Base {
96
127
  this.refresh();
97
128
  }
98
129
 
130
+ /**
131
+ * Reloads the player's basic info.
132
+ */
99
133
  async refresh() {
100
134
  let response = await Base.commune("getInfo", { _lastUpdate: this.lastUpdate });
101
135
  if (response.status === "success") {
@@ -118,6 +152,9 @@ class Base {
118
152
  $(".content#account #please-login").addClass("invisible");
119
153
  }
120
154
 
155
+ /**
156
+ * Initiates email editing.
157
+ */
121
158
  editEmail() {
122
159
  let $emailSetting = $(".content#account .setting#email");
123
160
  let $emailEdit = $(".content#account .edit#email");
@@ -126,6 +163,9 @@ class Base {
126
163
  $emailEdit.removeClass("invisible");
127
164
  }
128
165
 
166
+ /**
167
+ * Cancels editing the email.
168
+ */
129
169
  cancelEmail() {
130
170
  let $email = $(".content#account .setting#email p");
131
171
  let $emailSetting = $(".content#account .setting#email");
@@ -137,6 +177,9 @@ class Base {
137
177
  $emailInput.val($email.text());
138
178
  }
139
179
 
180
+ /**
181
+ * Confirms and submits an email edit.
182
+ */
140
183
  async updateEmail() {
141
184
  let $info = $(".content#account #info");
142
185
  let $email = $(".content#account .setting#email p");
@@ -155,6 +198,9 @@ class Base {
155
198
  this.cancelEmail();
156
199
  }
157
200
 
201
+ /**
202
+ * Initiates username editing.
203
+ */
158
204
  editUsername() {
159
205
  let $usernameSetting = $(".content#account .setting#username");
160
206
  let $usernameEdit = $(".content#account .edit#username");
@@ -163,6 +209,9 @@ class Base {
163
209
  $usernameEdit.removeClass("invisible");
164
210
  }
165
211
 
212
+ /**
213
+ * Cancels username editing.
214
+ */
166
215
  cancelUsername() {
167
216
  let $usernameSetting = $(".content#account .setting#username");
168
217
  let $usernameEdit = $(".content#account .edit#username");
@@ -174,6 +223,9 @@ class Base {
174
223
  $usernameInput.val($username.text());
175
224
  }
176
225
 
226
+ /**
227
+ * Confirms and submits a username edit.
228
+ */
177
229
  async updateUsername() {
178
230
  let $info = $(".content#account #info");
179
231
  let $username = $(".content#account .setting#username p");
@@ -202,6 +254,9 @@ class Base {
202
254
  this.switchTab("inventory");
203
255
  }
204
256
 
257
+ /**
258
+ * Closes the menu.
259
+ */
205
260
  closeMenu = () => {
206
261
  let $menu = $(".ui .menu");
207
262
  let $fade = $(".ui .fade");
@@ -218,6 +273,9 @@ class Base {
218
273
  }
219
274
  }
220
275
 
276
+ /**
277
+ * Opens the menu.
278
+ */
221
279
  openMenu = () => {
222
280
  let $menu = $(".ui .menu");
223
281
  let $fade = $(".ui .fade");
@@ -227,6 +285,10 @@ class Base {
227
285
  $fade.removeClass("invisible");
228
286
  }
229
287
 
288
+ /**
289
+ * Switches tabs in the menu.
290
+ * @param {String} id The name of the tab to switch to.
291
+ */
230
292
  switchTab = function switchTab(id) {
231
293
  $("#content-window .content").addClass("invisible");
232
294
  $(".menu .tabs button").removeClass("selected");
@@ -234,12 +296,23 @@ class Base {
234
296
  $(`.menu .tabs #${id}`).addClass("selected");
235
297
  }
236
298
 
299
+ /**
300
+ * Communes to logout.
301
+ * @returns Communion response.
302
+ */
237
303
  logout = async () => {
238
304
  let response = await Base.commune("logout");
239
305
 
240
306
  return response;
241
307
  }
242
308
 
309
+ /**
310
+ * Communes to register a new account.
311
+ * @param {String} email The user's email address.
312
+ * @param {String} username The user's display name.
313
+ * @param {String} password The user's ****.
314
+ * @returns Communion response.
315
+ */
243
316
  attemptRegister = async (email, username, password) => {
244
317
  let response = await Base.commune("register", {
245
318
  email, username, password
@@ -248,6 +321,12 @@ class Base {
248
321
  return response;
249
322
  }
250
323
 
324
+ /**
325
+ * Communes to login.
326
+ * @param {String} email The user's email address.
327
+ * @param {String} password The user's password.
328
+ * @returns Communion response.
329
+ */
251
330
  attemptLogin = async (email, password) => {
252
331
  let response = await Base.commune("login", {
253
332
  email: email,
@@ -265,18 +344,38 @@ class Base {
265
344
  return response;
266
345
  };
267
346
 
347
+ /**
348
+ * Communes to send a password reset email.
349
+ * @param {String} email The user's email.
350
+ * @param {Boolean} test Debug mode
351
+ * @returns Communion response.
352
+ */
268
353
  resetPassword = async (email, test = false) => {
269
354
  let response = await Base.commune("sendPasswordReset", { email, test });
270
355
 
271
356
  return response;
272
357
  }
273
358
 
359
+ /**
360
+ * Communes to finalize a password change.
361
+ * @param {Number} token The password reset token.
362
+ * @param {String} email The user's email address.
363
+ * @param {String} password The user's new password.
364
+ * @param {String} confirmation Confirmation of the user's new password.
365
+ * @returns Communion response.
366
+ */
274
367
  changePassword = async (token, email, password, confirmation) => {
275
368
  let response = await Base.commune("changePassword", { token, email, password, confirmation });
276
369
 
277
370
  return response;
278
371
  }
279
372
 
373
+ /**
374
+ * Runs a script on the server.
375
+ * @param {String} what The script to run.
376
+ * @param {Object} data Data to send as input for the script.
377
+ * @returns Communion response.
378
+ */
280
379
  do = async (what, data = null) => {
281
380
  let response = await $.post("/s/serve", JSON.stringify({
282
381
  script: what,
@@ -292,6 +391,12 @@ class Base {
292
391
  return response;
293
392
  }
294
393
 
394
+ /**
395
+ * Loads a certain spirit.
396
+ * @param {String} service The name of the spirit to load.
397
+ * @param {String} scope Defaults to local, else global.
398
+ * @returns Spirit world response.
399
+ */
295
400
  load = async (service, scope = "local") => {
296
401
  let response = await $.post("/s/load", JSON.stringify({ service, scope }));
297
402
 
@@ -1,3 +1,6 @@
1
+ /**
2
+ * Creates a chat box from a div.chat-box.
3
+ */
1
4
  class ChatBox {
2
5
  constructor(username, room) {
3
6
  this.socket = null;
@@ -16,9 +19,14 @@ class ChatBox {
16
19
  });
17
20
 
18
21
  this.socket.on('chat message', this.newMessage);
22
+ this.socket.on('chat info', this.updateInfo);
19
23
  this.render();
20
24
  }
21
25
 
26
+ /**
27
+ * Renders a new message in the chat.
28
+ * @param {Object} msg An object including the text to render.
29
+ */
22
30
  newMessage = (msg) => {
23
31
  let time = new Date(msg.time);
24
32
  this.$chatLog.append(`<p>[${time.toLocaleTimeString('en-US')}] ${msg.name}: ${msg.text}</p>`);
@@ -31,6 +39,20 @@ class ChatBox {
31
39
  }
32
40
  }
33
41
 
42
+ /**
43
+ * Updates info about the chat room in the chat box.
44
+ * @param {Object} msg An object including the users in the room.
45
+ */
46
+ updateInfo = (msg) => {
47
+ this.$users.empty();
48
+ for (let i = 0; i < msg.data.users.length; i++) {
49
+ this.$users.append(`<li>${msg.data.users[i]}</li>`);
50
+ }
51
+ }
52
+
53
+ /**
54
+ * Sends a new chat message to the server.
55
+ */
34
56
  sendMessage = () => {
35
57
  if (this.$entry.val() !== ""){
36
58
  let val = this.$entry.val();
@@ -44,18 +66,19 @@ class ChatBox {
44
66
  }
45
67
  }
46
68
 
69
+ /**
70
+ * Renders necessary child elements.
71
+ */
47
72
  render() {
48
73
  this.$div.empty();
49
74
 
50
- this.$div.append(`<h4>Chatting with the name ${this.username}:`);
51
- this.$div.append(`<div class="chat-log"> </div>`);
52
- this.$div.append(`<input autocomplete="off" type="text" class="chat-entry">`);
53
- this.$div.append(`<button class="chat-send">Send</button>`);
54
-
55
- this.$chatLog = this.$div.find(".chat-log");
56
- this.$entry = this.$div.find(".chat-entry");
75
+ this.$header = $(`<h4>Chatting with the name ${this.username}:`).appendTo(this.$div);
76
+ this.$chatLog = $(`<div class="chat-log"></div>`).appendTo(this.$div);
77
+ this.$users = $(`<ul class="users"></ul>`).appendTo(this.$div);
78
+ this.$entry = $(`<input autocomplete="off" type="text" class="chat-entry">`).appendTo(this.$div);
79
+ this.$send = $(`<button class="chat-send">Send</button>`).appendTo(this.$div);
57
80
 
58
- this.$div.find("button").on("click", this.sendMessage);
81
+ this.$send.on("click", this.sendMessage);
59
82
  this.$entry.on("keyup", (e) => {
60
83
  if (e.keyCode == 13) this.sendMessage();
61
84
  });
@@ -1,4 +1,8 @@
1
1
  .content#account {
2
+ padding: 20px;
3
+ }
4
+
5
+ .content#account h3 {
2
6
  padding: 10px;
3
7
  }
4
8