mirror of
https://github.com/HabitRPG/habitica.git
synced 2026-05-19 11:29:01 -05:00
Compare commits
49 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 192d649ffa | |||
| e7aae55eca | |||
| 36b03613e1 | |||
| 2de9a16a2c | |||
| 895241b7fa | |||
| 2535fd7095 | |||
| 30f1820a49 | |||
| 3bb6c391af | |||
| a0383c785a | |||
| 99790c05f4 | |||
| fc5fec9bfe | |||
| 9db5d4116d | |||
| 6676e94ef6 | |||
| 723adceb25 | |||
| 440d06da4a | |||
| 0ea84668a8 | |||
| 5893d8b9bb | |||
| 2c799b9c07 | |||
| 1550d9b4ee | |||
| ade812b86d | |||
| 62e6fbef61 | |||
| 67a0f8b65a | |||
| aa432022d3 | |||
| 86fb3c1fd1 | |||
| ff2b4add8b | |||
| 4ba73dfbec | |||
| e675ea9bd1 | |||
| 9c27d86ced | |||
| 58ee81adfc | |||
| 32c9904a6e | |||
| b86e0a1549 | |||
| 154ac9bb38 | |||
| a97060445a | |||
| 26b59de1de | |||
| 21c8b00ef6 | |||
| c25b7293bb | |||
| 15e078cb34 | |||
| f7bb17202b | |||
| 213b7696c5 | |||
| fe5c95316b | |||
| 54617f8583 | |||
| 75c9731ca4 | |||
| 31afc45744 | |||
| f6466b161b | |||
| a36114e904 | |||
| 529f856ab9 | |||
| 9077e66973 | |||
| a47a96b70d | |||
| 8a94e88786 |
+1
-1
@@ -47,5 +47,5 @@ webpack.webstorm.config
|
||||
|
||||
# mongodb replica set for local dev
|
||||
mongodb-*.tgz
|
||||
/mongodb-data
|
||||
/mongodb-data*
|
||||
/.nyc_output
|
||||
|
||||
+1
-1
Submodule habitica-images updated: d2919bc15f...dfb04339a4
@@ -26,7 +26,7 @@ async function updateUser (user) {
|
||||
[{ name: 'BASE_URL', content: BASE_URL }], // Add variables from template
|
||||
);
|
||||
|
||||
return User.update({ _id: user._id }, { $set: { migration: MIGRATION_NAME } }).exec();
|
||||
return User.updateOne({ _id: user._id }, { $set: { migration: MIGRATION_NAME } }).exec();
|
||||
}
|
||||
|
||||
export default async function processUsers () {
|
||||
|
||||
@@ -27,13 +27,13 @@ async function updateUser (user) {
|
||||
|
||||
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
|
||||
|
||||
return User.update({ _id: user._id }, { $set: set }).exec();
|
||||
return User.updateOne({ _id: user._id }, { $set: set }).exec();
|
||||
}
|
||||
|
||||
export default async function processUsers () {
|
||||
const query = {
|
||||
migration: { $ne: MIGRATION_NAME },
|
||||
'auth.local.lowerCaseUsername': 'olson1',
|
||||
'auth.local.username': 'ExampleHabitican',
|
||||
};
|
||||
|
||||
const fields = {
|
||||
|
||||
@@ -57,7 +57,7 @@ async function updateUser (user) {
|
||||
export default async function processUsers () {
|
||||
const query = {
|
||||
migration: { $ne: MIGRATION_NAME },
|
||||
'auth.local.username': 'SabreTest',
|
||||
'auth.local.username': 'ExampleHabitican',
|
||||
};
|
||||
|
||||
const fields = {
|
||||
|
||||
@@ -2,16 +2,15 @@
|
||||
* Award Habitoween ladder items to participants in this month's Habitoween festivities
|
||||
*/
|
||||
/* eslint-disable no-console */
|
||||
import { model as User } from '../../website/server/models/user';
|
||||
|
||||
const MIGRATION_NAME = '20241030_habitoween_ladder'; // Update when running in future years
|
||||
|
||||
import { model as User } from '../../website/server/models/user';
|
||||
|
||||
const progressCount = 1000;
|
||||
let count = 0;
|
||||
|
||||
async function updateUser (user) {
|
||||
count++;
|
||||
count += 1;
|
||||
|
||||
const set = { migration: MIGRATION_NAME };
|
||||
const inc = {
|
||||
@@ -26,7 +25,7 @@ async function updateUser (user) {
|
||||
'items.food.Candy_Desert': 1,
|
||||
'items.food.Candy_Red': 1,
|
||||
};
|
||||
let push = { notifications: { $each: [] }};
|
||||
const push = { notifications: { $each: [] } };
|
||||
|
||||
if (user && user.items && user.items.mounts && user.items.mounts['JackOLantern-RoyalPurple']) {
|
||||
push.notifications.$each.push({
|
||||
@@ -138,13 +137,13 @@ async function updateUser (user) {
|
||||
}
|
||||
|
||||
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
|
||||
return await User.updateOne({_id: user._id}, {$inc: inc, $push: push, $set: set}).exec();
|
||||
return User.updateOne({ _id: user._id }, { $inc: inc, $push: push, $set: set }).exec();
|
||||
}
|
||||
|
||||
export default async function processUsers () {
|
||||
let query = {
|
||||
migration: {$ne: MIGRATION_NAME},
|
||||
'auth.timestamps.loggedin': {$gt: new Date('2024-10-01')},
|
||||
const query = {
|
||||
migration: { $ne: MIGRATION_NAME },
|
||||
'auth.timestamps.loggedin': { $gt: new Date('2024-10-01') },
|
||||
};
|
||||
|
||||
const fields = {
|
||||
@@ -156,7 +155,7 @@ export default async function processUsers () {
|
||||
const users = await User // eslint-disable-line no-await-in-loop
|
||||
.find(query)
|
||||
.limit(250)
|
||||
.sort({_id: 1})
|
||||
.sort({ _id: 1 })
|
||||
.select(fields)
|
||||
.lean()
|
||||
.exec();
|
||||
@@ -173,4 +172,4 @@ export default async function processUsers () {
|
||||
|
||||
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* eslint-disable no-console */
|
||||
const MIGRATION_NAME = '20241120_harvest_feast';
|
||||
import { model as User } from '../../website/server/models/user';
|
||||
|
||||
const MIGRATION_NAME = '20241120_harvest_feast';
|
||||
const progressCount = 1000;
|
||||
let count = 0;
|
||||
|
||||
@@ -129,11 +129,11 @@ async function updateUser (user) {
|
||||
|
||||
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
|
||||
|
||||
return await User.updateOne({_id: user._id}, updateOp).exec();
|
||||
return User.updateOne({ _id: user._id }, updateOp).exec();
|
||||
}
|
||||
|
||||
export default async function processUsers () {
|
||||
let query = {
|
||||
const query = {
|
||||
migration: { $ne: MIGRATION_NAME },
|
||||
'auth.timestamps.loggedin': { $gt: new Date('2024-10-20') },
|
||||
};
|
||||
@@ -164,4 +164,4 @@ export default async function processUsers () {
|
||||
|
||||
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
/* eslint-disable no-console */
|
||||
import { model as User } from '../../website/server/models/user';
|
||||
|
||||
const MIGRATION_NAME = '20231228_nye';
|
||||
const progressCount = 1000;
|
||||
let count = 0;
|
||||
|
||||
async function updateUser (user) {
|
||||
count += 1;
|
||||
|
||||
const updateOp = {
|
||||
$set: { migration: MIGRATION_NAME },
|
||||
$push: { },
|
||||
};
|
||||
const data = {
|
||||
title: 'Happy New Year!',
|
||||
destination: '/inventory/equipment',
|
||||
};
|
||||
|
||||
if (typeof user.items.gear.owned.head_special_nye2023 !== 'undefined') {
|
||||
updateOp.$inc = {
|
||||
'items.food.Candy_Skeleton': 1,
|
||||
'items.food.Candy_Base': 1,
|
||||
'items.food.Candy_CottonCandyBlue': 1,
|
||||
'items.food.Candy_CottonCandyPink': 1,
|
||||
'items.food.Candy_Shade': 1,
|
||||
'items.food.Candy_White': 1,
|
||||
'items.food.Candy_Golden': 1,
|
||||
'items.food.Candy_Zombie': 1,
|
||||
'items.food.Candy_Desert': 1,
|
||||
'items.food.Candy_Red': 1,
|
||||
};
|
||||
data.icon = 'notif_candy_nye';
|
||||
data.text = 'You’ve received an assortment of candy to celebrate with your Pets!';
|
||||
data.destination = '/inventory/stable';
|
||||
} else if (typeof user.items.gear.owned.head_special_nye2022 !== 'undefined') {
|
||||
updateOp.$set['items.gear.owned.head_special_nye2023'] = true;
|
||||
data.icon = 'notif_2023hat_nye';
|
||||
data.text = 'Take on your resolutions with style in this Ludicrous Party Hat!';
|
||||
} else if (typeof user.items.gear.owned.head_special_nye2021 !== 'undefined') {
|
||||
updateOp.$set['items.gear.owned.head_special_nye2022'] = true;
|
||||
data.icon = 'notif_2022hat_nye';
|
||||
data.text = 'Take on your resolutions with style in this Fabulous Party Hat!';
|
||||
} else if (typeof user.items.gear.owned.head_special_nye2020 !== 'undefined') {
|
||||
updateOp.$set['items.gear.owned.head_special_nye2021'] = true;
|
||||
data.icon = 'notif_2021hat_nye';
|
||||
data.text = 'Take on your resolutions with style in this Preposterous Party Hat!';
|
||||
} else if (typeof user.items.gear.owned.head_special_nye2019 !== 'undefined') {
|
||||
updateOp.$set['items.gear.owned.head_special_nye2020'] = true;
|
||||
data.icon = 'notif_2020hat_nye';
|
||||
data.text = 'Take on your resolutions with style in this Extravagant Party Hat!';
|
||||
} else if (typeof user.items.gear.owned.head_special_nye2018 !== 'undefined') {
|
||||
updateOp.$set['items.gear.owned.head_special_nye2019'] = true;
|
||||
data.icon = 'notif_2019hat_nye';
|
||||
data.text = 'Take on your resolutions with style in this Outrageous Party Hat!';
|
||||
} else if (typeof user.items.gear.owned.head_special_nye2017 !== 'undefined') {
|
||||
updateOp.$set['items.gear.owned.head_special_nye2018'] = true;
|
||||
data.icon = 'notif_2018hat_nye';
|
||||
data.text = 'Take on your resolutions with style in this Outlandish Party Hat!';
|
||||
} else if (typeof user.items.gear.owned.head_special_nye2016 !== 'undefined') {
|
||||
updateOp.$set['items.gear.owned.head_special_nye2017'] = true;
|
||||
data.icon = 'notif_2017hat_nye';
|
||||
data.text = 'Take on your resolutions with style in this Fanciful Party Hat!';
|
||||
} else if (typeof user.items.gear.owned.head_special_nye2015 !== 'undefined') {
|
||||
updateOp.$set['items.gear.owned.head_special_nye2016'] = true;
|
||||
data.icon = 'notif_2016hat_nye';
|
||||
data.text = 'Take on your resolutions with style in this Whimsical Party Hat!';
|
||||
} else if (typeof user.items.gear.owned.head_special_nye2014 !== 'undefined') {
|
||||
updateOp.$set['items.gear.owned.head_special_nye2015'] = true;
|
||||
data.icon = 'notif_2015hat_nye';
|
||||
data.text = 'Take on your resolutions with style in this Ridiculous Party Hat!';
|
||||
} else if (typeof user.items.gear.owned.head_special_nye !== 'undefined') {
|
||||
updateOp.$set['items.gear.owned.head_special_nye2014'] = true;
|
||||
data.icon = 'notif_2014hat_nye';
|
||||
data.text = 'Take on your resolutions with style in this Silly Party Hat!';
|
||||
} else {
|
||||
updateOp.$set['items.gear.owned.head_special_nye'] = true;
|
||||
data.icon = 'notif_2013hat_nye';
|
||||
data.text = 'Take on your resolutions with style in this Absurd Party Hat!';
|
||||
}
|
||||
|
||||
updateOp.$push.notifications = {
|
||||
type: 'ITEM_RECEIVED',
|
||||
data,
|
||||
seen: false,
|
||||
};
|
||||
|
||||
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
|
||||
|
||||
return User.updateOne({ _id: user._id }, updateOp).exec();
|
||||
}
|
||||
|
||||
export default async function processUsers () {
|
||||
const query = {
|
||||
'auth.timestamps.loggedin': { $gt: new Date('2023-12-01') },
|
||||
migration: { $ne: MIGRATION_NAME },
|
||||
};
|
||||
|
||||
const fields = {
|
||||
_id: 1,
|
||||
items: 1,
|
||||
};
|
||||
|
||||
while (true) { // eslint-disable-line no-constant-condition
|
||||
const users = await User // eslint-disable-line no-await-in-loop
|
||||
.find(query)
|
||||
.limit(250)
|
||||
.sort({ _id: 1 })
|
||||
.select(fields)
|
||||
.lean()
|
||||
.exec();
|
||||
|
||||
if (users.length === 0) {
|
||||
console.warn('All appropriate users found and modified.');
|
||||
console.warn(`\n${count} users processed\n`);
|
||||
break;
|
||||
} else {
|
||||
query._id = {
|
||||
$gt: users[users.length - 1],
|
||||
};
|
||||
}
|
||||
|
||||
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
|
||||
}
|
||||
}
|
||||
Generated
+125
-85
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "habitica",
|
||||
"version": "5.31.0",
|
||||
"version": "5.32.5",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "habitica",
|
||||
"version": "5.31.0",
|
||||
"version": "5.32.5",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.22.10",
|
||||
@@ -22,7 +22,7 @@
|
||||
"apple-auth": "^1.0.9",
|
||||
"babel-preset-env": "^1.7.0",
|
||||
"bcrypt": "^5.1.1",
|
||||
"body-parser": "^1.20.2",
|
||||
"body-parser": "^1.20.3",
|
||||
"bootstrap": "^4.6.2",
|
||||
"compression": "^1.7.4",
|
||||
"cookie-session": "^2.0.0",
|
||||
@@ -33,7 +33,7 @@
|
||||
"eslint": "^8.55.0",
|
||||
"eslint-config-habitrpg": "^6.2.3",
|
||||
"eslint-plugin-mocha": "^5.0.0",
|
||||
"express": "^4.19.2",
|
||||
"express": "^4.21.1",
|
||||
"express-basic-auth": "^1.2.1",
|
||||
"express-validator": "^5.2.0",
|
||||
"firebase-admin": "^12.1.1",
|
||||
@@ -56,7 +56,7 @@
|
||||
"method-override": "^3.0.0",
|
||||
"moment": "^2.29.4",
|
||||
"moment-recur": "^1.0.7",
|
||||
"mongoose": "^7.6.3",
|
||||
"mongoose": "^7.8.3",
|
||||
"morgan": "^1.10.0",
|
||||
"nconf": "^0.12.1",
|
||||
"node-gcm": "^1.0.5",
|
||||
@@ -92,7 +92,7 @@
|
||||
"chai-as-promised": "^7.1.1",
|
||||
"chai-moment": "^0.1.0",
|
||||
"chalk": "^5.3.0",
|
||||
"cross-spawn": "^7.0.3",
|
||||
"cross-spawn": "^7.0.5",
|
||||
"mocha": "^5.1.1",
|
||||
"monk": "^7.3.4",
|
||||
"nyc": "^15.1.0",
|
||||
@@ -3044,9 +3044,9 @@
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
},
|
||||
"node_modules/@mongodb-js/saslprep": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.4.tgz",
|
||||
"integrity": "sha512-8zJ8N1x51xo9hwPh6AWnKdLGEC5N3lDa6kms1YHmFBoRhTpJR6HG8wWk0td1MVCu9cD4YBrvjZEtd5Obw0Fbnw==",
|
||||
"version": "1.1.9",
|
||||
"resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.9.tgz",
|
||||
"integrity": "sha512-tVkljjeEaAhCqTzajSdgbQ6gE6f3oneVwa3iXR6csiEwXXOFsiC6Uh9iAjAhXPtqa/XMDHWjjeNH/77m/Yq2dw==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"sparse-bitfield": "^3.0.3"
|
||||
@@ -6244,9 +6244,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/body-parser": {
|
||||
"version": "1.20.2",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
|
||||
"integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
|
||||
"version": "1.20.3",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
|
||||
"integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
|
||||
"dependencies": {
|
||||
"bytes": "3.1.2",
|
||||
"content-type": "~1.0.5",
|
||||
@@ -6256,7 +6256,7 @@
|
||||
"http-errors": "2.0.0",
|
||||
"iconv-lite": "0.4.24",
|
||||
"on-finished": "2.4.1",
|
||||
"qs": "6.11.0",
|
||||
"qs": "6.13.0",
|
||||
"raw-body": "2.5.2",
|
||||
"type-is": "~1.6.18",
|
||||
"unpipe": "1.0.0"
|
||||
@@ -6291,11 +6291,11 @@
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||
},
|
||||
"node_modules/body-parser/node_modules/qs": {
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
|
||||
"integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
|
||||
"version": "6.13.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
|
||||
"integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
|
||||
"dependencies": {
|
||||
"side-channel": "^1.0.4"
|
||||
"side-channel": "^1.0.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.6"
|
||||
@@ -6577,14 +6577,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/call-bind": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.6.tgz",
|
||||
"integrity": "sha512-Mj50FLHtlsoVfRfnHaZvyrooHcrlceNZdL/QBvJJVd9Ta55qCQK0gs4ss2oZDeV9zFCs6ewzYgVE5yfVmfFpVg==",
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
|
||||
"integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
|
||||
"dependencies": {
|
||||
"es-define-property": "^1.0.0",
|
||||
"es-errors": "^1.3.0",
|
||||
"function-bind": "^1.1.2",
|
||||
"get-intrinsic": "^1.2.3",
|
||||
"set-function-length": "^1.2.0"
|
||||
"get-intrinsic": "^1.2.4",
|
||||
"set-function-length": "^1.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -7369,9 +7370,9 @@
|
||||
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="
|
||||
},
|
||||
"node_modules/cookie": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
|
||||
"integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
|
||||
"version": "0.7.1",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz",
|
||||
"integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
@@ -7500,9 +7501,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
|
||||
"version": "7.0.5",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.5.tgz",
|
||||
"integrity": "sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==",
|
||||
"dependencies": {
|
||||
"path-key": "^3.1.0",
|
||||
"shebang-command": "^2.0.0",
|
||||
@@ -8376,9 +8377,9 @@
|
||||
"integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ=="
|
||||
},
|
||||
"node_modules/encodeurl": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
||||
"integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
|
||||
"integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
@@ -8497,6 +8498,17 @@
|
||||
"resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz",
|
||||
"integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA=="
|
||||
},
|
||||
"node_modules/es-define-property": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
|
||||
"integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
|
||||
"dependencies": {
|
||||
"get-intrinsic": "^1.2.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-errors": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
||||
@@ -9980,36 +9992,36 @@
|
||||
}
|
||||
},
|
||||
"node_modules/express": {
|
||||
"version": "4.19.2",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz",
|
||||
"integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==",
|
||||
"version": "4.21.1",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz",
|
||||
"integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==",
|
||||
"dependencies": {
|
||||
"accepts": "~1.3.8",
|
||||
"array-flatten": "1.1.1",
|
||||
"body-parser": "1.20.2",
|
||||
"body-parser": "1.20.3",
|
||||
"content-disposition": "0.5.4",
|
||||
"content-type": "~1.0.4",
|
||||
"cookie": "0.6.0",
|
||||
"cookie": "0.7.1",
|
||||
"cookie-signature": "1.0.6",
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
"encodeurl": "~1.0.2",
|
||||
"encodeurl": "~2.0.0",
|
||||
"escape-html": "~1.0.3",
|
||||
"etag": "~1.8.1",
|
||||
"finalhandler": "1.2.0",
|
||||
"finalhandler": "1.3.1",
|
||||
"fresh": "0.5.2",
|
||||
"http-errors": "2.0.0",
|
||||
"merge-descriptors": "1.0.1",
|
||||
"merge-descriptors": "1.0.3",
|
||||
"methods": "~1.1.2",
|
||||
"on-finished": "2.4.1",
|
||||
"parseurl": "~1.3.3",
|
||||
"path-to-regexp": "0.1.7",
|
||||
"path-to-regexp": "0.1.10",
|
||||
"proxy-addr": "~2.0.7",
|
||||
"qs": "6.11.0",
|
||||
"qs": "6.13.0",
|
||||
"range-parser": "~1.2.1",
|
||||
"safe-buffer": "5.2.1",
|
||||
"send": "0.18.0",
|
||||
"serve-static": "1.15.0",
|
||||
"send": "0.19.0",
|
||||
"serve-static": "1.16.2",
|
||||
"setprototypeof": "1.2.0",
|
||||
"statuses": "2.0.1",
|
||||
"type-is": "~1.6.18",
|
||||
@@ -10062,11 +10074,11 @@
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||
},
|
||||
"node_modules/express/node_modules/qs": {
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
|
||||
"integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
|
||||
"version": "6.13.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
|
||||
"integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
|
||||
"dependencies": {
|
||||
"side-channel": "^1.0.4"
|
||||
"side-channel": "^1.0.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.6"
|
||||
@@ -10531,12 +10543,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/finalhandler": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
|
||||
"integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
|
||||
"integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
|
||||
"dependencies": {
|
||||
"debug": "2.6.9",
|
||||
"encodeurl": "~1.0.2",
|
||||
"encodeurl": "~2.0.0",
|
||||
"escape-html": "~1.0.3",
|
||||
"on-finished": "2.4.1",
|
||||
"parseurl": "~1.3.3",
|
||||
@@ -13348,10 +13360,27 @@
|
||||
"resolved": "https://registry.npmjs.org/iota-array/-/iota-array-1.0.0.tgz",
|
||||
"integrity": "sha512-pZ2xT+LOHckCatGQ3DcG/a+QuEqvoxqkiL7tvE8nn3uuu+f6i1TtpB5/FtWFbxUuVr5PZCx8KskuGatbJDXOWA=="
|
||||
},
|
||||
"node_modules/ip": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz",
|
||||
"integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ=="
|
||||
"node_modules/ip-address": {
|
||||
"version": "9.0.5",
|
||||
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz",
|
||||
"integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==",
|
||||
"dependencies": {
|
||||
"jsbn": "1.1.0",
|
||||
"sprintf-js": "^1.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 12"
|
||||
}
|
||||
},
|
||||
"node_modules/ip-address/node_modules/jsbn": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz",
|
||||
"integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A=="
|
||||
},
|
||||
"node_modules/ip-address/node_modules/sprintf-js": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
|
||||
"integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA=="
|
||||
},
|
||||
"node_modules/ipaddr.js": {
|
||||
"version": "1.9.1",
|
||||
@@ -14961,9 +14990,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/merge-descriptors": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
|
||||
"integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
|
||||
"integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/merge-stream": {
|
||||
"version": "2.0.0",
|
||||
@@ -15564,13 +15596,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/mongoose": {
|
||||
"version": "7.6.8",
|
||||
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-7.6.8.tgz",
|
||||
"integrity": "sha512-q9zAySH+UtOK5yonWyNcLfq3PxrY6s4gdta4qNGKNOE2yTVoY9FP4hQtvWYnv4rkdk7T8QmQMC7bbhJjDxIunw==",
|
||||
"version": "7.8.3",
|
||||
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-7.8.3.tgz",
|
||||
"integrity": "sha512-eFnbkKgyVrICoHB6tVJ4uLanS7d5AIo/xHkEbQeOv6g2sD7gh/1biRwvFifsmbtkIddQVNr3ROqHik6gkknN3g==",
|
||||
"dependencies": {
|
||||
"bson": "^5.5.0",
|
||||
"kareem": "2.5.1",
|
||||
"mongodb": "5.9.1",
|
||||
"mongodb": "5.9.2",
|
||||
"mpath": "0.9.0",
|
||||
"mquery": "5.0.0",
|
||||
"ms": "2.1.3",
|
||||
@@ -15593,9 +15625,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/mongoose/node_modules/mongodb": {
|
||||
"version": "5.9.1",
|
||||
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.9.1.tgz",
|
||||
"integrity": "sha512-NBGA8AfJxGPeB12F73xXwozt8ZpeIPmCUeWRwl9xejozTXFes/3zaep9zhzs1B/nKKsw4P3I4iPfXl3K7s6g+Q==",
|
||||
"version": "5.9.2",
|
||||
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.9.2.tgz",
|
||||
"integrity": "sha512-H60HecKO4Bc+7dhOv4sJlgvenK4fQNqqUIlXxZYQNbfEWSALGAwGoyJd/0Qwk4TttFXUOHJ2ZJQe/52ScaUwtQ==",
|
||||
"dependencies": {
|
||||
"bson": "^5.5.0",
|
||||
"mongodb-connection-string-url": "^2.6.0",
|
||||
@@ -17592,9 +17624,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/path-to-regexp": {
|
||||
"version": "0.1.7",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
|
||||
"integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
|
||||
"version": "0.1.10",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz",
|
||||
"integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w=="
|
||||
},
|
||||
"node_modules/path-type": {
|
||||
"version": "1.1.0",
|
||||
@@ -19337,9 +19369,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/send": {
|
||||
"version": "0.18.0",
|
||||
"resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
|
||||
"integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
|
||||
"version": "0.19.0",
|
||||
"resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
|
||||
"integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
|
||||
"dependencies": {
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
@@ -19372,6 +19404,14 @@
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||
},
|
||||
"node_modules/send/node_modules/encodeurl": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
||||
"integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/send/node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
@@ -19386,14 +19426,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/serve-static": {
|
||||
"version": "1.15.0",
|
||||
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
|
||||
"integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
|
||||
"version": "1.16.2",
|
||||
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
|
||||
"integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
|
||||
"dependencies": {
|
||||
"encodeurl": "~1.0.2",
|
||||
"encodeurl": "~2.0.0",
|
||||
"escape-html": "~1.0.3",
|
||||
"parseurl": "~1.3.3",
|
||||
"send": "0.18.0"
|
||||
"send": "0.19.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
@@ -19519,11 +19559,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/side-channel": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.5.tgz",
|
||||
"integrity": "sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==",
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
|
||||
"integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.6",
|
||||
"call-bind": "^1.0.7",
|
||||
"es-errors": "^1.3.0",
|
||||
"get-intrinsic": "^1.2.4",
|
||||
"object-inspect": "^1.13.1"
|
||||
@@ -19861,15 +19901,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/socks": {
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz",
|
||||
"integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==",
|
||||
"version": "2.8.3",
|
||||
"resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz",
|
||||
"integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==",
|
||||
"dependencies": {
|
||||
"ip": "^2.0.0",
|
||||
"ip-address": "^9.0.5",
|
||||
"smart-buffer": "^4.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.13.0",
|
||||
"node": ">= 10.0.0",
|
||||
"npm": ">= 3.0.0"
|
||||
}
|
||||
},
|
||||
|
||||
+6
-5
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "habitica",
|
||||
"description": "A habit tracker app which treats your goals like a Role Playing Game.",
|
||||
"version": "5.31.0",
|
||||
"version": "5.32.5",
|
||||
"main": "./website/server/index.js",
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.22.10",
|
||||
@@ -17,7 +17,7 @@
|
||||
"apple-auth": "^1.0.9",
|
||||
"babel-preset-env": "^1.7.0",
|
||||
"bcrypt": "^5.1.1",
|
||||
"body-parser": "^1.20.2",
|
||||
"body-parser": "^1.20.3",
|
||||
"bootstrap": "^4.6.2",
|
||||
"compression": "^1.7.4",
|
||||
"cookie-session": "^2.0.0",
|
||||
@@ -28,7 +28,7 @@
|
||||
"eslint": "^8.55.0",
|
||||
"eslint-config-habitrpg": "^6.2.3",
|
||||
"eslint-plugin-mocha": "^5.0.0",
|
||||
"express": "^4.19.2",
|
||||
"express": "^4.21.1",
|
||||
"express-basic-auth": "^1.2.1",
|
||||
"express-validator": "^5.2.0",
|
||||
"firebase-admin": "^12.1.1",
|
||||
@@ -51,7 +51,7 @@
|
||||
"method-override": "^3.0.0",
|
||||
"moment": "^2.29.4",
|
||||
"moment-recur": "^1.0.7",
|
||||
"mongoose": "^7.6.3",
|
||||
"mongoose": "^7.8.3",
|
||||
"morgan": "^1.10.0",
|
||||
"nconf": "^0.12.1",
|
||||
"node-gcm": "^1.0.5",
|
||||
@@ -110,6 +110,7 @@
|
||||
"start:simple": "node ./website/server/index.js",
|
||||
"debug": "gulp nodemon --inspect",
|
||||
"mongo:dev": "run-rs -v 5.0.23 -l ubuntu1804 --keep --dbpath mongodb-data --number 1 --quiet",
|
||||
"mongo:test": "run-rs -v 5.0.23 -l ubuntu1804 --keep --dbpath mongodb-data-testing --number 1 --quiet",
|
||||
"postinstall": "git config --global url.\"https://\".insteadOf git:// && gulp build && cd website/client && npm install",
|
||||
"apidoc": "gulp apidoc",
|
||||
"heroku-postbuild": ".heroku/report_deploy.sh"
|
||||
@@ -120,7 +121,7 @@
|
||||
"chai-as-promised": "^7.1.1",
|
||||
"chai-moment": "^0.1.0",
|
||||
"chalk": "^5.3.0",
|
||||
"cross-spawn": "^7.0.3",
|
||||
"cross-spawn": "^7.0.5",
|
||||
"mocha": "^5.1.1",
|
||||
"monk": "^7.3.4",
|
||||
"nyc": "^15.1.0",
|
||||
|
||||
@@ -51,6 +51,7 @@ describe('Stripe - Checkout', () => {
|
||||
gift: undefined,
|
||||
sub: undefined,
|
||||
gemsBlock: gemsBlockKey,
|
||||
server_url: BASE_URL,
|
||||
};
|
||||
|
||||
expect(gems.validateGiftMessage).to.not.be.called;
|
||||
@@ -101,6 +102,7 @@ describe('Stripe - Checkout', () => {
|
||||
gift: JSON.stringify(gift),
|
||||
sub: undefined,
|
||||
gemsBlock: undefined,
|
||||
server_url: BASE_URL,
|
||||
};
|
||||
|
||||
expect(gems.validateGiftMessage).to.be.calledOnce;
|
||||
@@ -155,6 +157,7 @@ describe('Stripe - Checkout', () => {
|
||||
gift: JSON.stringify(gift),
|
||||
sub: undefined,
|
||||
gemsBlock: undefined,
|
||||
server_url: BASE_URL,
|
||||
};
|
||||
|
||||
expect(oneTimePayments.getOneTimePaymentInfo).to.be.calledOnce;
|
||||
@@ -192,6 +195,7 @@ describe('Stripe - Checkout', () => {
|
||||
userId: user._id,
|
||||
gift: undefined,
|
||||
sub: JSON.stringify(sub),
|
||||
server_url: BASE_URL,
|
||||
};
|
||||
|
||||
expect(subscriptions.checkSubData).to.be.calledOnce;
|
||||
@@ -258,6 +262,7 @@ describe('Stripe - Checkout', () => {
|
||||
userId: user._id,
|
||||
gift: undefined,
|
||||
sub: JSON.stringify(sub),
|
||||
server_url: BASE_URL,
|
||||
groupId,
|
||||
};
|
||||
|
||||
@@ -328,8 +333,9 @@ describe('Stripe - Checkout', () => {
|
||||
user.purchased.plan.customerId = customerId;
|
||||
|
||||
const metadata = {
|
||||
userId: user._id,
|
||||
type: 'edit-card-user',
|
||||
userId: user._id,
|
||||
server_url: BASE_URL,
|
||||
};
|
||||
|
||||
const res = await createEditCardCheckoutSession({ user }, stripe);
|
||||
@@ -418,6 +424,7 @@ describe('Stripe - Checkout', () => {
|
||||
const metadata = {
|
||||
userId: user._id,
|
||||
type: 'edit-card-group',
|
||||
server_url: BASE_URL,
|
||||
groupId,
|
||||
};
|
||||
|
||||
@@ -455,6 +462,7 @@ describe('Stripe - Checkout', () => {
|
||||
userId: anotherUser._id,
|
||||
type: 'edit-card-group',
|
||||
groupId,
|
||||
server_url: BASE_URL,
|
||||
};
|
||||
|
||||
const res = await createEditCardCheckoutSession({ user: anotherUser, groupId }, stripe);
|
||||
|
||||
@@ -16,6 +16,7 @@ import * as subscriptions from '../../../../../../website/server/libs/payments/s
|
||||
const { i18n } = common;
|
||||
|
||||
describe('Stripe - Webhooks', () => {
|
||||
const BASE_URL = nconf.get('BASE_URL');
|
||||
const stripe = stripeModule('test');
|
||||
const endpointSecret = nconf.get('STRIPE_WEBHOOKS_ENDPOINT_SECRET');
|
||||
const headers = {};
|
||||
@@ -284,7 +285,9 @@ describe('Stripe - Webhooks', () => {
|
||||
const session = {};
|
||||
|
||||
beforeEach(() => {
|
||||
session.metadata = {};
|
||||
session.metadata = {
|
||||
server_url: BASE_URL,
|
||||
};
|
||||
event = { type: eventType, data: { object: session } };
|
||||
constructEventStub = sandbox.stub(stripe.webhooks, 'constructEvent');
|
||||
constructEventStub.returns(event);
|
||||
|
||||
@@ -59,7 +59,7 @@ describe('POST /debug/jump-time', () => {
|
||||
expect(resultDate.getDate()).to.eql(today.getDate());
|
||||
expect(resultDate.getMonth()).to.eql(today.getMonth());
|
||||
expect(resultDate.getFullYear()).to.eql(today.getFullYear());
|
||||
const newResultDate = new Date((await user.post('/debug/jump-time', { offsetDays: 355 })).time);
|
||||
const newResultDate = new Date((await user.post('/debug/jump-time', { offsetDays: 365 })).time);
|
||||
expect(newResultDate.getFullYear()).to.eql(today.getFullYear() + 1);
|
||||
});
|
||||
|
||||
|
||||
@@ -60,12 +60,12 @@ describe('PUT /heroes/:heroId', () => {
|
||||
expect(heroRes.profile).to.have.all.keys(['name']);
|
||||
|
||||
// test response values
|
||||
expect(heroRes.balance).to.equal(3 + 0.75); // 3+0.75 for first contrib level
|
||||
expect(heroRes.balance).to.equal(3 + 2.5); // 3+2.5 for first contrib level
|
||||
expect(heroRes.contributor.level).to.equal(1);
|
||||
expect(heroRes.purchased.ads).to.equal(true);
|
||||
// test hero values
|
||||
await hero.sync();
|
||||
expect(hero.balance).to.equal(3 + 0.75); // 3+0.75 for first contrib level
|
||||
expect(hero.balance).to.equal(3 + 2.5); // 3+2.5 for first contrib level
|
||||
expect(hero.contributor.level).to.equal(1);
|
||||
expect(hero.purchased.ads).to.equal(true);
|
||||
expect(hero.auth.blocked).to.equal(prevBlockState);
|
||||
@@ -136,12 +136,12 @@ describe('PUT /heroes/:heroId', () => {
|
||||
expect(heroRes.profile).to.have.all.keys(['name']);
|
||||
|
||||
// test response values
|
||||
expect(heroRes.balance).to.equal(1); // 0+1 for sixth contrib level
|
||||
expect(heroRes.balance).to.equal(15); // 0+15 for sixth contrib level
|
||||
expect(heroRes.contributor.level).to.equal(6);
|
||||
expect(heroRes.items.pets['Dragon-Hydra']).to.equal(5);
|
||||
// test hero values
|
||||
await hero.sync();
|
||||
expect(hero.balance).to.equal(1); // 0+1 for sixth contrib level
|
||||
expect(hero.balance).to.equal(15); // 0+15 for sixth contrib level
|
||||
expect(hero.contributor.level).to.equal(6);
|
||||
expect(hero.items.pets['Dragon-Hydra']).to.equal(5);
|
||||
});
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import {
|
||||
generateUser,
|
||||
translate as t,
|
||||
} from '../../../../helpers/api-integration/v3';
|
||||
import common from '../../../../../website/common';
|
||||
|
||||
describe('GET /members/username/:username', () => {
|
||||
let user;
|
||||
|
||||
before(async () => {
|
||||
user = await generateUser();
|
||||
});
|
||||
|
||||
it('validates req.params.username', async () => {
|
||||
await expect(user.get('/members/username/')).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('invalidReqParams'),
|
||||
});
|
||||
});
|
||||
|
||||
it('returns a member public data only', async () => {
|
||||
// make sure user has all the fields that can be returned by the getMember call
|
||||
const member = await generateUser({
|
||||
contributor: { level: 1 },
|
||||
backer: { tier: 3 },
|
||||
preferences: {
|
||||
costume: false,
|
||||
background: 'volcano',
|
||||
},
|
||||
secret: {
|
||||
text: 'Clark Kent',
|
||||
},
|
||||
});
|
||||
const memberRes = await user.get(`/members/username/${member.auth.local.username}`);
|
||||
expect(memberRes).to.have.all.keys([ // works as: object has all and only these keys
|
||||
'_id', 'id', 'preferences', 'profile', 'stats', 'achievements', 'party',
|
||||
'backer', 'contributor', 'auth', 'items', 'inbox', 'loginIncentives', 'flags',
|
||||
]);
|
||||
expect(Object.keys(memberRes.auth)).to.eql(['local', 'timestamps']);
|
||||
expect(Object.keys(memberRes.preferences).sort()).to.eql([
|
||||
'size', 'hair', 'skin', 'shirt',
|
||||
'chair', 'costume', 'sleep', 'background', 'tasks', 'disableClasses',
|
||||
].sort());
|
||||
|
||||
expect(memberRes.stats.maxMP).to.exist;
|
||||
expect(memberRes.stats.maxHealth).to.equal(common.maxHealth);
|
||||
expect(memberRes.stats.toNextLevel).to.equal(common.tnl(memberRes.stats.lvl));
|
||||
expect(memberRes.inbox.optOut).to.exist;
|
||||
expect(memberRes.inbox.canReceive).to.exist;
|
||||
expect(memberRes.inbox.messages).to.not.exist;
|
||||
expect(memberRes.secret).to.not.exist;
|
||||
|
||||
expect(memberRes.blocks).to.not.exist;
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,104 @@
|
||||
import find from 'lodash/find';
|
||||
import {
|
||||
generateUser,
|
||||
translate as t,
|
||||
} from '../../../helpers/api-integration/v4';
|
||||
|
||||
/**
|
||||
* Checks the messages array if the uniqueMessageId has the like flag
|
||||
* @param {InboxMessage[]} messages
|
||||
* @param {String} uniqueMessageId
|
||||
* @param {String} userId
|
||||
* @param {Boolean} likeStatus
|
||||
*/
|
||||
function expectMessagesLikeStatus (messages, uniqueMessageId, userId, likeStatus) {
|
||||
const messageToCheck = find(messages, { uniqueMessageId });
|
||||
|
||||
expect(messageToCheck.likes[userId]).to.equal(likeStatus);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line mocha/no-exclusive-tests
|
||||
describe('POST /inbox/like-private-message/:messageId', () => {
|
||||
let userToSendMessage;
|
||||
const getLikeUrl = messageId => `/inbox/like-private-message/${messageId}`;
|
||||
|
||||
before(async () => {
|
||||
userToSendMessage = await generateUser();
|
||||
});
|
||||
|
||||
it('Returns an error when private message is not found', async () => {
|
||||
await expect(userToSendMessage.post(getLikeUrl('some-unknown-id')))
|
||||
.to.eventually.be.rejected.and.eql({
|
||||
code: 404,
|
||||
error: 'NotFound',
|
||||
message: t('messageGroupChatNotFound'),
|
||||
});
|
||||
});
|
||||
|
||||
it('Likes a message', async () => {
|
||||
const receiver = await generateUser();
|
||||
|
||||
const sentMessageResult = await userToSendMessage.post('/members/send-private-message', {
|
||||
message: 'some message :)',
|
||||
toUserId: receiver._id,
|
||||
});
|
||||
|
||||
const { uniqueMessageId } = sentMessageResult.message;
|
||||
|
||||
const likeResult = await receiver.post(getLikeUrl(uniqueMessageId));
|
||||
expect(likeResult.likes[receiver._id]).to.equal(true);
|
||||
|
||||
const senderMessages = await userToSendMessage.get('/inbox/messages');
|
||||
|
||||
expectMessagesLikeStatus(senderMessages, uniqueMessageId, receiver._id, true);
|
||||
|
||||
const receiversMessages = await receiver.get('/inbox/messages');
|
||||
|
||||
expectMessagesLikeStatus(receiversMessages, uniqueMessageId, receiver._id, true);
|
||||
});
|
||||
|
||||
it('Allows to likes their own private message', async () => {
|
||||
const receiver = await generateUser();
|
||||
|
||||
const sentMessageResult = await userToSendMessage.post('/members/send-private-message', {
|
||||
message: 'some message :)',
|
||||
toUserId: receiver._id,
|
||||
});
|
||||
|
||||
const { uniqueMessageId } = sentMessageResult.message;
|
||||
|
||||
const likeResult = await userToSendMessage.post(getLikeUrl(uniqueMessageId));
|
||||
expect(likeResult.likes[userToSendMessage._id]).to.equal(true);
|
||||
|
||||
const messages = await userToSendMessage.get('/inbox/messages');
|
||||
expectMessagesLikeStatus(messages, uniqueMessageId, userToSendMessage._id, true);
|
||||
|
||||
const receiversMessages = await receiver.get('/inbox/messages');
|
||||
|
||||
expectMessagesLikeStatus(receiversMessages, uniqueMessageId, userToSendMessage._id, true);
|
||||
});
|
||||
|
||||
it('Unlikes a message', async () => {
|
||||
const receiver = await generateUser();
|
||||
|
||||
const sentMessageResult = await userToSendMessage.post('/members/send-private-message', {
|
||||
message: 'some message :)',
|
||||
toUserId: receiver._id,
|
||||
});
|
||||
|
||||
const { uniqueMessageId } = sentMessageResult.message;
|
||||
|
||||
const likeResult = await receiver.post(getLikeUrl(uniqueMessageId));
|
||||
|
||||
expect(likeResult.likes[receiver._id]).to.equal(true);
|
||||
|
||||
const unlikeResult = await receiver.post(getLikeUrl(uniqueMessageId));
|
||||
|
||||
expect(unlikeResult.likes[receiver._id]).to.equal(false);
|
||||
|
||||
const messages = await userToSendMessage.get('/inbox/messages');
|
||||
|
||||
const messageToCheck = find(messages, { id: sentMessageResult.message.id });
|
||||
expect(messageToCheck.likes[receiver._id]).to.equal(false);
|
||||
});
|
||||
});
|
||||
@@ -144,6 +144,12 @@ describe('Content Schedule', () => {
|
||||
expect(matchers.seasonalGear.end).to.eql(moment.utc(`2025-03-21T${String(switchoverTime).padStart(2, '0')}:00:00.000Z`).toDate());
|
||||
});
|
||||
|
||||
it('sets the end date in new year for a winter gala', () => {
|
||||
const date = new Date('2025-01-04');
|
||||
const matchers = getAllScheduleMatchingGroups(date);
|
||||
expect(matchers.seasonalGear.end).to.eql(moment.utc(`2025-03-21T${String(switchoverTime).padStart(2, '0')}:00:00.000Z`).toDate());
|
||||
});
|
||||
|
||||
it('uses correct date for first hours of the month', () => {
|
||||
// if the date is checked before CONTENT_SWITCHOVER_TIME_OFFSET,
|
||||
// it should be considered the previous month
|
||||
@@ -266,6 +272,21 @@ describe('Content Schedule', () => {
|
||||
expect(matcher.match('backgroundkey072024')).to.be.true;
|
||||
});
|
||||
|
||||
it('allows background matching the month for new backgrounds from multiple years', () => {
|
||||
const date = new Date('2026-07-08');
|
||||
const matcher = getAllScheduleMatchingGroups(date).backgrounds;
|
||||
expect(matcher.match('backgroundkey072024')).to.be.true;
|
||||
expect(matcher.match('backgroundkey072025')).to.be.true;
|
||||
expect(matcher.match('backgroundkey072026')).to.be.true;
|
||||
});
|
||||
|
||||
it('allows background matching the previous month in the first week for new backgrounds', () => {
|
||||
const date = new Date('2024-09-02');
|
||||
const matcher = getAllScheduleMatchingGroups(date).backgrounds;
|
||||
expect(matcher.match('backgroundkey082024')).to.be.true;
|
||||
expect(matcher.match('backgroundkey092024')).to.be.false;
|
||||
});
|
||||
|
||||
it('disallows background in the future', () => {
|
||||
const date = new Date('2024-07-08');
|
||||
const matcher = getAllScheduleMatchingGroups(date).backgrounds;
|
||||
@@ -285,19 +306,26 @@ describe('Content Schedule', () => {
|
||||
expect(matcher.match('backgroundkey022021')).to.be.true;
|
||||
});
|
||||
|
||||
it('allows background even yeared backgrounds in first half of year', () => {
|
||||
it('allows even yeared backgrounds in first half of year', () => {
|
||||
const date = new Date('2025-02-08');
|
||||
const matcher = getAllScheduleMatchingGroups(date).backgrounds;
|
||||
expect(matcher.match('backgroundkey022024')).to.be.true;
|
||||
expect(matcher.match('backgroundkey082022')).to.be.true;
|
||||
});
|
||||
|
||||
it('allows background odd yeared backgrounds in second half of year', () => {
|
||||
it('allows odd yeared backgrounds in second half of year', () => {
|
||||
const date = new Date('2024-08-08');
|
||||
const matcher = getAllScheduleMatchingGroups(date).backgrounds;
|
||||
expect(matcher.match('backgroundkey022023')).to.be.true;
|
||||
expect(matcher.match('backgroundkey082021')).to.be.true;
|
||||
});
|
||||
|
||||
it('allows odd yeared backgrounds in beginning of january', () => {
|
||||
const date = new Date('2025-01-06');
|
||||
const matcher = getAllScheduleMatchingGroups(date).backgrounds;
|
||||
expect(matcher.match('backgroundkey122024'), 'backgroundkey122024').to.be.true;
|
||||
expect(matcher.match('backgroundkey062023'), 'backgroundkey062022').to.be.true;
|
||||
});
|
||||
});
|
||||
|
||||
describe('timeTravelers matcher', () => {
|
||||
|
||||
@@ -7,7 +7,7 @@ module.exports = {
|
||||
extends: [
|
||||
'habitrpg/lib/vue',
|
||||
],
|
||||
ignorePatterns: ['dist/', 'node_modules/'],
|
||||
ignorePatterns: ['dist/', 'node_modules/', '*.d.ts'],
|
||||
rules: {
|
||||
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
|
||||
|
||||
Generated
+210
-76
@@ -3934,9 +3934,9 @@
|
||||
"integrity": "sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w=="
|
||||
},
|
||||
"node_modules/body-parser": {
|
||||
"version": "1.20.2",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
|
||||
"integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
|
||||
"version": "1.20.3",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
|
||||
"integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
|
||||
"dependencies": {
|
||||
"bytes": "3.1.2",
|
||||
"content-type": "~1.0.5",
|
||||
@@ -3946,7 +3946,7 @@
|
||||
"http-errors": "2.0.0",
|
||||
"iconv-lite": "0.4.24",
|
||||
"on-finished": "2.4.1",
|
||||
"qs": "6.11.0",
|
||||
"qs": "6.13.0",
|
||||
"raw-body": "2.5.2",
|
||||
"type-is": "~1.6.18",
|
||||
"unpipe": "1.0.0"
|
||||
@@ -4140,6 +4140,33 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/call-bind-apply-helpers": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz",
|
||||
"integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
"function-bind": "^1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/call-bound": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz",
|
||||
"integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.1",
|
||||
"get-intrinsic": "^1.2.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/callsites": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
|
||||
@@ -4616,9 +4643,9 @@
|
||||
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="
|
||||
},
|
||||
"node_modules/cookie": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
|
||||
"integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
|
||||
"version": "0.7.1",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz",
|
||||
"integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
@@ -5422,6 +5449,19 @@
|
||||
"resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz",
|
||||
"integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA=="
|
||||
},
|
||||
"node_modules/dunder-proto": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.0.tgz",
|
||||
"integrity": "sha512-9+Sj30DIu+4KvHqMfLUGLFYL2PkURSYMVXJyXe92nFRvlYq5hBjLEhblKB+vkd/WVlUYMWigiY07T91Fkk0+4A==",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.0",
|
||||
"es-errors": "^1.3.0",
|
||||
"gopd": "^1.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/duplexer": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
|
||||
@@ -5464,9 +5504,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/encodeurl": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
||||
"integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
|
||||
"integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
@@ -5588,12 +5628,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/es-define-property": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
|
||||
"integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
|
||||
"dependencies": {
|
||||
"get-intrinsic": "^1.2.4"
|
||||
},
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
@@ -5611,6 +5648,17 @@
|
||||
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz",
|
||||
"integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w=="
|
||||
},
|
||||
"node_modules/es-object-atoms": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz",
|
||||
"integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-set-tostringtag": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz",
|
||||
@@ -6695,36 +6743,36 @@
|
||||
}
|
||||
},
|
||||
"node_modules/express": {
|
||||
"version": "4.19.2",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz",
|
||||
"integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==",
|
||||
"version": "4.21.2",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
|
||||
"integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
|
||||
"dependencies": {
|
||||
"accepts": "~1.3.8",
|
||||
"array-flatten": "1.1.1",
|
||||
"body-parser": "1.20.2",
|
||||
"body-parser": "1.20.3",
|
||||
"content-disposition": "0.5.4",
|
||||
"content-type": "~1.0.4",
|
||||
"cookie": "0.6.0",
|
||||
"cookie": "0.7.1",
|
||||
"cookie-signature": "1.0.6",
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
"encodeurl": "~1.0.2",
|
||||
"encodeurl": "~2.0.0",
|
||||
"escape-html": "~1.0.3",
|
||||
"etag": "~1.8.1",
|
||||
"finalhandler": "1.2.0",
|
||||
"finalhandler": "1.3.1",
|
||||
"fresh": "0.5.2",
|
||||
"http-errors": "2.0.0",
|
||||
"merge-descriptors": "1.0.1",
|
||||
"merge-descriptors": "1.0.3",
|
||||
"methods": "~1.1.2",
|
||||
"on-finished": "2.4.1",
|
||||
"parseurl": "~1.3.3",
|
||||
"path-to-regexp": "0.1.7",
|
||||
"path-to-regexp": "0.1.12",
|
||||
"proxy-addr": "~2.0.7",
|
||||
"qs": "6.11.0",
|
||||
"qs": "6.13.0",
|
||||
"range-parser": "~1.2.1",
|
||||
"safe-buffer": "5.2.1",
|
||||
"send": "0.18.0",
|
||||
"serve-static": "1.15.0",
|
||||
"send": "0.19.0",
|
||||
"serve-static": "1.16.2",
|
||||
"setprototypeof": "1.2.0",
|
||||
"statuses": "2.0.1",
|
||||
"type-is": "~1.6.18",
|
||||
@@ -6733,6 +6781,10 @@
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.10.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/express/node_modules/array-flatten": {
|
||||
@@ -6877,12 +6929,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/finalhandler": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
|
||||
"integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
|
||||
"integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
|
||||
"dependencies": {
|
||||
"debug": "2.6.9",
|
||||
"encodeurl": "~1.0.2",
|
||||
"encodeurl": "~2.0.0",
|
||||
"escape-html": "~1.0.3",
|
||||
"on-finished": "2.4.1",
|
||||
"parseurl": "~1.3.3",
|
||||
@@ -7125,15 +7177,20 @@
|
||||
}
|
||||
},
|
||||
"node_modules/get-intrinsic": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
|
||||
"integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
|
||||
"version": "1.2.6",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.6.tgz",
|
||||
"integrity": "sha512-qxsEs+9A+u85HhllWJJFicJfPDhRmjzoYdl64aMWW9yRIJmSyxdn8IEkuIM530/7T+lv0TIHd8L6Q/ra0tEoeA==",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.1",
|
||||
"dunder-proto": "^1.0.0",
|
||||
"es-define-property": "^1.0.1",
|
||||
"es-errors": "^1.3.0",
|
||||
"es-object-atoms": "^1.0.0",
|
||||
"function-bind": "^1.1.2",
|
||||
"has-proto": "^1.0.1",
|
||||
"has-symbols": "^1.0.3",
|
||||
"hasown": "^2.0.0"
|
||||
"gopd": "^1.2.0",
|
||||
"has-symbols": "^1.1.0",
|
||||
"hasown": "^2.0.2",
|
||||
"math-intrinsics": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -7253,11 +7310,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/gopd": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
|
||||
"integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
|
||||
"dependencies": {
|
||||
"get-intrinsic": "^1.1.3"
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
@@ -7353,9 +7410,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/has-symbols": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
|
||||
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
||||
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
@@ -7383,9 +7440,9 @@
|
||||
"integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg=="
|
||||
},
|
||||
"node_modules/hasown": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz",
|
||||
"integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==",
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
||||
"dependencies": {
|
||||
"function-bind": "^1.1.2"
|
||||
},
|
||||
@@ -8919,6 +8976,14 @@
|
||||
"markdown-it": "bin/markdown-it.js"
|
||||
}
|
||||
},
|
||||
"node_modules/math-intrinsics": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.0.0.tgz",
|
||||
"integrity": "sha512-4MqMiKP90ybymYvsut0CH2g4XWbfLtmlCkXmtmdcDCxNB+mQcu1w/1+L/VD7vi/PSv7X2JYV7SCcR+jiPXnQtA==",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/mdn-data": {
|
||||
"version": "2.0.14",
|
||||
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
|
||||
@@ -8958,9 +9023,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/merge-descriptors": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
|
||||
"integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
|
||||
"integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/merge-source-map": {
|
||||
"version": "1.1.0",
|
||||
@@ -9862,9 +9930,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/object-inspect": {
|
||||
"version": "1.13.1",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz",
|
||||
"integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==",
|
||||
"version": "1.13.3",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz",
|
||||
"integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
@@ -10310,9 +10381,9 @@
|
||||
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
|
||||
},
|
||||
"node_modules/path-to-regexp": {
|
||||
"version": "0.1.7",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
|
||||
"integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
|
||||
"version": "0.1.12",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
|
||||
"integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ=="
|
||||
},
|
||||
"node_modules/path-type": {
|
||||
"version": "4.0.0",
|
||||
@@ -11129,11 +11200,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/qs": {
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
|
||||
"integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
|
||||
"version": "6.13.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
|
||||
"integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
|
||||
"dependencies": {
|
||||
"side-channel": "^1.0.4"
|
||||
"side-channel": "^1.0.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.6"
|
||||
@@ -11736,9 +11807,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/send": {
|
||||
"version": "0.18.0",
|
||||
"resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
|
||||
"integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
|
||||
"version": "0.19.0",
|
||||
"resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
|
||||
"integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
|
||||
"dependencies": {
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
@@ -11771,6 +11842,14 @@
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||
},
|
||||
"node_modules/send/node_modules/encodeurl": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
||||
"integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/send/node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
@@ -11855,14 +11934,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/serve-static": {
|
||||
"version": "1.15.0",
|
||||
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
|
||||
"integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
|
||||
"version": "1.16.2",
|
||||
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
|
||||
"integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
|
||||
"dependencies": {
|
||||
"encodeurl": "~1.0.2",
|
||||
"encodeurl": "~2.0.0",
|
||||
"escape-html": "~1.0.3",
|
||||
"parseurl": "~1.3.3",
|
||||
"send": "0.18.0"
|
||||
"send": "0.19.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
@@ -11951,13 +12030,68 @@
|
||||
}
|
||||
},
|
||||
"node_modules/side-channel": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
|
||||
"integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
|
||||
"integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.0",
|
||||
"get-intrinsic": "^1.0.2",
|
||||
"object-inspect": "^1.9.0"
|
||||
"es-errors": "^1.3.0",
|
||||
"object-inspect": "^1.13.3",
|
||||
"side-channel-list": "^1.0.0",
|
||||
"side-channel-map": "^1.0.1",
|
||||
"side-channel-weakmap": "^1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/side-channel-list": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
|
||||
"integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
"object-inspect": "^1.13.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/side-channel-map": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
|
||||
"integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.2",
|
||||
"es-errors": "^1.3.0",
|
||||
"get-intrinsic": "^1.2.5",
|
||||
"object-inspect": "^1.13.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/side-channel-weakmap": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
|
||||
"integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.2",
|
||||
"es-errors": "^1.3.0",
|
||||
"get-intrinsic": "^1.2.5",
|
||||
"object-inspect": "^1.13.3",
|
||||
"side-channel-map": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
|
||||
@@ -2396,6 +2396,11 @@
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_winter_landscape_with_cabin {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_winter_landscape_with_cabin.png');
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_winter_mountain_range {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_winter_mountain_range.png');
|
||||
width: 141px;
|
||||
@@ -29904,6 +29909,11 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.broad_armor_armoire_snowyFluffTrimmedCoat {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_armoire_snowyFluffTrimmedCoat.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.broad_armor_armoire_softBlackSuit {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_armoire_softBlackSuit.png');
|
||||
width: 114px;
|
||||
@@ -30469,6 +30479,11 @@
|
||||
width: 117px;
|
||||
height: 120px;
|
||||
}
|
||||
.head_armoire_snowyTrapperHat {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_armoire_snowyTrapperHat.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.head_armoire_stormKnightHelm {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_armoire_stormKnightHelm.png');
|
||||
width: 114px;
|
||||
@@ -31389,6 +31404,11 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.slim_armor_armoire_snowyFluffTrimmedCoat {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_armoire_snowyFluffTrimmedCoat.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.slim_armor_armoire_softBlackSuit {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_armoire_softBlackSuit.png');
|
||||
width: 114px;
|
||||
@@ -33699,6 +33719,16 @@
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
}
|
||||
.head_mystery_202501 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_mystery_202501.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.shield_mystery_202501 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_mystery_202501.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.back_mystery_201402 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/back_mystery_201402.png');
|
||||
width: 90px;
|
||||
@@ -40067,6 +40097,66 @@
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
}
|
||||
.notif_2013hat_nye {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/notif_2013hat_nye.png');
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
}
|
||||
.notif_2014hat_nye {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/notif_2014hat_nye.png');
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
}
|
||||
.notif_2015hat_nye {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/notif_2015hat_nye.png');
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
}
|
||||
.notif_2016hat_nye {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/notif_2016hat_nye.png');
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
}
|
||||
.notif_2017hat_nye {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/notif_2017hat_nye.png');
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
}
|
||||
.notif_2018hat_nye {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/notif_2018hat_nye.png');
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
}
|
||||
.notif_2019hat_nye {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/notif_2019hat_nye.png');
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
}
|
||||
.notif_2020hat_nye {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/notif_2020hat_nye.png');
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
}
|
||||
.notif_2021hat_nye {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/notif_2021hat_nye.png');
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
}
|
||||
.notif_2022hat_nye {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/notif_2022hat_nye.png');
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
}
|
||||
.notif_2023hat_nye {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/notif_2023hat_nye.png');
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
}
|
||||
.notif_candy_nye {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/notif_candy_nye.png');
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
}
|
||||
.notif_habitoween_base_mount {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/notif_habitoween_base_mount.png');
|
||||
width: 28px;
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
line-height: 1.71;
|
||||
border: 1px solid transparent;
|
||||
padding: 4px 12px;
|
||||
line-height: 1.714;
|
||||
border: 2px solid transparent;
|
||||
padding: 2px 12px;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 1px 3px 0 rgba($black, 0.12), 0 1px 2px 0 rgba($black, 0.24);
|
||||
color: $white;
|
||||
@@ -19,7 +19,7 @@
|
||||
}
|
||||
|
||||
&:focus {
|
||||
border-color: $purple-400;
|
||||
box-shadow: 0 3px 6px 0 rgba($black, 0.16), 0 3px 6px 0 rgba($black, 0.24);
|
||||
}
|
||||
|
||||
&:active, &.active:not(.btn-flat) {
|
||||
@@ -30,9 +30,9 @@
|
||||
cursor: default;
|
||||
color: $gray-50;
|
||||
opacity: 0.75;
|
||||
box-shadow: 0 1px 3px 0 rgba(26, 24, 29, 0.12), 0 1px 2px 0 rgba(26, 24, 29, 0.24);
|
||||
box-shadow: none;
|
||||
background-color: $gray-700;
|
||||
border: 1px solid transparent;
|
||||
border: 2px solid transparent;
|
||||
|
||||
.svg {
|
||||
color: $gray-300;
|
||||
@@ -40,7 +40,7 @@
|
||||
}
|
||||
|
||||
&.with-icon {
|
||||
height: 2rem; // otherwise would something set the height to 33px
|
||||
height: 32px; // otherwise would something set the height to 33px
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
@@ -48,40 +48,47 @@
|
||||
}
|
||||
|
||||
.btn-front {
|
||||
border: none !important;
|
||||
font-size: 16px;
|
||||
line-height: 1.5;
|
||||
padding: 7.5px 15.5px;
|
||||
padding: 2px 17px;
|
||||
|
||||
&:hover {
|
||||
border: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: $purple-200;
|
||||
border: 1px solid transparent;
|
||||
border: 2px solid transparent;
|
||||
line-height: 1.714;
|
||||
--icon-color: #{$purple-500};
|
||||
|
||||
&:focus {
|
||||
background: $purple-200;
|
||||
border-color: $purple-400;
|
||||
border: 2px solid $purple-400;
|
||||
box-shadow: 0 3px 6px 0 rgba($black, 0.16), 0 3px 6px 0 rgba($black, 0.24);
|
||||
--icon-color: #{$white};
|
||||
}
|
||||
|
||||
&:not(:disabled):not(.disabled) {
|
||||
&:hover {
|
||||
background: #5d3b9c;
|
||||
border: 1px solid transparent;
|
||||
background: $purple-200;
|
||||
border: 2px solid transparent;
|
||||
|
||||
--icon-color: #{$white};
|
||||
}
|
||||
|
||||
&:active, &.active {
|
||||
background: $purple-200;
|
||||
border: 1px solid transparent;
|
||||
border: 2px solid transparent;
|
||||
box-shadow: none;
|
||||
|
||||
--icon-color: #{$white};
|
||||
}
|
||||
|
||||
&:active:focus, &.active:focus {
|
||||
box-shadow: none;
|
||||
border-color: $purple-400;
|
||||
border: 2px solid $purple-400;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,42 +101,45 @@
|
||||
|
||||
.btn-secondary,
|
||||
.dropdown > .btn-secondary.dropdown-toggle:not(.btn-success),
|
||||
.show > .btn-secondary.dropdown-toggle:not(.btn-success)
|
||||
{
|
||||
.show > .btn-secondary.dropdown-toggle:not(.btn-success) {
|
||||
background: $white;
|
||||
border: 1px solid transparent;
|
||||
border: 2px solid transparent;
|
||||
color: $gray-50;
|
||||
|
||||
--icon-color: #{$gray-200};
|
||||
|
||||
&:focus, &:active {
|
||||
color: $gray-50;
|
||||
background: $white;
|
||||
border-color: $purple-400;
|
||||
border: 2px solid $purple-400;
|
||||
color: $gray-50;
|
||||
|
||||
--icon-color: #{$purple-300};
|
||||
}
|
||||
|
||||
&:not(:disabled):not(.disabled) {
|
||||
&:active, &.active {
|
||||
background: $white;
|
||||
border: 2px solid $purple-400;
|
||||
color: $purple-300;
|
||||
--icon-color: #{$purple-300};
|
||||
|
||||
&:focus {
|
||||
color: $purple-300;
|
||||
box-shadow: none;
|
||||
border-color: $purple-400;
|
||||
border: 2px solid $purple-400;
|
||||
box-shadow: 0 3px 6px 0 rgba($black, 0.16), 0 3px 6px 0 rgba($black, 0.24);
|
||||
}
|
||||
|
||||
&:active {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
background: $white;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: $purple-300;
|
||||
|
||||
background: $white !important;
|
||||
border: 1px solid transparent;
|
||||
border: 2px solid transparent;
|
||||
|
||||
--icon-color: #{$purple-300};
|
||||
.svg {
|
||||
@@ -151,91 +161,116 @@
|
||||
|
||||
.btn-danger {
|
||||
background: $maroon-100;
|
||||
border: 1px solid transparent;
|
||||
border: 2px solid transparent;
|
||||
box-shadow: 0 1px 3px 0 rgba($black, 0.16), 0 1px 3px 0 rgba($black, 0.24);
|
||||
|
||||
|
||||
&:hover:not(:disabled):not(.disabled) {
|
||||
background: #e14e4e;
|
||||
border: 1px solid transparent;
|
||||
background: $maroon-100;
|
||||
border: 2px solid transparent;
|
||||
box-shadow: 0 3px 6px 0 rgba($black, 0.16), 0 3px 6px 0 rgba($black, 0.24);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
background: $maroon-100;
|
||||
border-color: $purple-400;
|
||||
border: 2px solid $purple-400;
|
||||
}
|
||||
|
||||
&:not(:disabled):not(.disabled):active:focus, &:not(:disabled):not(.disabled).active:focus {
|
||||
box-shadow: none;
|
||||
border-color: $purple-400;
|
||||
border: 2px solid $purple-400;
|
||||
}
|
||||
|
||||
&:not(:disabled):not(.disabled):active, &:not(:disabled):not(.disabled).active {
|
||||
background: $maroon-100;
|
||||
border: 1px solid transparent;
|
||||
border: 2px solid $purple-400;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-warning {
|
||||
background: $orange-10;
|
||||
box-shadow: 0 1px 3px 0 rgba($black, 0.16), 0 1px 3px 0 rgba($black, 0.24);
|
||||
color: $white !important;
|
||||
|
||||
&:hover:not(:disabled):not(.disabled) {
|
||||
background: $orange-100;
|
||||
background: $orange-10;
|
||||
color: $white;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
background: $orange-10;
|
||||
border-color: $purple-400;
|
||||
border: 2px solid $purple-400;
|
||||
}
|
||||
|
||||
&:not(:disabled):not(.disabled):active:focus, &:not(:disabled):not(.disabled).active:focus {
|
||||
border: 2px solid $purple-400;
|
||||
box-shadow: none;
|
||||
border-color: $purple-400;
|
||||
}
|
||||
|
||||
&:not(:disabled):not(.disabled):active, &:not(:disabled):not(.disabled).active {
|
||||
background: $orange-10;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-success {
|
||||
background: $green-50;
|
||||
border: 1px solid transparent;
|
||||
border: 2px solid transparent;
|
||||
|
||||
&:hover:not(:disabled):not(.disabled) {
|
||||
background: #32bd8a;
|
||||
border: 1px solid transparent;
|
||||
background: $green-50;
|
||||
border: 2px solid transparent;
|
||||
box-shadow: 0 3px 6px 0 rgba($black, 0.16), 0 3px 6px 0 rgba($black, 0.24);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
background: $green-50;
|
||||
border-color: $purple-400;
|
||||
border: 2px solid $purple-400;
|
||||
box-shadow: 0 3px 6px 0 rgba($black, 0.16), 0 3px 6px 0 rgba($black, 0.24);
|
||||
}
|
||||
|
||||
&:not(:disabled):not(.disabled):active:focus, &:not(:disabled):not(.disabled).active:focus {
|
||||
border: 2px solid $purple-400;
|
||||
box-shadow: none;
|
||||
border-color: $purple-400;
|
||||
}
|
||||
|
||||
&:not(:disabled):not(.disabled):active, &:not(:disabled):not(.disabled).active {
|
||||
background: $green-50;
|
||||
border: 1px solid transparent;
|
||||
border: 2px solid $purple-400;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-info {
|
||||
background: $blue-50;
|
||||
border: 2px solid transparent;
|
||||
box-shadow: 0 1px 3px 0 rgba($black, 0.16), 0 1px 3px 0 rgba($black, 0.24);
|
||||
|
||||
&:disabled {
|
||||
background: $blue-50;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border: 2px solid transparent;
|
||||
box-shadow: 0 3px 6px 0 rgba($black, 0.16), 0 3px 6px 0 rgba($black, 0.24);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
background: $blue-100;
|
||||
border: 2px solid $purple-400;
|
||||
box-shadow: 0 3px 6px 0 rgba($black, 0.16), 0 3px 6px 0 rgba($black, 0.24);
|
||||
}
|
||||
|
||||
&:hover:not(:disabled):not(.disabled) {
|
||||
background-color: $blue-100;
|
||||
box-shadow: 0 3px 6px 0 rgba($black, 0.16), 0 3px 6px 0 rgba($black, 0.24);
|
||||
}
|
||||
|
||||
&:active:not(:disabled):not(.disabled), &.active:not(:disabled):not(.disabled) {
|
||||
background: $blue-50;
|
||||
background: $blue-100;
|
||||
border: 2px solid $purple-400;
|
||||
box-shadow: 0 3px 6px 0 rgba($black, 0.16), 0 3px 6px 0 rgba($black, 0.24);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,7 +279,7 @@
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
font-size: 14px;
|
||||
line-height: 1.43;
|
||||
line-height: 1.714;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
background: $gray-500;
|
||||
@@ -262,12 +297,22 @@
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.btn-flat,
|
||||
.dropdown > .btn-flat.dropdown-toggle:not(.btn-success),
|
||||
.show > .btn-flat.dropdown-toggle:not(.btn-success) {
|
||||
&.with-icon {
|
||||
.svg-icon.color {
|
||||
color: var(--icon-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn-cancel {
|
||||
color: $blue-10;
|
||||
}
|
||||
|
||||
.btn-small {
|
||||
font-size: 12px;
|
||||
line-height: 1.33;
|
||||
padding: 4px 8px;
|
||||
line-height: 2;
|
||||
padding: 2px 2px;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
.dropdown > .btn {
|
||||
padding: 0.219rem 0.75rem;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
line-height: 1.714;
|
||||
padding: 2px 12px;
|
||||
}
|
||||
|
||||
.dropdown-toggle:hover {
|
||||
@@ -33,11 +34,16 @@
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
padding: 0px;
|
||||
border: none;
|
||||
border: transparent;
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 3px 6px 0 rgba(26, 24, 29, 0.16), 0 3px 6px 0 rgba(26, 24, 29, 0.24);
|
||||
box-shadow: 0 3px 6px 0 rgba($black, 0.16), 0 3px 6px 0 rgba($black, 0.24);
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.no-min-width {
|
||||
.dropdown-menu {
|
||||
min-width: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
// shared dropdown-item styles
|
||||
@@ -53,6 +59,8 @@
|
||||
color: $gray-50 !important;
|
||||
cursor: pointer;
|
||||
|
||||
--dropdown-item-hover-icon-color: #{$gray-200};
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
background-color: inherit;
|
||||
@@ -87,7 +95,7 @@
|
||||
|
||||
&:not(:hover) {
|
||||
.with-icon .svg-icon {
|
||||
color: $gray-200;
|
||||
color: var(dropdown-item-hover-icon-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -113,6 +121,10 @@
|
||||
}
|
||||
|
||||
.dropdown-icon-item {
|
||||
line-height: 1;
|
||||
padding-top: 2px !important;
|
||||
padding-bottom: 2px !important;
|
||||
|
||||
.svg-icon {
|
||||
margin: 0px 16px 0px 0px;
|
||||
vertical-align: middle;
|
||||
@@ -128,7 +140,6 @@
|
||||
|
||||
.dropdown-toggle {
|
||||
width: 100% !important;
|
||||
height: 32px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
@@ -147,7 +158,7 @@
|
||||
|
||||
// selectList.vue items sizing
|
||||
.selectListItem .dropdown-item {
|
||||
padding: 0.25rem 0.75rem;
|
||||
padding: 0.25rem 1rem 0.25rem 0.75rem;
|
||||
height: 32px;
|
||||
|
||||
&:active, &:hover, &:focus, &.active {
|
||||
|
||||
@@ -105,6 +105,11 @@
|
||||
<style lang="scss" scoped>
|
||||
@import '~@/assets/scss/colors.scss';
|
||||
|
||||
.btn-primary:active {
|
||||
border: 2px solid $purple-400 !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.class-badge {
|
||||
$badge-size: 32px;
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
:class="{'open': expand}"
|
||||
@click="expand = !expand"
|
||||
>
|
||||
Priviliges, Gem Balance
|
||||
Privileges, Gem Balance
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
|
||||
@@ -131,13 +131,6 @@
|
||||
>{{ $t('requestFeature') }}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://habitica.fandom.com/"
|
||||
target="_blank"
|
||||
>{{ $t('wiki') }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- Developers -->
|
||||
@@ -186,7 +179,7 @@
|
||||
</div>
|
||||
<div class="donate-button">
|
||||
<button
|
||||
class="button btn-contribute"
|
||||
class="btn button btn-secondary btn-contribute"
|
||||
@click="donate()"
|
||||
>
|
||||
<div class="text">
|
||||
@@ -309,7 +302,7 @@
|
||||
<div class="my-2">
|
||||
Time Traveling! It is {{ new Date().toLocaleDateString() }}
|
||||
<a
|
||||
class="btn btn-warning btn-small"
|
||||
class="btn btn-small"
|
||||
@click="resetTime()"
|
||||
>
|
||||
Reset
|
||||
@@ -341,7 +334,7 @@
|
||||
</button>
|
||||
<div
|
||||
v-if="debugMenuShown"
|
||||
class="debug-toggle debug-group"
|
||||
class="btn debug-toggle debug-group"
|
||||
>
|
||||
<div class="debug-pop">
|
||||
<a
|
||||
@@ -512,7 +505,14 @@ li {
|
||||
grid-area: debug-pop;
|
||||
}
|
||||
|
||||
.time-travel { grid-area: time-travel;}
|
||||
.time-travel {
|
||||
grid-area: time-travel;
|
||||
|
||||
a:hover {
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
footer {
|
||||
background-color: $gray-500;
|
||||
@@ -584,42 +584,65 @@ h3 {
|
||||
}
|
||||
|
||||
.debug {
|
||||
margin-top: 16px;
|
||||
border: 2px solid transparent;
|
||||
box-shadow: 0 1px 3px 0 rgba($black, 0.12), 0 1px 2px 0 rgba($black, 0.24);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 16px;
|
||||
padding: 2px 12px;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 3px 6px 0 rgba($black, 0.12), 0 3px 6px 0 rgba($black, 0.24);
|
||||
}
|
||||
&:focus {
|
||||
border: 2px solid $purple-400 !important;
|
||||
box-shadow: 0 3px 6px 0 rgba($black, 0.12), 0 3px 6px 0 rgba($black, 0.24);
|
||||
}
|
||||
:active {
|
||||
border: 2px solid $purple-600 !important;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
.debug-group {
|
||||
border-radius: 4px;
|
||||
padding: 16px;
|
||||
box-shadow: 0 1px 3px 0 rgba(26, 24, 29, 0.12), 0 1px 2px 0 rgba(26, 24, 29, 0.24);
|
||||
font-weight: 700;
|
||||
background-color: $gray-600;
|
||||
border: 2px solid transparent;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 1px 3px 0 rgba($black, 0.12), 0 1px 2px 0 rgba($black, 0.24);
|
||||
font-weight: 700;
|
||||
padding: 8px 16px;
|
||||
|
||||
.btn {
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
border: 2px solid transparent;
|
||||
box-shadow: 0 1px 3px 0 rgba($black, 0.12), 0 1px 2px 0 rgba($black, 0.24);
|
||||
text-decoration: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-small {
|
||||
background-color: $maroon-100;
|
||||
border: 2px solid transparent;
|
||||
color: $white !important;
|
||||
line-height: 18px;
|
||||
&:hover {
|
||||
background-color: $maroon-100;
|
||||
text-decoration: none !important;
|
||||
border: 2px solid $maroon-100;
|
||||
}
|
||||
}
|
||||
.btn-secondary {
|
||||
padding: 2px 12px;
|
||||
}
|
||||
.btn-secondary a:hover {
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
.btn-contribute {
|
||||
background: $white;
|
||||
border-radius: 2px;
|
||||
width: 175px;
|
||||
height: 32px;
|
||||
color: $gray-50;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
&:hover {
|
||||
color:$purple-300;
|
||||
box-shadow: 0 3px 6px 0 rgba(26, 24, 29, 0.16), 0 3px 6px 0 rgba(26, 24, 29, 0.24);
|
||||
&:active:not(:disabled) {
|
||||
color:$purple-300;
|
||||
border: 1px solid $purple-400;
|
||||
box-shadow: 0 3px 6px 0 rgba(26, 24, 29, 0.16), 0 3px 6px 0 rgba(26, 24, 29, 0.24);
|
||||
}
|
||||
}
|
||||
border: 2px solid transparent;
|
||||
|
||||
a {
|
||||
display: flex;
|
||||
|
||||
@@ -1,93 +1,100 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="member.preferences"
|
||||
class="avatar"
|
||||
:style="{width, height, paddingTop}"
|
||||
:class="backgroundClass"
|
||||
@click.prevent="castEnd()"
|
||||
>
|
||||
<div class="avatar-wrapper">
|
||||
<div
|
||||
class="character-sprites"
|
||||
:style="{margin: spritesMargin}"
|
||||
v-if="member.preferences"
|
||||
class="avatar"
|
||||
:style="{width, height, paddingTop}"
|
||||
:class="topLevelClassList"
|
||||
@click.prevent="castEnd()"
|
||||
>
|
||||
<template v-if="!avatarOnly">
|
||||
<!-- Mount Body-->
|
||||
<span
|
||||
v-if="member.items.currentMount"
|
||||
:class="'Mount_Body_' + member.items.currentMount"
|
||||
></span>
|
||||
</template>
|
||||
<!-- Buffs that cause visual changes to avatar: Snowman, Ghost, Flower, etc-->
|
||||
<template v-for="(klass, item) in visualBuffs">
|
||||
<span
|
||||
v-if="member.stats.buffs[item] && showVisualBuffs"
|
||||
:key="item"
|
||||
:class="klass"
|
||||
></span>
|
||||
</template>
|
||||
<!-- Show flower ALL THE TIME!!!-->
|
||||
<!-- See https://github.com/HabitRPG/habitica/issues/7133-->
|
||||
<span :class="'hair_flower_' + member.preferences.hair.flower"></span>
|
||||
<!-- Show avatar only if not currently affected by visual buff-->
|
||||
<template v-if="showAvatar()">
|
||||
<span :class="['chair_' + member.preferences.chair, specialMountClass]"></span>
|
||||
<span :class="[getGearClass('back'), specialMountClass]"></span>
|
||||
<span :class="[skinClass, specialMountClass]"></span>
|
||||
<!-- eslint-disable max-len-->
|
||||
<span
|
||||
:class="[shirtClass, specialMountClass]"
|
||||
></span>
|
||||
<!-- eslint-enable max-len-->
|
||||
<span :class="['head_0', specialMountClass]"></span>
|
||||
<!-- eslint-disable max-len-->
|
||||
<span :class="[member.preferences.size + '_' + getGearClass('armor'), specialMountClass]"></span>
|
||||
<!-- eslint-enable max-len-->
|
||||
<span :class="[getGearClass('back_collar'), specialMountClass]"></span>
|
||||
<template
|
||||
v-for="type in ['bangs', 'base', 'mustache', 'beard']"
|
||||
>
|
||||
<div
|
||||
class="character-sprites"
|
||||
:style="{margin: spritesMargin}"
|
||||
>
|
||||
<template v-if="!avatarOnly">
|
||||
<!-- Mount Body-->
|
||||
<span
|
||||
:key="type"
|
||||
:class="[hairClass(type), specialMountClass]"
|
||||
v-if="member.items.currentMount"
|
||||
:class="'Mount_Body_' + member.items.currentMount"
|
||||
></span>
|
||||
</template>
|
||||
<span :class="[getGearClass('body'), specialMountClass]"></span>
|
||||
<span :class="[getGearClass('eyewear'), specialMountClass]"></span>
|
||||
<span :class="[getGearClass('head'), specialMountClass]"></span>
|
||||
<span :class="[getGearClass('headAccessory'), specialMountClass]"></span>
|
||||
<span :class="['hair_flower_' + member.preferences.hair.flower, specialMountClass]"></span>
|
||||
<!-- Buffs that cause visual changes to avatar: Snowman, Ghost, Flower, etc-->
|
||||
<template v-for="(klass, item) in visualBuffs">
|
||||
<span
|
||||
v-if="member.stats.buffs[item] && showVisualBuffs"
|
||||
:key="item"
|
||||
:class="klass"
|
||||
></span>
|
||||
</template>
|
||||
<!-- Show flower ALL THE TIME!!!-->
|
||||
<!-- See https://github.com/HabitRPG/habitica/issues/7133-->
|
||||
<span :class="'hair_flower_' + member.preferences.hair.flower"></span>
|
||||
<!-- Show avatar only if not currently affected by visual buff-->
|
||||
<template v-if="showAvatar()">
|
||||
<span :class="['chair_' + member.preferences.chair, specialMountClass]"></span>
|
||||
<span :class="[getGearClass('back'), specialMountClass]"></span>
|
||||
<span :class="[skinClass, specialMountClass]"></span>
|
||||
<!-- eslint-disable max-len-->
|
||||
<span
|
||||
:class="[shirtClass, specialMountClass]"
|
||||
></span>
|
||||
<!-- eslint-enable max-len-->
|
||||
<span :class="['head_0', specialMountClass]"></span>
|
||||
<!-- eslint-disable max-len-->
|
||||
<span :class="[member.preferences.size + '_' + getGearClass('armor'), specialMountClass]"></span>
|
||||
<!-- eslint-enable max-len-->
|
||||
<span :class="[getGearClass('back_collar'), specialMountClass]"></span>
|
||||
<template
|
||||
v-for="type in ['bangs', 'base', 'mustache', 'beard']"
|
||||
>
|
||||
<span
|
||||
:key="type"
|
||||
:class="[hairClass(type), specialMountClass]"
|
||||
></span>
|
||||
</template>
|
||||
<span :class="[getGearClass('body'), specialMountClass]"></span>
|
||||
<span :class="[getGearClass('eyewear'), specialMountClass]"></span>
|
||||
<span :class="[getGearClass('head'), specialMountClass]"></span>
|
||||
<span :class="[getGearClass('headAccessory'), specialMountClass]"></span>
|
||||
<span
|
||||
:class="[
|
||||
'hair_flower_' + member.preferences.hair.flower, specialMountClass
|
||||
]"
|
||||
></span>
|
||||
<span
|
||||
v-if="!hideGear('shield')"
|
||||
:class="[getGearClass('shield'), specialMountClass]"
|
||||
></span>
|
||||
<span
|
||||
v-if="!hideGear('weapon')"
|
||||
:class="[getGearClass('weapon'), specialMountClass]"
|
||||
class="weapon"
|
||||
></span>
|
||||
</template>
|
||||
<!-- Resting-->
|
||||
<span
|
||||
v-if="!hideGear('shield')"
|
||||
:class="[getGearClass('shield'), specialMountClass]"
|
||||
v-if="member.preferences.sleep"
|
||||
class="zzz"
|
||||
></span>
|
||||
<span
|
||||
v-if="!hideGear('weapon')"
|
||||
:class="[getGearClass('weapon'), specialMountClass]"
|
||||
></span>
|
||||
</template>
|
||||
<!-- Resting-->
|
||||
<span
|
||||
v-if="member.preferences.sleep"
|
||||
class="zzz"
|
||||
></span>
|
||||
<template v-if="!avatarOnly">
|
||||
<!-- Mount Head-->
|
||||
<span
|
||||
v-if="member.items.currentMount"
|
||||
:class="'Mount_Head_' + member.items.currentMount"
|
||||
></span>
|
||||
<!-- Pet-->
|
||||
<span
|
||||
class="current-pet"
|
||||
:class="petClass"
|
||||
></span>
|
||||
</template>
|
||||
<template v-if="!avatarOnly">
|
||||
<!-- Mount Head-->
|
||||
<span
|
||||
v-if="member.items.currentMount"
|
||||
:class="'Mount_Head_' + member.items.currentMount"
|
||||
></span>
|
||||
<!-- Pet-->
|
||||
<span
|
||||
class="current-pet"
|
||||
:class="petClass"
|
||||
></span>
|
||||
</template>
|
||||
</div>
|
||||
<class-badge
|
||||
v-if="hasClass && !hideClassBadge"
|
||||
class="under-avatar"
|
||||
:member-class="member.stats.class"
|
||||
/>
|
||||
</div>
|
||||
<class-badge
|
||||
v-if="hasClass && !hideClassBadge"
|
||||
class="under-avatar"
|
||||
:member-class="member.stats.class"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -96,15 +103,23 @@
|
||||
|
||||
.avatar {
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
image-rendering: pixelated;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
|
||||
&.centered-avatar {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
// resetting the additional padding
|
||||
margin-bottom: -0.5rem !important;
|
||||
}
|
||||
|
||||
.character-sprites {
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.character-sprites span {
|
||||
@@ -123,6 +138,27 @@
|
||||
.invert {
|
||||
filter: invert(100%);
|
||||
}
|
||||
|
||||
.weapon {
|
||||
// the only one that is relative so that it fits into the parent div
|
||||
position: relative !important;
|
||||
}
|
||||
|
||||
.debug {
|
||||
border: 1px solid red;
|
||||
|
||||
.character-sprites {
|
||||
border: 1px solid blue;
|
||||
}
|
||||
|
||||
.weapon {
|
||||
border: 1px solid green;
|
||||
}
|
||||
|
||||
span {
|
||||
border: 1px solid yellow;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
@@ -133,12 +169,24 @@ import foolPet from '../mixins/foolPet';
|
||||
|
||||
import ClassBadge from '@/components/members/classBadge';
|
||||
|
||||
/**
|
||||
* TODO replace avatarOnly with multiple options like
|
||||
* - showMount
|
||||
* - showPet
|
||||
* - showBackground
|
||||
* - showWeapons
|
||||
*/
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ClassBadge,
|
||||
},
|
||||
mixins: [foolPet],
|
||||
props: {
|
||||
debugMode: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
member: {
|
||||
type: Object,
|
||||
required: true,
|
||||
@@ -156,14 +204,21 @@ export default {
|
||||
},
|
||||
overrideAvatarGear: {
|
||||
type: Object,
|
||||
default (data) {
|
||||
return data;
|
||||
},
|
||||
},
|
||||
width: {
|
||||
type: Number,
|
||||
default: 140,
|
||||
type: String,
|
||||
default: '140px',
|
||||
},
|
||||
height: {
|
||||
type: Number,
|
||||
default: 147,
|
||||
type: String,
|
||||
default: undefined,
|
||||
},
|
||||
centerAvatar: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
spritesMargin: {
|
||||
type: String,
|
||||
@@ -171,11 +226,16 @@ export default {
|
||||
},
|
||||
overrideTopPadding: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
showVisualBuffs: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
showWeapon: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
@@ -204,6 +264,19 @@ export default {
|
||||
|
||||
return val;
|
||||
},
|
||||
topLevelClassList () {
|
||||
const classes = [this.backgroundClass];
|
||||
|
||||
if (this.debugMode) {
|
||||
classes.push('debug');
|
||||
}
|
||||
|
||||
if (this.centerAvatar) {
|
||||
classes.push('centered-avatar');
|
||||
}
|
||||
|
||||
return classes.join(' ');
|
||||
},
|
||||
backgroundClass () {
|
||||
if (this.member) {
|
||||
const { background } = this.member.preferences;
|
||||
@@ -290,6 +363,10 @@ export default {
|
||||
},
|
||||
hideGear (gearType) {
|
||||
if (!this.member) return true;
|
||||
if (!this.showWeapon) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (gearType === 'weapon') {
|
||||
const equippedWeapon = this.member.items.gear[this.costumeClass][gearType];
|
||||
|
||||
|
||||
@@ -25,9 +25,13 @@
|
||||
</b-modal>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
<style scoped lang="scss">
|
||||
.modal-body {
|
||||
padding-bottom: 2em;
|
||||
|
||||
.btn {
|
||||
margin: 0px 2px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -1,352 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<div
|
||||
v-if="isUserMentioned"
|
||||
class="mentioned-icon"
|
||||
></div>
|
||||
<div
|
||||
v-if="hasPermission(user, 'moderator') && msg.flagCount"
|
||||
class="message-hidden"
|
||||
>
|
||||
{{ flagCountDescription }}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<user-link
|
||||
:user-id="msg.uuid"
|
||||
:name="msg.user"
|
||||
:backer="msg.backer"
|
||||
:contributor="msg.contributor"
|
||||
/>
|
||||
<p class="time">
|
||||
<span
|
||||
v-if="msg.username"
|
||||
class="mr-1"
|
||||
>@{{ msg.username }}</span>
|
||||
<span
|
||||
v-if="msg.username"
|
||||
class="mr-1"
|
||||
>•</span>
|
||||
<span
|
||||
v-b-tooltip.hover="messageDate"
|
||||
>{{ msg.timestamp | timeAgo }} </span>
|
||||
<span v-if="msg.client && user.contributor.level >= 4">({{ msg.client }})</span>
|
||||
</p>
|
||||
<div
|
||||
ref="markdownContainer"
|
||||
class="text markdown"
|
||||
dir="auto"
|
||||
v-html="parseMarkdown(msg.text)"
|
||||
></div>
|
||||
<hr>
|
||||
<div
|
||||
v-if="msg.id"
|
||||
class="d-flex"
|
||||
>
|
||||
<div
|
||||
class="action d-flex align-items-center"
|
||||
@click="copyAsTodo(msg)"
|
||||
>
|
||||
<div
|
||||
class="svg-icon"
|
||||
v-html="icons.copy"
|
||||
></div>
|
||||
<div>{{ $t('copyAsTodo') }}</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="(user.flags.communityGuidelinesAccepted && msg.uuid !== 'system')
|
||||
&& (!isMessageReported || hasPermission(user, 'moderator'))"
|
||||
class="action d-flex align-items-center"
|
||||
@click="report(msg)"
|
||||
>
|
||||
<div
|
||||
v-once
|
||||
class="svg-icon"
|
||||
v-html="icons.report"
|
||||
></div>
|
||||
<div v-once>
|
||||
{{ $t('report') }}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="msg.uuid === user._id || hasPermission(user, 'moderator')"
|
||||
class="action d-flex align-items-center"
|
||||
@click="remove()"
|
||||
>
|
||||
<div
|
||||
v-once
|
||||
class="svg-icon"
|
||||
v-html="icons.delete"
|
||||
></div>
|
||||
<div v-once>
|
||||
{{ $t('delete') }}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-b-tooltip="{title: likeTooltip(msg.likes[user._id])}"
|
||||
class="ml-auto d-flex"
|
||||
>
|
||||
<div
|
||||
v-if="likeCount > 0"
|
||||
class="action d-flex align-items-center mr-0"
|
||||
:class="{activeLike: msg.likes[user._id]}"
|
||||
@click="like()"
|
||||
>
|
||||
<div
|
||||
class="svg-icon"
|
||||
:title="$t('liked')"
|
||||
v-html="icons.liked"
|
||||
></div>
|
||||
+{{ likeCount }}
|
||||
</div>
|
||||
<div
|
||||
v-if="likeCount === 0"
|
||||
class="action d-flex align-items-center mr-0"
|
||||
:class="{activeLike: msg.likes[user._id]}"
|
||||
@click="like()"
|
||||
>
|
||||
<div
|
||||
class="svg-icon"
|
||||
:title="$t('like')"
|
||||
v-html="icons.like"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
<span v-if="!msg.likes[user._id]">{{ $t('like') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.at-highlight {
|
||||
background-color: rgba(213, 200, 255, 0.32);
|
||||
padding: 0.1rem;
|
||||
}
|
||||
|
||||
.at-text {
|
||||
color: #6133b4;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~@/assets/scss/colors.scss';
|
||||
|
||||
.mentioned-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 50%;
|
||||
background-color: #bda8ff;
|
||||
box-shadow: 0 1px 1px 0 rgba(26, 24, 29, 0.12);
|
||||
position: absolute;
|
||||
right: -.5em;
|
||||
top: -.5em;
|
||||
}
|
||||
|
||||
.message-hidden {
|
||||
margin-left: 1.5em;
|
||||
margin-top: 1em;
|
||||
color: red;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin-bottom: 0.5rem;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.card-body {
|
||||
padding: 0.75rem 1.25rem 0.75rem 1.25rem;
|
||||
|
||||
.time {
|
||||
font-size: 12px;
|
||||
color: #878190;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.text {
|
||||
font-size: 14px;
|
||||
color: #4e4a57;
|
||||
text-align: initial;
|
||||
min-height: 0rem;
|
||||
}
|
||||
}
|
||||
|
||||
.action {
|
||||
display: inline-block;
|
||||
color: #878190;
|
||||
margin-right: 1em;
|
||||
font-size: 12px;
|
||||
|
||||
:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.svg-icon {
|
||||
color: #A5A1AC;
|
||||
margin-right: .2em;
|
||||
width: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.activeLike {
|
||||
color: $purple-300;
|
||||
|
||||
.svg-icon {
|
||||
color: $purple-400;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import moment from 'moment';
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
import escapeRegExp from 'lodash/escapeRegExp';
|
||||
|
||||
import { CHAT_FLAG_LIMIT_FOR_HIDING, CHAT_FLAG_FROM_SHADOW_MUTE } from '@/../../common/script/constants';
|
||||
import renderWithMentions from '@/libs/renderWithMentions';
|
||||
import { userStateMixin } from '../../mixins/userState';
|
||||
import userLink from '../userLink';
|
||||
|
||||
import deleteIcon from '@/assets/svg/delete.svg';
|
||||
import copyIcon from '@/assets/svg/copy.svg';
|
||||
import likeIcon from '@/assets/svg/like.svg';
|
||||
import likedIcon from '@/assets/svg/liked.svg';
|
||||
import reportIcon from '@/assets/svg/report.svg';
|
||||
|
||||
export default {
|
||||
components: { userLink },
|
||||
filters: {
|
||||
timeAgo (value) {
|
||||
return moment(value).fromNow();
|
||||
},
|
||||
date (value) {
|
||||
// @TODO: Vue doesn't support this so we cant user preference
|
||||
return moment(value).toDate().toString();
|
||||
},
|
||||
},
|
||||
mixins: [userStateMixin],
|
||||
props: {
|
||||
msg: {},
|
||||
groupId: {},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
like: likeIcon,
|
||||
copy: copyIcon,
|
||||
report: reportIcon,
|
||||
delete: deleteIcon,
|
||||
liked: likedIcon,
|
||||
}),
|
||||
reported: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isUserMentioned () {
|
||||
const message = this.msg;
|
||||
|
||||
if (message.highlight) return true;
|
||||
|
||||
const { user } = this;
|
||||
const displayName = user.profile.name;
|
||||
const { username } = user.auth.local;
|
||||
const pattern = `@(${escapeRegExp(displayName)}|${escapeRegExp(username)})(\\b)`;
|
||||
message.highlight = new RegExp(pattern, 'i').test(message.text);
|
||||
|
||||
return message.highlight;
|
||||
},
|
||||
likeCount () {
|
||||
const message = this.msg;
|
||||
if (!message.likes) return 0;
|
||||
|
||||
let likeCount = 0;
|
||||
for (const key of Object.keys(message.likes)) {
|
||||
const like = message.likes[key];
|
||||
if (like) likeCount += 1;
|
||||
}
|
||||
return likeCount;
|
||||
},
|
||||
isMessageReported () {
|
||||
return (this.msg.flags && this.msg.flags[this.user.id]) || this.reported;
|
||||
},
|
||||
flagCountDescription () {
|
||||
if (!this.msg.flagCount) return '';
|
||||
if (this.msg.flagCount < CHAT_FLAG_LIMIT_FOR_HIDING) return 'Message flagged once, not hidden';
|
||||
if (this.msg.flagCount < CHAT_FLAG_FROM_SHADOW_MUTE) return 'Message hidden';
|
||||
return 'Message hidden (shadow-muted)';
|
||||
},
|
||||
messageDate () {
|
||||
const date = moment(this.msg.timestamp).toDate();
|
||||
return date.toString();
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
const links = this.$refs.markdownContainer.getElementsByTagName('a');
|
||||
for (let i = 0; i < links.length; i += 1) {
|
||||
let link = links[i].pathname;
|
||||
|
||||
// Internet Explorer does not provide the leading slash character in the pathname
|
||||
link = link.charAt(0) === '/' ? link : `/${link}`;
|
||||
|
||||
if (link.startsWith('/profile/')) {
|
||||
links[i].onclick = ev => {
|
||||
ev.preventDefault();
|
||||
this.$router.push({ path: link });
|
||||
};
|
||||
}
|
||||
}
|
||||
this.CHAT_FLAG_LIMIT_FOR_HIDING = CHAT_FLAG_LIMIT_FOR_HIDING;
|
||||
this.CHAT_FLAG_FROM_SHADOW_MUTE = CHAT_FLAG_FROM_SHADOW_MUTE;
|
||||
this.$emit('chat-card-mounted', this.msg.id);
|
||||
},
|
||||
methods: {
|
||||
async like () {
|
||||
const message = cloneDeep(this.msg);
|
||||
|
||||
await this.$store.dispatch('chat:like', {
|
||||
groupId: this.groupId,
|
||||
chatId: message.id,
|
||||
});
|
||||
|
||||
message.likes[this.user._id] = !message.likes[this.user._id];
|
||||
|
||||
this.$emit('message-liked', message);
|
||||
this.$root.$emit('bv::hide::tooltip');
|
||||
},
|
||||
likeTooltip (likedStatus) {
|
||||
if (!likedStatus) return this.$t('like');
|
||||
return null;
|
||||
},
|
||||
copyAsTodo (message) {
|
||||
this.$root.$emit('habitica::copy-as-todo', message);
|
||||
},
|
||||
report () {
|
||||
this.$root.$on('habitica:report-result', data => {
|
||||
if (data.ok) {
|
||||
this.reported = true;
|
||||
}
|
||||
|
||||
this.$root.$off('habitica:report-result');
|
||||
});
|
||||
|
||||
this.$root.$emit('habitica::report-chat', {
|
||||
message: this.msg,
|
||||
groupId: this.groupId || 'privateMessage',
|
||||
});
|
||||
},
|
||||
async remove () {
|
||||
if (!window.confirm(this.$t('areYouSureDeleteMessage'))) return; // eslint-disable-line no-alert
|
||||
|
||||
const message = this.msg;
|
||||
this.$emit('message-removed', message);
|
||||
|
||||
await this.$store.dispatch('chat:deleteChat', {
|
||||
groupId: this.groupId,
|
||||
chatId: message.id,
|
||||
});
|
||||
},
|
||||
parseMarkdown (text) {
|
||||
return renderWithMentions(text, this.user);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -3,15 +3,6 @@
|
||||
ref="container"
|
||||
class="container-fluid"
|
||||
>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<copy-as-todo-modal
|
||||
:group-type="groupType"
|
||||
:group-name="groupName"
|
||||
:group-id="groupId"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row loadmore">
|
||||
<div v-if="canLoadMore">
|
||||
<div class="loadmore-divider"></div>
|
||||
@@ -33,6 +24,8 @@
|
||||
<div
|
||||
v-for="msg in messages.filter(m => chat && canViewFlag(m))"
|
||||
:key="msg.id"
|
||||
class="message-row"
|
||||
:class="{ 'margin-right': user._id !== msg.uuid}"
|
||||
>
|
||||
<div class="d-flex">
|
||||
<avatar
|
||||
@@ -45,16 +38,14 @@
|
||||
:override-top-padding="'14px'"
|
||||
@click.native="showMemberModal(msg.uuid)"
|
||||
/>
|
||||
<div class="card">
|
||||
<chat-card
|
||||
:msg="msg"
|
||||
:group-id="groupId"
|
||||
@message-liked="messageLiked"
|
||||
@message-removed="messageRemoved"
|
||||
@show-member-modal="showMemberModal"
|
||||
@chat-card-mounted="itemWasMounted"
|
||||
/>
|
||||
</div>
|
||||
<message-card
|
||||
:msg="msg"
|
||||
:group-id="groupId"
|
||||
:user-sent-message="user._id === msg.uuid"
|
||||
@message-liked="messageLiked"
|
||||
@message-removed="messageRemoved"
|
||||
@message-card-mounted="itemWasMounted"
|
||||
/>
|
||||
<avatar
|
||||
v-if="user._id === msg.uuid"
|
||||
:class="{ invisible: avatarUnavailable(msg) }"
|
||||
@@ -137,11 +128,27 @@
|
||||
margin-bottom: .5em;
|
||||
padding: 0rem;
|
||||
width: 90%;
|
||||
|
||||
&.system-message {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.message-scroll .d-flex {
|
||||
min-width: 1px;
|
||||
}
|
||||
|
||||
.message-row {
|
||||
margin-left: 12px;
|
||||
margin-right: 0;
|
||||
margin-bottom: 1.2rem;
|
||||
|
||||
&:not(.margin-right) {
|
||||
.d-flex {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
@@ -152,13 +159,13 @@ import findIndex from 'lodash/findIndex';
|
||||
import { userStateMixin } from '../../mixins/userState';
|
||||
|
||||
import Avatar from '../avatar';
|
||||
import copyAsTodoModal from './copyAsTodoModal';
|
||||
import chatCard from './chatCard';
|
||||
import MessageCard from '@/components/messages/messageCard.vue';
|
||||
|
||||
// TODO merge chatMessages.vue (party message list) with messageList.vue (private message list)
|
||||
|
||||
export default {
|
||||
components: {
|
||||
copyAsTodoModal,
|
||||
chatCard,
|
||||
MessageCard,
|
||||
Avatar,
|
||||
},
|
||||
mixins: [userStateMixin],
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
<template>
|
||||
<b-modal
|
||||
id="copyAsTodo"
|
||||
:title="$t('copyMessageAsToDo')"
|
||||
:hide-footer="true"
|
||||
size="md"
|
||||
>
|
||||
<div class="form-group">
|
||||
<input
|
||||
v-model="task.text"
|
||||
class="form-control"
|
||||
type="text"
|
||||
>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<textarea
|
||||
v-model="task.notes"
|
||||
class="form-control"
|
||||
rows="5"
|
||||
focus-element="true"
|
||||
></textarea>
|
||||
</div>
|
||||
<hr>
|
||||
<task
|
||||
v-if="task._id"
|
||||
:is-user="isUser"
|
||||
:task="task"
|
||||
/>
|
||||
<div class="modal-footer">
|
||||
<button
|
||||
class="btn btn-secondary"
|
||||
@click="close()"
|
||||
>
|
||||
{{ $t('close') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
@click="saveTodo()"
|
||||
>
|
||||
{{ $t('submit') }}
|
||||
</button>
|
||||
</div>
|
||||
</b-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import taskDefaults from '@/../../common/script/libs/taskDefaults';
|
||||
import { mapActions } from '@/libs/store';
|
||||
import markdownDirective from '@/directives/markdown';
|
||||
import notificationsMixin from '@/mixins/notifications';
|
||||
import Task from '@/components/tasks/task';
|
||||
|
||||
const baseUrl = 'https://habitica.com';
|
||||
|
||||
export default {
|
||||
directives: {
|
||||
markdown: markdownDirective,
|
||||
},
|
||||
components: {
|
||||
Task,
|
||||
},
|
||||
mixins: [notificationsMixin],
|
||||
props: ['copyingMessage', 'groupType', 'groupName', 'groupId'],
|
||||
data () {
|
||||
return {
|
||||
isUser: true,
|
||||
task: {},
|
||||
};
|
||||
},
|
||||
mounted () {
|
||||
this.$root.$on('habitica::copy-as-todo', message => {
|
||||
const notes = `${message.user || 'system message'}${message.user ? ' wrote' : ''} in [${this.groupName}](${this.groupPath()})`;
|
||||
const newTask = {
|
||||
text: message.text,
|
||||
type: 'todo',
|
||||
notes,
|
||||
};
|
||||
this.task = taskDefaults(newTask, this.$store.state.user.data);
|
||||
this.$root.$emit('bv::show::modal', 'copyAsTodo');
|
||||
});
|
||||
},
|
||||
beforeDestroy () {
|
||||
this.$root.$off('habitica::copy-as-todo');
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
createTask: 'tasks:create',
|
||||
}),
|
||||
groupPath () {
|
||||
if (this.groupType === 'party') {
|
||||
return `${baseUrl}/party`;
|
||||
}
|
||||
return `${baseUrl}/groups/guild/${this.groupId}`;
|
||||
},
|
||||
close () {
|
||||
this.$root.$emit('bv::hide::modal', 'copyAsTodo');
|
||||
},
|
||||
saveTodo () {
|
||||
this.createTask(this.task);
|
||||
this.text(this.$t('messageAddedAsToDo'));
|
||||
this.$root.$emit('bv::hide::modal', 'copyAsTodo');
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -22,13 +22,13 @@
|
||||
:placeholder="placeholder"
|
||||
:class="{'user-entry': newMessage}"
|
||||
:maxlength="MAX_MESSAGE_LENGTH"
|
||||
@keydown="updateCarretPosition"
|
||||
@keydown="autoCompleteMixinUpdateCarretPosition"
|
||||
@keyup.ctrl.enter="sendMessageShortcut()"
|
||||
@keydown.tab="handleTab($event)"
|
||||
@keydown.up="selectPreviousAutocomplete($event)"
|
||||
@keydown.down="selectNextAutocomplete($event)"
|
||||
@keypress.enter="selectAutocomplete($event)"
|
||||
@keydown.esc="handleEscape($event)"
|
||||
@keydown.tab="autoCompleteMixinHandleTab($event)"
|
||||
@keydown.up="autoCompleteMixinSelectPreviousAutocomplete($event)"
|
||||
@keydown.down="autoCompleteMixinSelectNextAutocomplete($event)"
|
||||
@keypress.enter="autoCompleteMixinSelectAutocomplete($event)"
|
||||
@keydown.esc="autoCompleteMixinHandleEscape($event)"
|
||||
@paste="disableMessageSendShortcut()"
|
||||
></textarea>
|
||||
<span>{{ currentLength }} / {{ MAX_MESSAGE_LENGTH }}</span>
|
||||
@@ -36,8 +36,8 @@
|
||||
ref="autocomplete"
|
||||
:text="newMessage"
|
||||
:textbox="textbox"
|
||||
:coords="coords"
|
||||
:caret-position="caretPosition"
|
||||
:coords="mixinData.autoComplete.coords"
|
||||
:caret-position="mixinData.autoComplete.caretPosition"
|
||||
:chat="group.chat"
|
||||
@select="selectedAutocomplete"
|
||||
/>
|
||||
@@ -74,7 +74,7 @@
|
||||
<slot name="additionRow"></slot>
|
||||
<div class="row">
|
||||
<div class="hr col-12"></div>
|
||||
<chat-message
|
||||
<chat-messages
|
||||
:chat.sync="group.chat"
|
||||
:group-type="group.type"
|
||||
:group-id="group._id"
|
||||
@@ -86,16 +86,15 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import debounce from 'lodash/debounce';
|
||||
|
||||
import { MAX_MESSAGE_LENGTH } from '@/../../common/script/constants';
|
||||
import externalLinks from '../../mixins/externalLinks';
|
||||
|
||||
import autocomplete from '../chat/autoComplete';
|
||||
import communityGuidelines from './communityGuidelines';
|
||||
import chatMessage from '../chat/chatMessages';
|
||||
import chatMessages from '../chat/chatMessages';
|
||||
import { mapState } from '@/libs/store';
|
||||
import markdownDirective from '@/directives/markdown';
|
||||
import { autoCompleteHelperMixin } from '@/mixins/autoCompleteHelper';
|
||||
|
||||
export default {
|
||||
directives: {
|
||||
@@ -104,23 +103,18 @@ export default {
|
||||
components: {
|
||||
autocomplete,
|
||||
communityGuidelines,
|
||||
chatMessage,
|
||||
chatMessages,
|
||||
},
|
||||
mixins: [externalLinks],
|
||||
mixins: [externalLinks, autoCompleteHelperMixin],
|
||||
props: ['label', 'group', 'placeholder'],
|
||||
data () {
|
||||
return {
|
||||
newMessage: '',
|
||||
sending: false,
|
||||
caretPosition: 0,
|
||||
chat: {
|
||||
submitDisable: false,
|
||||
submitTimeout: null,
|
||||
},
|
||||
coords: {
|
||||
TOP: 0,
|
||||
LEFT: 0,
|
||||
},
|
||||
textbox: null,
|
||||
MAX_MESSAGE_LENGTH: MAX_MESSAGE_LENGTH.toString(),
|
||||
};
|
||||
@@ -142,35 +136,6 @@ export default {
|
||||
this.handleExternalLinks();
|
||||
},
|
||||
methods: {
|
||||
// https://medium.com/@_jh3y/how-to-where-s-the-caret-getting-the-xy-position-of-the-caret-a24ba372990a
|
||||
getCoord (e, text) {
|
||||
this.caretPosition = text.selectionEnd;
|
||||
const div = document.createElement('div');
|
||||
const span = document.createElement('span');
|
||||
const copyStyle = getComputedStyle(text);
|
||||
|
||||
[].forEach.call(copyStyle, prop => {
|
||||
div.style[prop] = copyStyle[prop];
|
||||
});
|
||||
|
||||
div.style.position = 'absolute';
|
||||
document.body.appendChild(div);
|
||||
div.textContent = text.value.substr(0, this.caretPosition);
|
||||
span.textContent = text.value.substr(this.caretPosition) || '.';
|
||||
div.appendChild(span);
|
||||
this.coords = {
|
||||
TOP: span.offsetTop,
|
||||
LEFT: span.offsetLeft,
|
||||
};
|
||||
document.body.removeChild(div);
|
||||
},
|
||||
updateCarretPosition: debounce(function updateCarretPosition (eventUpdate) {
|
||||
this._updateCarretPosition(eventUpdate);
|
||||
}, 250),
|
||||
_updateCarretPosition (eventUpdate) {
|
||||
const text = eventUpdate.target;
|
||||
this.getCoord(eventUpdate, text);
|
||||
},
|
||||
async sendMessageShortcut () {
|
||||
// If the user recently pasted in the text field, don't submit
|
||||
if (!this.chat.submitDisable) {
|
||||
@@ -221,50 +186,6 @@ export default {
|
||||
}, 500);
|
||||
},
|
||||
|
||||
handleTab (e) {
|
||||
if (this.$refs.autocomplete.searchActive) {
|
||||
e.preventDefault();
|
||||
if (e.shiftKey) {
|
||||
this.$refs.autocomplete.selectPrevious();
|
||||
} else {
|
||||
this.$refs.autocomplete.selectNext();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
handleEscape (e) {
|
||||
if (this.$refs.autocomplete.searchActive) {
|
||||
e.preventDefault();
|
||||
this.$refs.autocomplete.cancel();
|
||||
}
|
||||
},
|
||||
|
||||
selectNextAutocomplete (e) {
|
||||
if (this.$refs.autocomplete.searchActive) {
|
||||
e.preventDefault();
|
||||
this.$refs.autocomplete.selectNext();
|
||||
}
|
||||
},
|
||||
|
||||
selectPreviousAutocomplete (e) {
|
||||
if (this.$refs.autocomplete.searchActive) {
|
||||
e.preventDefault();
|
||||
this.$refs.autocomplete.selectPrevious();
|
||||
}
|
||||
},
|
||||
|
||||
selectAutocomplete (e) {
|
||||
if (this.$refs.autocomplete.searchActive) {
|
||||
if (this.$refs.autocomplete.selected !== null) {
|
||||
e.preventDefault();
|
||||
this.$refs.autocomplete.makeSelection();
|
||||
} else {
|
||||
// no autocomplete selected, newline instead
|
||||
this.$refs.autocomplete.cancel();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
selectedAutocomplete (newText, newCaret) {
|
||||
this.newMessage = newText;
|
||||
// Wait for v-modal to update
|
||||
@@ -273,7 +194,6 @@ export default {
|
||||
this.textbox.focus();
|
||||
});
|
||||
},
|
||||
|
||||
fetchRecentMessages () {
|
||||
this.$emit('fetchRecentMessages');
|
||||
},
|
||||
@@ -284,10 +204,7 @@ export default {
|
||||
beforeRouteUpdate (to, from, next) {
|
||||
// Reset chat
|
||||
this.newMessage = '';
|
||||
this.coords = {
|
||||
TOP: 0,
|
||||
LEFT: 0,
|
||||
};
|
||||
this.autoCompleteMixinResetCoordsPosition();
|
||||
|
||||
next();
|
||||
},
|
||||
|
||||
@@ -334,11 +334,6 @@
|
||||
href="https://docs.google.com/forms/d/e/1FAIpQLScPhrwq_7P1C6PTrI3lbvTsvqGyTNnGzp1ugi1Ml0PFee_p5g/viewform?usp=sf_link"
|
||||
target="_blank"
|
||||
>{{ $t('requestFeature') }}</a>
|
||||
<a
|
||||
class="topbar-dropdown-item dropdown-item"
|
||||
href="https://habitica.fandom.com/wiki/Habitica_Wiki"
|
||||
target="_blank"
|
||||
>{{ $t('wiki') }}</a>
|
||||
</div>
|
||||
</li>
|
||||
</b-navbar-nav>
|
||||
|
||||
@@ -41,7 +41,8 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
action () {
|
||||
if (!this.notification || !this.notification.data) {
|
||||
if (!this.notification || !this.notification.data
|
||||
|| this.notification.data.destination === this.$route.path) {
|
||||
return;
|
||||
}
|
||||
if (this.notification.data.destination.indexOf('backgrounds') !== -1) {
|
||||
|
||||
@@ -106,7 +106,7 @@
|
||||
</div>
|
||||
<div slot="drawer-header">
|
||||
<div class="drawer-tab-container">
|
||||
<div class="clearfix">
|
||||
<div class="clearfix mb-2">
|
||||
<toggle-switch
|
||||
class="float-right align-with-tab"
|
||||
:label="$t(costumeMode ? 'useCostume' : 'autoEquipBattleGear')"
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
:name="member.profile.name"
|
||||
:backer="member.backer"
|
||||
:contributor="member.contributor"
|
||||
:smaller-style="true"
|
||||
/>
|
||||
<inline-class-badge
|
||||
v-if="member.stats"
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
<template>
|
||||
<div
|
||||
class="d-inline-flex like-button"
|
||||
@click="like()"
|
||||
>
|
||||
<div
|
||||
v-b-tooltip="{title: likeTooltip(likeCount)}"
|
||||
class="d-flex"
|
||||
>
|
||||
<div
|
||||
v-if="likeCount > 0"
|
||||
class="action d-flex align-items-center mr-0"
|
||||
:class="{isLiked: true, currentUserLiked: likedByCurrentUser}"
|
||||
>
|
||||
<div
|
||||
class="svg-icon mr-1"
|
||||
:title="$t('liked')"
|
||||
v-html="icons.liked"
|
||||
></div>
|
||||
+{{ likeCount }}
|
||||
</div>
|
||||
<div
|
||||
v-if="likeCount === 0"
|
||||
class="action d-flex align-items-center mr-1"
|
||||
>
|
||||
<div
|
||||
class="svg-icon"
|
||||
:title="$t('like')"
|
||||
v-html="icons.like"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
<span v-if="likeCount === 0">{{ $t('like') }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~@/assets/scss/colors.scss';
|
||||
@import '~@/assets/scss/tiers.scss';
|
||||
|
||||
.action {
|
||||
display: inline-block;
|
||||
margin-right: 1em;
|
||||
|
||||
.svg-icon {
|
||||
color: $gray-100;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
&.isLiked {
|
||||
color: $purple-200;
|
||||
font-weight: bold;
|
||||
|
||||
.svg-icon {
|
||||
color: $purple-300;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.like-button {
|
||||
color: $gray-100;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
color: $purple-200;
|
||||
|
||||
.svg-icon {
|
||||
color: $purple-300;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import likeIcon from '@/assets/svg/like.svg';
|
||||
import likedIcon from '@/assets/svg/liked.svg';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
likeCount: {
|
||||
type: Number,
|
||||
},
|
||||
likedByCurrentUser: {
|
||||
type: Boolean,
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
like: likeIcon,
|
||||
liked: likedIcon,
|
||||
}),
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
async like () {
|
||||
this.$emit('toggle-like');
|
||||
},
|
||||
likeTooltip (likedStatus) {
|
||||
if (!likedStatus) return this.$t('like');
|
||||
return null;
|
||||
},
|
||||
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -1,73 +1,157 @@
|
||||
<template>
|
||||
<div class="card-body">
|
||||
<user-link
|
||||
:user-id="msg.uuid"
|
||||
:name="msg.user"
|
||||
:backer="msg.backer"
|
||||
:contributor="msg.contributor"
|
||||
/>
|
||||
<p class="time">
|
||||
<span
|
||||
v-if="msg.username"
|
||||
class="mr-1"
|
||||
>@{{ msg.username }}</span><span
|
||||
v-if="msg.username"
|
||||
class="mr-1"
|
||||
>•</span>
|
||||
<span
|
||||
v-b-tooltip.hover="messageDate"
|
||||
>{{ msg.timestamp | timeAgo }} </span>
|
||||
<span v-if="msg.client && user.contributor.level >= 4"> ({{ msg.client }})</span>
|
||||
</p>
|
||||
<div
|
||||
class="card"
|
||||
:class="{
|
||||
'system-message': isSystemMessage
|
||||
}"
|
||||
>
|
||||
<div
|
||||
class="text markdown"
|
||||
dir="auto"
|
||||
v-html="parseMarkdown(msg.text)"
|
||||
></div>
|
||||
<div
|
||||
v-if="isMessageReported"
|
||||
class="reported"
|
||||
>
|
||||
<span v-once>{{ $t('reportedMessage') }}</span><br>
|
||||
<span v-once>{{ $t('canDeleteNow') }}</span>
|
||||
</div>
|
||||
<hr>
|
||||
<div
|
||||
v-if="msg.id"
|
||||
class="d-flex"
|
||||
v-b-tooltip.hover="messageDateForSystemMessage"
|
||||
class="message-card"
|
||||
|
||||
:class="{
|
||||
'user-sent-message': userSentMessage,
|
||||
'user-received-message': !userSentMessage && !isSystemMessage,
|
||||
'system-message': isSystemMessage
|
||||
}"
|
||||
>
|
||||
<div
|
||||
v-if="!isMessageReported"
|
||||
class="action d-flex align-items-center"
|
||||
@click="report(msg)"
|
||||
v-if="isUserMentioned"
|
||||
class="mentioned-icon"
|
||||
></div>
|
||||
<div
|
||||
v-if="userIsModerator && msg.flagCount"
|
||||
class="message-hidden"
|
||||
>
|
||||
<div
|
||||
v-once
|
||||
class="svg-icon"
|
||||
v-html="icons.report"
|
||||
></div>
|
||||
<div v-once>
|
||||
{{ $t('report') }}
|
||||
</div>
|
||||
{{ flagCountDescription }}
|
||||
</div>
|
||||
<div
|
||||
class="action d-flex align-items-center"
|
||||
@click="remove()"
|
||||
class="card-body"
|
||||
>
|
||||
<user-link
|
||||
v-if="!isSystemMessage"
|
||||
:user-id="msg.uuid"
|
||||
:name="msg.user"
|
||||
:backer="msg.backer"
|
||||
:contributor="msg.contributor"
|
||||
/>
|
||||
<p
|
||||
v-if="!isSystemMessage"
|
||||
class="time"
|
||||
>
|
||||
<span
|
||||
v-if="msg.username"
|
||||
class="mr-1"
|
||||
>@{{ msg.username }}</span><span
|
||||
v-if="msg.username"
|
||||
class="mr-1"
|
||||
>•</span>
|
||||
<span v-b-tooltip.hover="messageDate">{{ msg.timestamp | timeAgo }} </span>
|
||||
<span v-if="msg.client && user.contributor.level >= 4">
|
||||
({{ msg.client }})
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<b-dropdown
|
||||
v-if="!isSystemMessage"
|
||||
right="right"
|
||||
variant="flat"
|
||||
toggle-class="with-icon"
|
||||
class="card-menu no-min-width"
|
||||
:no-caret="true"
|
||||
>
|
||||
<template #button-content>
|
||||
<span
|
||||
v-once
|
||||
class="svg-icon inline menuIcon color"
|
||||
v-html="icons.menuIcon"
|
||||
>
|
||||
</span>
|
||||
</template>
|
||||
<b-dropdown-item
|
||||
class="selectListItem"
|
||||
@click="copy(msg)"
|
||||
>
|
||||
<span class="with-icon">
|
||||
<span
|
||||
v-once
|
||||
class="svg-icon icon-16 color"
|
||||
v-html="icons.copy"
|
||||
></span>
|
||||
<span v-once>
|
||||
{{ $t('copy') }}
|
||||
</span>
|
||||
</span>
|
||||
</b-dropdown-item>
|
||||
<b-dropdown-item
|
||||
v-if="canReportMessage"
|
||||
class="selectListItem custom-hover--red"
|
||||
@click="report(msg)"
|
||||
>
|
||||
<span class="with-icon">
|
||||
<span
|
||||
v-once
|
||||
class="svg-icon icon-16 color"
|
||||
v-html="icons.report"
|
||||
></span>
|
||||
<span v-once>
|
||||
{{ $t('report') }}
|
||||
</span>
|
||||
</span>
|
||||
</b-dropdown-item>
|
||||
<b-dropdown-item
|
||||
v-if="canDeleteMessage"
|
||||
class="selectListItem custom-hover--red"
|
||||
@click="remove()"
|
||||
>
|
||||
<span class="with-icon">
|
||||
<span
|
||||
v-once
|
||||
class="svg-icon icon-16 color"
|
||||
v-html="icons.delete"
|
||||
></span>
|
||||
<span v-once>
|
||||
{{ $t('delete') }}
|
||||
</span>
|
||||
</span>
|
||||
</b-dropdown-item>
|
||||
</b-dropdown>
|
||||
|
||||
<div
|
||||
v-once
|
||||
class="svg-icon"
|
||||
v-html="icons.delete"
|
||||
></div>
|
||||
<div v-once>
|
||||
{{ $t('delete') }}
|
||||
v-if="isSystemMessage"
|
||||
class="system-message-body"
|
||||
>
|
||||
{{ msg.unformattedText }}
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
ref="markdownContainer"
|
||||
class="text markdown"
|
||||
dir="auto"
|
||||
v-html="parseMarkdown(msg.text)"
|
||||
></div>
|
||||
<div
|
||||
v-if="isMessageReported"
|
||||
class="reported"
|
||||
>
|
||||
<span v-once>{{ $t('reportedMessage') }}</span><br>
|
||||
<span v-once>{{ $t('canDeleteNow') }}</span>
|
||||
</div>
|
||||
|
||||
<like-button
|
||||
v-if="canLikeMessage"
|
||||
class="mt-75"
|
||||
:liked-by-current-user="msg.likes[user._id]"
|
||||
:like-count="likeCount"
|
||||
@toggle-like="like()"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.message-card {
|
||||
.at-highlight {
|
||||
background-color: rgba(213, 200, 255, 0.32);
|
||||
padding: 0.1rem;
|
||||
@@ -76,43 +160,76 @@
|
||||
.at-text {
|
||||
color: #6133b4;
|
||||
}
|
||||
|
||||
.card-menu button {
|
||||
justify-content: center;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 1rem;
|
||||
width: 1rem;
|
||||
}
|
||||
|
||||
.markdown p:last-of-type {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~@/assets/scss/colors.scss';
|
||||
@import '~@/assets/scss/tiers.scss';
|
||||
@import '~@/assets/scss/colors.scss';
|
||||
@import '~@/assets/scss/tiers.scss';
|
||||
|
||||
.action {
|
||||
display: inline-block;
|
||||
color: $gray-200;
|
||||
margin-right: 1em;
|
||||
font-size: 12px;
|
||||
.card {
|
||||
background: transparent !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
.message-card:not(.system-message) {
|
||||
background: white;
|
||||
}
|
||||
|
||||
.svg-icon {
|
||||
color: $gray-300;
|
||||
margin-right: .2em;
|
||||
width: 16px;
|
||||
}
|
||||
.mentioned-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 50%;
|
||||
background-color: $purple-500;
|
||||
box-shadow: 0 1px 1px 0 rgba(26, 24, 29, 0.12);
|
||||
position: absolute;
|
||||
right: -.5em;
|
||||
top: -.5em;
|
||||
}
|
||||
|
||||
.message-hidden {
|
||||
margin-left: 1.5em;
|
||||
margin-top: 1em;
|
||||
color: red;
|
||||
}
|
||||
|
||||
.active {
|
||||
color: $purple-300;
|
||||
|
||||
.svg-icon {
|
||||
color: $purple-400;
|
||||
}
|
||||
}
|
||||
|
||||
.active {
|
||||
color: $purple-300;
|
||||
.message-card {
|
||||
border-radius: 7px;
|
||||
margin: 0;
|
||||
padding: 1rem 0.75rem 0.5rem 1rem;
|
||||
|
||||
.svg-icon {
|
||||
color: $purple-400;
|
||||
}
|
||||
&.system-message {
|
||||
padding-top: 0.5rem;
|
||||
}
|
||||
|
||||
.card-body {
|
||||
padding: 0.75rem 1.25rem 0.75rem 1.25rem;
|
||||
position: relative;
|
||||
padding: 0;
|
||||
|
||||
.time {
|
||||
font-size: 12px;
|
||||
color: $gray-200;
|
||||
color: $gray-100;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
@@ -123,49 +240,173 @@
|
||||
min-height: 0rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hr {
|
||||
margin-bottom: 0.5rem;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
.card-menu {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
|
||||
.reported {
|
||||
margin-top: 18px;
|
||||
color: $red-50;
|
||||
&:not(.show) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.card-body:hover {
|
||||
.card-menu {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
hr {
|
||||
margin-bottom: 0.5rem;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.reported {
|
||||
margin-top: 18px;
|
||||
color: $red-50;
|
||||
}
|
||||
|
||||
.selectListItem:not(:hover) .svg-icon.icon-16.color {
|
||||
color: #{$gray-100}
|
||||
}
|
||||
|
||||
.custom-hover--red {
|
||||
--hover-color: #{$maroon-50};
|
||||
--hover-background: #{rgba($red-500, 0.25)};
|
||||
}
|
||||
|
||||
.user-sent-message {
|
||||
border: 1px solid $purple-400;
|
||||
}
|
||||
|
||||
.system-message {
|
||||
border: 1px solid $purple-400;
|
||||
}
|
||||
|
||||
.user-received-message {
|
||||
border: 1px solid $gray-500;
|
||||
}
|
||||
|
||||
.card-menu {
|
||||
// icon-color is the menu icon itself
|
||||
--icon-color: #{$gray-100};
|
||||
|
||||
--dropdown-item-hover-icon-color: #{$gray-100};
|
||||
|
||||
&:hover {
|
||||
--icon-color: #{$purple-300};
|
||||
}
|
||||
}
|
||||
|
||||
.menuIcon {
|
||||
width: 4px;
|
||||
height: 1rem;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.system-message-body {
|
||||
line-height: 1.71;
|
||||
text-align: center;
|
||||
color: $purple-300;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import axios from 'axios';
|
||||
import moment from 'moment';
|
||||
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
import escapeRegExp from 'lodash/escapeRegExp';
|
||||
import { CHAT_FLAG_FROM_SHADOW_MUTE, CHAT_FLAG_LIMIT_FOR_HIDING } from '@/../../common/script/constants';
|
||||
import externalLinks from '../../mixins/externalLinks';
|
||||
|
||||
import { CopyToClipboardMixin } from '@/mixins/copyToClipboard';
|
||||
|
||||
import renderWithMentions from '@/libs/renderWithMentions';
|
||||
import { mapState } from '@/libs/store';
|
||||
import userLink from '../userLink';
|
||||
|
||||
import deleteIcon from '@/assets/svg/delete.svg';
|
||||
import reportIcon from '@/assets/svg/report.svg';
|
||||
import menuIcon from '@/assets/svg/menu.svg';
|
||||
import { userStateMixin } from '@/mixins/userState';
|
||||
import copyIcon from '@/assets/svg/copy.svg';
|
||||
import LikeButton from '@/components/messages/likeButton.vue';
|
||||
|
||||
const LikeLogicMixin = {
|
||||
computed: {
|
||||
likeCount () {
|
||||
const message = this.msg;
|
||||
if (!message.likes) return 0;
|
||||
|
||||
let likeCount = 0;
|
||||
for (const key of Object.keys(message.likes)) {
|
||||
const like = message.likes[key];
|
||||
if (like) likeCount += 1;
|
||||
}
|
||||
return likeCount;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
|
||||
async like () {
|
||||
const message = cloneDeep(this.msg);
|
||||
|
||||
await this.$store.dispatch('chat:like', {
|
||||
groupId: this.groupId,
|
||||
chatMessageId: this.privateMessageMode ? message.uniqueMessageId : message.id,
|
||||
});
|
||||
|
||||
message.likes[this.user._id] = !message.likes[this.user._id];
|
||||
|
||||
this.$emit('message-liked', message);
|
||||
this.$root.$emit('bv::hide::tooltip');
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default {
|
||||
components: {
|
||||
LikeButton,
|
||||
userLink,
|
||||
},
|
||||
filters: {
|
||||
timeAgo (value) {
|
||||
return moment(value).fromNow();
|
||||
},
|
||||
date (value) {
|
||||
// @TODO: Vue doesn't support this so we cant user preference
|
||||
return moment(value).toDate().toString();
|
||||
},
|
||||
},
|
||||
mixins: [externalLinks],
|
||||
mixins: [
|
||||
externalLinks, userStateMixin, LikeLogicMixin,
|
||||
CopyToClipboardMixin,
|
||||
],
|
||||
props: {
|
||||
msg: {},
|
||||
msg: {
|
||||
type: Object,
|
||||
},
|
||||
groupId: {
|
||||
type: String,
|
||||
},
|
||||
privateMessageMode: {
|
||||
type: Boolean,
|
||||
},
|
||||
userSentMessage: {
|
||||
type: Boolean,
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
delete: deleteIcon,
|
||||
report: reportIcon,
|
||||
copy: copyIcon,
|
||||
menuIcon,
|
||||
}),
|
||||
reported: false,
|
||||
};
|
||||
@@ -175,19 +416,100 @@ export default {
|
||||
isMessageReported () {
|
||||
return (this.msg.flags && this.msg.flags[this.user.id]) || this.reported;
|
||||
},
|
||||
messageDateForSystemMessage () {
|
||||
return this.isSystemMessage ? this.messageDate : '';
|
||||
},
|
||||
messageDate () {
|
||||
const date = moment(this.msg.timestamp).toDate();
|
||||
return date.toString();
|
||||
},
|
||||
userIsModerator () {
|
||||
return this.hasPermission(this.user, 'moderator');
|
||||
},
|
||||
isSystemMessage () {
|
||||
return this.msg.uuid === 'system';
|
||||
},
|
||||
canLikeMessage () {
|
||||
if (this.isSystemMessage) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.privateMessageMode) {
|
||||
return Boolean(this.msg.uniqueMessageId);
|
||||
}
|
||||
|
||||
return this.msg.id;
|
||||
},
|
||||
canDeleteMessage () {
|
||||
return this.privateMessageMode
|
||||
|| this.msg.uuid === this.user._id
|
||||
|| this.userIsModerator;
|
||||
},
|
||||
canReportMessage () {
|
||||
if (this.privateMessageMode) {
|
||||
return !this.isMessageReported;
|
||||
}
|
||||
return (this.user.flags.communityGuidelinesAccepted && this.msg.uuid !== 'system')
|
||||
&& (!this.isMessageReported || this.userIsModerator);
|
||||
},
|
||||
isUserMentioned () {
|
||||
const message = this.msg;
|
||||
|
||||
if (message.highlight) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const { user } = this;
|
||||
const displayName = user.profile.name;
|
||||
const { username } = user.auth.local;
|
||||
const pattern = `@(${escapeRegExp(displayName)}|${escapeRegExp(username)})(\\b)`;
|
||||
message.highlight = new RegExp(pattern, 'i').test(message.text);
|
||||
|
||||
return message.highlight;
|
||||
},
|
||||
flagCountDescription () {
|
||||
if (!this.msg.flagCount) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (this.msg.flagCount < CHAT_FLAG_LIMIT_FOR_HIDING) {
|
||||
return 'Message flagged once, not hidden';
|
||||
}
|
||||
|
||||
if (this.msg.flagCount < CHAT_FLAG_FROM_SHADOW_MUTE) {
|
||||
return 'Message hidden';
|
||||
}
|
||||
|
||||
return 'Message hidden (shadow-muted)';
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
this.$emit('message-card-mounted');
|
||||
this.handleExternalLinks();
|
||||
this.mapProfileLinksToModal();
|
||||
},
|
||||
updated () {
|
||||
this.handleExternalLinks();
|
||||
this.mapProfileLinksToModal();
|
||||
},
|
||||
methods: {
|
||||
mapProfileLinksToModal () {
|
||||
const links = this.$refs.markdownContainer.getElementsByTagName('a');
|
||||
for (let i = 0; i < links.length; i += 1) {
|
||||
let link = links[i].pathname;
|
||||
|
||||
// Internet Explorer does not provide the leading slash character in the pathname
|
||||
link = link.charAt(0) === '/' ? link : `/${link}`;
|
||||
|
||||
if (link.startsWith('/profile/')) {
|
||||
links[i].onclick = ev => {
|
||||
ev.preventDefault();
|
||||
this.$router.push({ path: link });
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
report () {
|
||||
this.$root.$on('habitica:report-result', data => {
|
||||
if (data.ok) {
|
||||
@@ -199,16 +521,29 @@ export default {
|
||||
|
||||
this.$root.$emit('habitica::report-chat', {
|
||||
message: this.msg,
|
||||
groupId: 'privateMessage',
|
||||
groupId: this.groupId,
|
||||
});
|
||||
},
|
||||
async remove () {
|
||||
if (!window.confirm(this.$t('areYouSureDeleteMessage'))) return; // eslint-disable-line no-alert
|
||||
// eslint-disable-next-line no-alert
|
||||
if (!window.confirm(this.$t('areYouSureDeleteMessage'))) {
|
||||
return;
|
||||
}
|
||||
|
||||
const message = this.msg;
|
||||
this.$emit('message-removed', message);
|
||||
|
||||
await axios.delete(`/api/v4/inbox/messages/${message.id}`);
|
||||
if (this.privateMessageMode) {
|
||||
await axios.delete(`/api/v4/inbox/messages/${message.id}`);
|
||||
} else {
|
||||
await this.$store.dispatch('chat:deleteChat', {
|
||||
groupId: this.groupId,
|
||||
chatId: message.id,
|
||||
});
|
||||
}
|
||||
},
|
||||
copy (message) {
|
||||
this.mixinCopyToClipboard(message.text, this.$t('messageCopiedToClipboard'));
|
||||
},
|
||||
parseMarkdown (text) {
|
||||
return renderWithMentions(text, this.user);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<div
|
||||
ref="container"
|
||||
class="container-fluid"
|
||||
class="message-list"
|
||||
>
|
||||
<div class="row loadmore">
|
||||
<div class="loadmore">
|
||||
<div v-if="canLoadMore && !isLoading">
|
||||
<div class="loadmore-divider-holder">
|
||||
<div class="loadmore-divider"></div>
|
||||
@@ -28,7 +28,7 @@
|
||||
<div
|
||||
v-for="(msg) in messages"
|
||||
:key="msg.id"
|
||||
class="row message-row"
|
||||
class="message-row"
|
||||
:class="{ 'margin-right': user._id !== msg.uuid}"
|
||||
>
|
||||
<div
|
||||
@@ -39,28 +39,31 @@
|
||||
class="avatar-left"
|
||||
:member="conversationOpponentUser"
|
||||
:avatar-only="true"
|
||||
:override-top-padding="'14px'"
|
||||
:show-weapon="false"
|
||||
:debug-mode="false"
|
||||
:override-top-padding="'0'"
|
||||
:hide-class-badge="true"
|
||||
@click.native="showMemberModal(msg.uuid)"
|
||||
/>
|
||||
<div
|
||||
class="card"
|
||||
:class="{'card-right': user._id !== msg.uuid, 'card-left': user._id === msg.uuid}"
|
||||
>
|
||||
<message-card
|
||||
:msg="msg"
|
||||
@message-removed="messageRemoved"
|
||||
@show-member-modal="showMemberModal"
|
||||
@message-card-mounted="itemWasMounted"
|
||||
/>
|
||||
</div>
|
||||
<message-card
|
||||
:msg="msg"
|
||||
:user-sent-message="user._id === msg.uuid"
|
||||
:group-id="'privateMessage'"
|
||||
:private-message-mode="true"
|
||||
@message-liked="messageLiked"
|
||||
@message-removed="messageRemoved"
|
||||
@show-member-modal="showMemberModal"
|
||||
@message-card-mounted="itemWasMounted"
|
||||
/>
|
||||
<avatar
|
||||
v-if="user && user._id === msg.uuid"
|
||||
class="avatar-right"
|
||||
:member="user"
|
||||
:avatar-only="true"
|
||||
:show-weapon="false"
|
||||
:debug-mode="false"
|
||||
:hide-class-badge="true"
|
||||
:override-top-padding="'14px'"
|
||||
:override-top-padding="'0'"
|
||||
@click.native="showMemberModal(msg.uuid)"
|
||||
/>
|
||||
</div>
|
||||
@@ -69,121 +72,123 @@
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~@/assets/scss/colors.scss';
|
||||
@import '~@/assets/scss/colors.scss';
|
||||
|
||||
.avatar {
|
||||
width: 170px;
|
||||
min-width: 8rem;
|
||||
height: 120px;
|
||||
padding-top: 0 !important;
|
||||
.avatar-left, .avatar-right {
|
||||
align-self: center;
|
||||
|
||||
::v-deep .character-sprites {
|
||||
margin-bottom: -5px !important;
|
||||
padding-bottom: 0 !important;
|
||||
margin-top: -1px !important;
|
||||
}
|
||||
|
||||
.avatar-right {
|
||||
margin-left: -1rem;
|
||||
::v-deep .avatar {
|
||||
margin-left: -1.75rem;
|
||||
margin-right: -0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .character-sprites {
|
||||
margin-right: 1rem !important;
|
||||
.avatar-left {
|
||||
margin-right: 1.5rem;
|
||||
}
|
||||
|
||||
.avatar-right {
|
||||
overflow: clip;
|
||||
margin-left: 1.5rem;
|
||||
|
||||
::v-deep .character-sprites {
|
||||
margin-right: 1rem !important;
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
border: 0px;
|
||||
margin-bottom: 1rem;
|
||||
padding: 0rem;
|
||||
width: 684px;
|
||||
|
||||
}
|
||||
|
||||
.message-list {
|
||||
width: 100%;
|
||||
padding-right: 10px;
|
||||
margin-right: 0 !important;
|
||||
}
|
||||
|
||||
.message-row {
|
||||
margin-left: 12px;
|
||||
margin-right: 0;
|
||||
margin-bottom: 1.2rem;
|
||||
|
||||
&:not(.margin-right) {
|
||||
.d-flex {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
border: 0px;
|
||||
margin-bottom: 1rem;
|
||||
padding: 0rem;
|
||||
width: 684px;
|
||||
}
|
||||
.message-row {
|
||||
margin-left: 12px;
|
||||
margin-right: 12px;
|
||||
.hr {
|
||||
width: 100%;
|
||||
height: 20px;
|
||||
border-bottom: 1px solid $gray-500;
|
||||
text-align: center;
|
||||
margin: 2em 0;
|
||||
}
|
||||
|
||||
&:not(.margin-right) {
|
||||
.d-flex {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
}
|
||||
@media only screen and (max-width: 1200px) {
|
||||
.card {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.hr-middle {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
font-family: 'Roboto Condensed';
|
||||
line-height: 1.5;
|
||||
text-align: center;
|
||||
color: $gray-200;
|
||||
background-color: $gray-700;
|
||||
padding: .2em;
|
||||
margin-top: .2em;
|
||||
display: inline-block;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 1400px) {
|
||||
.message-row {
|
||||
margin-left: -15px;
|
||||
margin-right: -30px;
|
||||
}
|
||||
}
|
||||
.loadmore {
|
||||
justify-content: center;
|
||||
margin-right: 12px;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 24px;
|
||||
|
||||
.card-left {
|
||||
border: 1px solid $purple-500;
|
||||
}
|
||||
|
||||
.card-right {
|
||||
border: 1px solid $gray-500;
|
||||
}
|
||||
|
||||
.hr {
|
||||
> div {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 20px;
|
||||
border-bottom: 1px solid $gray-500;
|
||||
text-align: center;
|
||||
margin: 2em 0;
|
||||
}
|
||||
align-items: center;
|
||||
|
||||
.hr-middle {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
font-family: 'Roboto Condensed';
|
||||
line-height: 1.5;
|
||||
text-align: center;
|
||||
color: $gray-200;
|
||||
background-color: $gray-700;
|
||||
padding: .2em;
|
||||
margin-top: .2em;
|
||||
display: inline-block;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.loadmore {
|
||||
justify-content: center;
|
||||
margin-right: 12px;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 24px;
|
||||
|
||||
> div {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
|
||||
button {
|
||||
text-align: center;
|
||||
color: $gray-50;
|
||||
}
|
||||
button {
|
||||
text-align: center;
|
||||
color: $gray-50;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.loadmore-divider-holder {
|
||||
flex: 1;
|
||||
margin-left: 24px;
|
||||
margin-right: 24px;
|
||||
.loadmore-divider-holder {
|
||||
flex: 1;
|
||||
margin-left: 24px;
|
||||
margin-right: 24px;
|
||||
|
||||
&:last-of-type {
|
||||
margin-right: 0;
|
||||
}
|
||||
&:last-of-type {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.loadmore-divider {
|
||||
height: 1px;
|
||||
border-top: 1px $gray-500 solid;
|
||||
width: 100%;
|
||||
.loadmore-divider {
|
||||
height: 1px;
|
||||
border-top: 1px $gray-500 solid;
|
||||
width: 100%;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.loading {
|
||||
padding-left: 1.5rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.loading {
|
||||
padding-left: 1.5rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -280,6 +285,9 @@ export default {
|
||||
// container.style.overflowY = 'scroll';
|
||||
}
|
||||
}, 50),
|
||||
messageLiked (message) {
|
||||
this.$emit('message-liked', message);
|
||||
},
|
||||
messageRemoved (message) {
|
||||
this.$emit('message-removed', message);
|
||||
},
|
||||
|
||||
@@ -71,7 +71,6 @@
|
||||
id="selectUser"
|
||||
v-model="userSearchTerm"
|
||||
:is-valid="foundUser._id"
|
||||
|
||||
:placeholder="$t('usernameOrUserId')"
|
||||
:invalid-issues="userInputInvalidIssues"
|
||||
/>
|
||||
@@ -318,6 +317,7 @@ export default {
|
||||
computed: {
|
||||
...mapState({
|
||||
currentEventList: 'worldState.data.currentEventList',
|
||||
user: 'user.data',
|
||||
}),
|
||||
currentEvent () {
|
||||
return find(this.currentEventList, event => Boolean(event.gemsPromo) || Boolean(event.promo));
|
||||
@@ -399,6 +399,8 @@ export default {
|
||||
this.foundUser = result;
|
||||
}, 500),
|
||||
selectUser () {
|
||||
this.foundUser.g1g1 = this.currentEvent?.promo === 'g1g1'
|
||||
&& this.foundUser._id !== this.user._id;
|
||||
this.$root.$emit('habitica::send-gift', this.foundUser);
|
||||
this.close();
|
||||
},
|
||||
|
||||
@@ -59,6 +59,12 @@
|
||||
<template v-if="paymentData.paymentType === 'gift-subscription'">
|
||||
<div>
|
||||
<span
|
||||
v-if="paymentData.g1g1"
|
||||
v-html="$t('paymentYouSentSubscriptionG1G1', {
|
||||
name: paymentData.giftReceiver, months: paymentData.subscription.months})"
|
||||
></span>
|
||||
<span
|
||||
v-else
|
||||
v-html="$t('paymentYouSentSubscription', {
|
||||
name: paymentData.giftReceiver, months: paymentData.subscription.months})"
|
||||
></span>
|
||||
|
||||
@@ -429,6 +429,7 @@
|
||||
}
|
||||
|
||||
.btn-update-card {
|
||||
line-height: 1.714;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
padding: 4px 12px;
|
||||
@@ -647,6 +648,7 @@
|
||||
border-radius: 8px;
|
||||
box-shadow: 0px 1px 3px 0px rgba($black, 0.12), 0px 1px 2px 0px rgba($black, 0.24);
|
||||
width: 448px;
|
||||
background-color: $white;
|
||||
}
|
||||
|
||||
.svg-amazon-pay {
|
||||
|
||||
@@ -147,9 +147,17 @@
|
||||
<payments-buttons
|
||||
v-if="userReceivingGift?._id"
|
||||
:disabled="!subscription.key"
|
||||
:stripe-fn="() => redirectToStripe({gift, uuid: userReceivingGift._id, receiverName})"
|
||||
:stripe-fn="() => redirectToStripe({
|
||||
gift,
|
||||
uuid: userReceivingGift._id,
|
||||
receiverName,
|
||||
g1g1: userReceivingGift.g1g1,
|
||||
})"
|
||||
:paypal-fn="() => openPaypalGift({
|
||||
gift: gift, giftedTo: userReceivingGift._id, receiverName,
|
||||
gift: gift,
|
||||
giftedTo: userReceivingGift._id,
|
||||
receiverName,
|
||||
g1g1: userReceivingGift.g1g1,
|
||||
})"
|
||||
/>
|
||||
<payments-buttons
|
||||
|
||||
@@ -27,27 +27,15 @@
|
||||
@changedPosition="tabSelected($event)"
|
||||
>
|
||||
<div slot="right-item">
|
||||
<div
|
||||
<a
|
||||
v-once
|
||||
id="petLikeToEatMarket"
|
||||
class="drawer-help-text"
|
||||
href="/static/faq#pet-foods"
|
||||
target="_blank"
|
||||
>
|
||||
<span>{{ $t('petLikeToEat') + ' ' }}</span>
|
||||
<span
|
||||
class="svg-icon inline icon-16"
|
||||
v-html="icons.information"
|
||||
></span>
|
||||
</div>
|
||||
<b-popover
|
||||
target="petLikeToEatMarket"
|
||||
:placement="'top'"
|
||||
>
|
||||
<div
|
||||
v-once
|
||||
class="popover-content-text"
|
||||
v-html="$t('petLikeToEatText')"
|
||||
></div>
|
||||
</b-popover>
|
||||
<span>{{ $t('petLikeToEat') }}</span>
|
||||
</a>
|
||||
</div>
|
||||
</drawer-header-tabs>
|
||||
</div>
|
||||
@@ -80,7 +68,6 @@
|
||||
import _filter from 'lodash/filter';
|
||||
import { mapState } from '@/libs/store';
|
||||
import inventoryUtils from '@/mixins/inventoryUtils';
|
||||
import svgInformation from '@/assets/svg/information.svg';
|
||||
|
||||
import Drawer from '@/components/ui/drawer';
|
||||
import DrawerSlider from '@/components/ui/drawerSlider';
|
||||
@@ -127,10 +114,6 @@ export default {
|
||||
},
|
||||
],
|
||||
selectedDrawerTab: this.defaultSelectedTab,
|
||||
|
||||
icons: Object.freeze({
|
||||
information: svgInformation,
|
||||
}),
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
||||
@@ -378,7 +378,7 @@
|
||||
height: 40px;
|
||||
border-radius: 2px;
|
||||
background-color: $white;
|
||||
box-shadow: 0 2px 2px 0 rgba(26, 24, 29, 0.16), 0 1px 4px 0 rgba(26, 24, 29, 0.12);
|
||||
box-shadow: 0 2px 2px 0 rgba($black, 0.16), 0 1px 4px 0 rgba($black, 0.12);
|
||||
margin-right: 24px;
|
||||
|
||||
input {
|
||||
@@ -462,17 +462,17 @@
|
||||
|
||||
&.gems {
|
||||
color: $green-10;
|
||||
background-color: rgba(36, 204, 143, 0.15);
|
||||
background-color: rgba($green-100, 0.15);
|
||||
}
|
||||
|
||||
&.gold {
|
||||
color: $yellow-5;
|
||||
background-color: rgba(255, 190, 93, 0.15);
|
||||
background-color: rgba($yellow-100, 0.15);
|
||||
}
|
||||
|
||||
&.hourglasses {
|
||||
color: $hourglass-color;
|
||||
background-color: rgba(41, 149, 205, 0.15);
|
||||
background-color: rgba($blue-10, 0.15);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -516,11 +516,16 @@
|
||||
|
||||
button.btn.btn-primary {
|
||||
margin-top: 16px;
|
||||
padding: 4px 16px;
|
||||
height: 32px;
|
||||
padding: 2px 12px;
|
||||
line-height: 1.714;
|
||||
|
||||
&:focus {
|
||||
border: 2px solid black;
|
||||
border: 2px solid $purple-400;
|
||||
}
|
||||
|
||||
&:active {
|
||||
border: 2px solid $purple-400 !important;
|
||||
box-shadow:none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -297,11 +297,16 @@
|
||||
|
||||
button.btn.btn-primary {
|
||||
margin-top: 16px;
|
||||
padding: 4px 16px;
|
||||
height: 32px;
|
||||
padding: 2px 12px;
|
||||
line-height: 1.714;
|
||||
|
||||
&:focus {
|
||||
border: 2px solid black;
|
||||
border: 2px solid $purple-400;
|
||||
}
|
||||
|
||||
&:active {
|
||||
border: 2px solid $purple-400;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.balance {
|
||||
|
||||
@@ -198,7 +198,7 @@
|
||||
top: 25px;
|
||||
border-radius: 8px;
|
||||
background-color: $gray-600;
|
||||
box-shadow: 0 2px 16px 0 rgba(26, 24, 29, 0.32);
|
||||
box-shadow: 0 2px 16px 0 rgba($black, 0.32);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
@@ -208,12 +208,17 @@
|
||||
}
|
||||
|
||||
button.btn.btn-primary {
|
||||
margin-top: 14px;
|
||||
padding: 4px 16px;
|
||||
height: 32px;
|
||||
margin-top: 16px;
|
||||
padding: 2px 12px;
|
||||
line-height: 1.714;
|
||||
|
||||
&:focus {
|
||||
border: 2px solid black;
|
||||
border: 2px solid $purple-400;
|
||||
}
|
||||
|
||||
&:active {
|
||||
border: 2px solid $purple-400;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,7 +254,7 @@
|
||||
|
||||
&.gems {
|
||||
color: $green-10;
|
||||
background-color: rgba(36, 204, 143, 0.15);
|
||||
background-color: rgba($green-100, 0.15);
|
||||
line-height: 1.4;
|
||||
margin: 0 0 0 -4px;
|
||||
border-radius: 20px;
|
||||
@@ -257,7 +262,7 @@
|
||||
|
||||
&.gold {
|
||||
color: $yellow-5;
|
||||
background-color: rgba(255, 190, 93, 0.15);
|
||||
background-color: rgba($yellow-100, 0.15);
|
||||
line-height: 1.4;
|
||||
margin: 0 0 0 -4px;
|
||||
border-radius: 20px;
|
||||
@@ -265,7 +270,7 @@
|
||||
|
||||
&.hourglasses {
|
||||
color: $hourglass-color;
|
||||
background-color: rgba(41, 149, 205, 0.15);
|
||||
background-color: rgba($blue-10, 0.15);
|
||||
line-height: 1.4;
|
||||
margin: 0 0 0 -4px;
|
||||
border-radius: 20px;
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
position: fixed;
|
||||
right: 10px;
|
||||
width: 350px;
|
||||
z-index: 9999; // to keep it above modal overlays
|
||||
z-index: 999; // to keep it above modal overlays
|
||||
|
||||
top: var(--current-scrollY);
|
||||
|
||||
|
||||
@@ -152,8 +152,11 @@
|
||||
}
|
||||
|
||||
.btn-primary.pull-right {
|
||||
height: 2.5em;
|
||||
line-height: 2.25;
|
||||
margin: auto 0px auto auto;
|
||||
&:focus, :active {
|
||||
border: 2px solid $purple-400;
|
||||
}
|
||||
}
|
||||
|
||||
nav.navbar {
|
||||
|
||||
@@ -552,8 +552,16 @@
|
||||
}
|
||||
|
||||
.sign-up {
|
||||
border: 2px solid transparent;
|
||||
box-shadow: 0 1px 3px 0 rgba($black, 0.16), 0 1px 3px 0 rgba($black, 0.24);
|
||||
padding-top: 11px;
|
||||
padding-bottom: 11px;
|
||||
|
||||
&:focus, &:active {
|
||||
background-color: $blue-50;
|
||||
border: 2px solid $purple-400;
|
||||
box-shadow: 0 3px 6px 0 rgba($black, 0.16), 0 3px 6px 0 rgba($black, 0.24);
|
||||
}
|
||||
}
|
||||
|
||||
::-webkit-input-placeholder { /* Chrome/Opera/Safari */
|
||||
@@ -650,9 +658,9 @@
|
||||
.btn-primary {
|
||||
width: 411px;
|
||||
height: 48px;
|
||||
border-radius: 2px;
|
||||
border-radius: 4px;
|
||||
background-color: $purple-400;
|
||||
box-shadow: 0 2px 2px 0 rgba(26, 24, 29, 0.24), 0 1px 4px 0 rgba(26, 24, 29, 0.16);
|
||||
box-shadow: 0 2px 2px 0 rgba($black, 0.24), 0 1px 4px 0 rgba($black, 0.16);
|
||||
margin-bottom: 5em;
|
||||
}
|
||||
|
||||
@@ -669,7 +677,7 @@
|
||||
|
||||
&:hover {
|
||||
background-color: $purple-50;
|
||||
box-shadow: 0 4px 4px 0 rgba(26, 24, 29, 0.16), 0 1px 8px 0 rgba(26, 24, 29, 0.12);
|
||||
box-shadow: 0 4px 4px 0 rgba($black, 0.16), 0 1px 8px 0 rgba($black, 0.12);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ $itemHeight: 2rem;
|
||||
|
||||
.inline-dropdown {
|
||||
&.select-multi .dropdown-toggle {
|
||||
height: auto;
|
||||
line-height: 1.571;
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
>
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://habitica.fandom.com/wiki/Markdown_Cheat_Sheet"
|
||||
href="https://github.com/HabitRPG/habitica/wiki/Markdown-in-Habitica"
|
||||
:class="cssClass('headings')"
|
||||
>{{ $t('markdownHelpLink') }}</a>
|
||||
</small>
|
||||
@@ -651,9 +651,9 @@
|
||||
|
||||
input, textarea {
|
||||
transition-property: border-color, box-shadow, color, background;
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
background-color: rgba($white, 0.5);
|
||||
&:focus:not(:disabled), &:active:not(:disabled), &:hover:not(:disabled) {
|
||||
background-color: rgba(255, 255, 255, 0.75);
|
||||
background-color: rgba($white, 0.75);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -810,11 +810,7 @@
|
||||
margin-right: 16px;
|
||||
color: $blue-10;
|
||||
}
|
||||
|
||||
.btn-footer {
|
||||
height: 2rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.weekday-check {
|
||||
margin-left: 0px;
|
||||
@@ -884,6 +880,24 @@
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.disabled {
|
||||
background-color: $white;
|
||||
border: 2px solid transparent;
|
||||
color: $gray-200;
|
||||
line-height: 1.714;
|
||||
box-shadow: 0px 1px 3px 0px rgba(26, 24, 29, 0.12), 0px 1px 2px 0px rgba(26, 24, 29, 0.24);
|
||||
|
||||
&:focus {
|
||||
background-color: $white;
|
||||
border: 2px solid $purple-400;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
&:active {
|
||||
box-shadow: 0px 1px 3px 0px rgba(26, 24, 29, 0.12), 0px 1px 2px 0px rgba(26, 24, 29, 0.24);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 768px) {
|
||||
|
||||
@@ -61,6 +61,18 @@
|
||||
left: calc((100% + 236px - 978px) / 2);
|
||||
right: 0%;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 575px) {
|
||||
max-width: none;
|
||||
left: 3%;
|
||||
right: 3%;
|
||||
}
|
||||
|
||||
.message {
|
||||
@media screen and (max-width: 450px) {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.drawer-toggle-icon {
|
||||
@@ -117,6 +129,12 @@
|
||||
padding-top: 6px;
|
||||
padding-left: 24px;
|
||||
padding-right: 24px;
|
||||
|
||||
a {
|
||||
line-height: 1.33;
|
||||
color: $gray-500;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.drawer-tab {
|
||||
@@ -136,7 +154,7 @@
|
||||
color: $white !important;
|
||||
text-decoration: none !important;
|
||||
border-bottom: 2px solid transparent;
|
||||
padding: 0.5rem;
|
||||
padding: 8px;
|
||||
|
||||
&-active, &:hover {
|
||||
color: $white !important;
|
||||
@@ -157,17 +175,19 @@
|
||||
}
|
||||
|
||||
.drawer-slider {
|
||||
padding: 12px 0 0 8px;
|
||||
padding: 0;
|
||||
white-space: nowrap;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
|
||||
& .message {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: auto;
|
||||
|
||||
top: calc(50% - 30px);
|
||||
left: 24px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
position: absolute;
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
|
||||
.header-tabs {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto 1fr;
|
||||
grid-template-columns: max-content;
|
||||
}
|
||||
|
||||
// MS Edge
|
||||
|
||||
@@ -34,12 +34,6 @@
|
||||
<template
|
||||
v-for="item in showItems"
|
||||
>
|
||||
<div
|
||||
v-if="shouldAddVerticalLine(item)"
|
||||
:key="item.key"
|
||||
class="vertical-divider"
|
||||
:style="dividerMargins"
|
||||
></div>
|
||||
<slot
|
||||
name="item"
|
||||
:item="item"
|
||||
@@ -56,6 +50,10 @@
|
||||
|
||||
$buttonAreaWidth: 60;
|
||||
|
||||
.items > div {
|
||||
margin: 0 12px
|
||||
}
|
||||
|
||||
.slider-root {
|
||||
position: relative;
|
||||
}
|
||||
@@ -95,9 +93,11 @@
|
||||
|
||||
&.left-button {
|
||||
left: 0;
|
||||
padding-left: 0px;
|
||||
}
|
||||
|
||||
&.right-button {
|
||||
padding-left:20px;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
@@ -108,15 +108,6 @@
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding-top: 10px;
|
||||
margin-left: $buttonAreaWidth+ px;
|
||||
margin-right: $buttonAreaWidth+ px;
|
||||
}
|
||||
|
||||
.vertical-divider {
|
||||
height: 92px;
|
||||
width: 1px;
|
||||
background: #34313a;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -199,9 +190,6 @@ export default {
|
||||
itemsPerPage () {
|
||||
return Math.floor(this.currentWidth / (this.itemWidth + this.itemMargin));
|
||||
},
|
||||
shouldAddVerticalLine (item) {
|
||||
return this.items[this.itemsPerPage() - 1] === item && this.pointer !== 5;
|
||||
},
|
||||
scrollButtonsVisible () {
|
||||
return this.items.length > this.itemsPerPage();
|
||||
},
|
||||
|
||||
@@ -12,7 +12,9 @@
|
||||
@select="selectItem($event)"
|
||||
>
|
||||
<template #item="{ item }">
|
||||
<span :class="{'dropdown-icon-item': withIcon}">
|
||||
<span
|
||||
:class="{'dropdown-icon-item': withIcon}"
|
||||
>
|
||||
<slot
|
||||
name="item"
|
||||
:item="item"
|
||||
@@ -54,7 +56,3 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
}"
|
||||
>
|
||||
<input
|
||||
ref="textInput"
|
||||
:value="value"
|
||||
class="form-control"
|
||||
:type="inputType"
|
||||
@@ -29,19 +30,23 @@
|
||||
}"
|
||||
:readonly="readonly"
|
||||
:aria-readonly="readonly"
|
||||
autocomplete="off"
|
||||
|
||||
:placeholder="placeholder"
|
||||
@keyup="handleChange"
|
||||
@keyup.enter="$emit('enter')"
|
||||
@blur="$emit('blur')"
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
v-for="issue in invalidIssues"
|
||||
:key="issue"
|
||||
class="input-error"
|
||||
>
|
||||
{{ issue }}
|
||||
</div>
|
||||
<template v-if="!hideErrorLine">
|
||||
<div
|
||||
v-for="issue in invalidIssues"
|
||||
:key="issue"
|
||||
class="input-error"
|
||||
>
|
||||
{{ issue }}
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -85,6 +90,10 @@ export default {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
hideErrorLine: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
@@ -107,6 +116,9 @@ export default {
|
||||
this.wasChanged = true;
|
||||
this.$emit('update:value', value);
|
||||
},
|
||||
focus () {
|
||||
this.$refs.textInput.focus();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -128,4 +140,12 @@ export default {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* this removes safari "save username" UI, we only search for one, we dont want to save it */
|
||||
input::-webkit-contacts-auto-fill-button,
|
||||
input::-webkit-credentials-auto-fill-button {
|
||||
visibility: hidden;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -29,20 +29,12 @@
|
||||
@import '~@/assets/scss/colors.scss';
|
||||
|
||||
.user-link { // this is the user name
|
||||
font-family: 'Roboto Condensed', sans-serif;
|
||||
font-weight: bold;
|
||||
margin-bottom: 0;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
font-size: 16px;
|
||||
|
||||
// currently used in the member-details-new.vue
|
||||
&.smaller {
|
||||
font-family: Roboto;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
line-height: 1.71;
|
||||
}
|
||||
font-size: 14px;
|
||||
line-height: 1.71;
|
||||
display: inline-flex !important;
|
||||
|
||||
&.no-tier {
|
||||
color: $gray-50;
|
||||
@@ -111,7 +103,6 @@ export default {
|
||||
'backer',
|
||||
'contributor',
|
||||
'hideTooltip',
|
||||
'smallerStyle',
|
||||
'showBuffed',
|
||||
'context',
|
||||
],
|
||||
@@ -173,7 +164,7 @@ export default {
|
||||
return this.hideTooltip ? '' : achievementsLib.getContribText(this.contributor, this.isNPC) || '';
|
||||
},
|
||||
levelStyle () {
|
||||
return `${this.userLevelStyleFromLevel(this.level, this.isNPC)} ${this.smallerStyle ? 'smaller' : ''}`;
|
||||
return `${this.userLevelStyleFromLevel(this.level, this.isNPC)}`;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -979,6 +979,7 @@
|
||||
import moment from 'moment';
|
||||
import axios from 'axios';
|
||||
import each from 'lodash/each';
|
||||
import find from 'lodash/find';
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
import achievementsLib from '@/../../common/script/libs/achievements';
|
||||
import Content from '@/../../common/script/content';
|
||||
@@ -1062,8 +1063,12 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
currentEventList: 'worldState.data.currentEventList',
|
||||
flatGear: 'content.gear.flat',
|
||||
}),
|
||||
currentEvent () {
|
||||
return find(this.currentEventList, event => Boolean(event.promo));
|
||||
},
|
||||
userJoinedDate () {
|
||||
return moment(this.user.auth.timestamps.created)
|
||||
.format(this.userLoggedIn.preferences.dateFormat.toUpperCase());
|
||||
@@ -1257,6 +1262,7 @@ export default {
|
||||
},
|
||||
|
||||
openSendGemsModal () {
|
||||
this.user.g1g1 = this.currentEvent?.promo === 'g1g1';
|
||||
this.$store.state.giftModalOptions.startingPage = 'buyGems';
|
||||
this.$root.$emit('habitica::send-gift', this.user);
|
||||
},
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
import debounce from 'lodash/debounce';
|
||||
|
||||
export const autoCompleteHelperMixin = {
|
||||
data () {
|
||||
return {
|
||||
mixinData: {
|
||||
autoComplete: {
|
||||
caretPosition: 0,
|
||||
coords: {
|
||||
TOP: 0,
|
||||
LEFT: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
autoCompleteMixinHandleTab (e) {
|
||||
if (this.$refs.autocomplete.searchActive) {
|
||||
e.preventDefault();
|
||||
if (e.shiftKey) {
|
||||
this.$refs.autocomplete.selectPrevious();
|
||||
} else {
|
||||
this.$refs.autocomplete.selectNext();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
autoCompleteMixinHandleEscape (e) {
|
||||
if (this.$refs.autocomplete.searchActive) {
|
||||
e.preventDefault();
|
||||
this.$refs.autocomplete.cancel();
|
||||
}
|
||||
},
|
||||
|
||||
autoCompleteMixinSelectNextAutocomplete (e) {
|
||||
if (this.$refs.autocomplete.searchActive) {
|
||||
e.preventDefault();
|
||||
this.$refs.autocomplete.selectNext();
|
||||
}
|
||||
},
|
||||
|
||||
autoCompleteMixinSelectPreviousAutocomplete (e) {
|
||||
if (this.$refs.autocomplete.searchActive) {
|
||||
e.preventDefault();
|
||||
this.$refs.autocomplete.selectPrevious();
|
||||
}
|
||||
},
|
||||
|
||||
autoCompleteMixinSelectAutocomplete (e) {
|
||||
if (this.$refs.autocomplete.searchActive) {
|
||||
if (this.$refs.autocomplete.selected !== null) {
|
||||
e.preventDefault();
|
||||
this.$refs.autocomplete.makeSelection();
|
||||
} else {
|
||||
// no autocomplete selected, newline instead
|
||||
this.$refs.autocomplete.cancel();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
autoCompleteMixinUpdateCarretPosition: debounce(function updateCarretPosition (eventUpdate) {
|
||||
this._updateCarretPosition(eventUpdate);
|
||||
}, 250),
|
||||
|
||||
autoCompleteMixinResetCoordsPosition () {
|
||||
this.mixinData.autoComplete.coords = {
|
||||
TOP: 0,
|
||||
LEFT: 0,
|
||||
};
|
||||
},
|
||||
|
||||
// https://medium.com/@_jh3y/how-to-where-s-the-caret-getting-the-xy-position-of-the-caret-a24ba372990a
|
||||
_getCoord (e, text) {
|
||||
const caretPosition = text.selectionEnd;
|
||||
this.mixinData.autoComplete.caretPosition = caretPosition;
|
||||
|
||||
const div = document.createElement('div');
|
||||
const span = document.createElement('span');
|
||||
const copyStyle = getComputedStyle(text);
|
||||
|
||||
[].forEach.call(copyStyle, prop => {
|
||||
div.style[prop] = copyStyle[prop];
|
||||
});
|
||||
|
||||
div.style.position = 'absolute';
|
||||
document.body.appendChild(div);
|
||||
div.textContent = text.value.substr(0, caretPosition);
|
||||
span.textContent = text.value.substr(caretPosition) || '.';
|
||||
div.appendChild(span);
|
||||
this.mixinData.autoComplete.coords = {
|
||||
TOP: span.offsetTop,
|
||||
LEFT: span.offsetLeft,
|
||||
};
|
||||
document.body.removeChild(div);
|
||||
},
|
||||
_updateCarretPosition (eventUpdate) {
|
||||
const text = eventUpdate.target;
|
||||
this._getCoord(eventUpdate, text);
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
import notifications from './notifications';
|
||||
import { NotificationMixins } from './notifications';
|
||||
|
||||
export default {
|
||||
mixins: [notifications],
|
||||
export const CopyToClipboardMixin = {
|
||||
mixins: [NotificationMixins],
|
||||
methods: {
|
||||
async mixinCopyToClipboard (valueToCopy, notificationToShow = null) {
|
||||
if (navigator.clipboard) {
|
||||
@@ -21,3 +21,5 @@ export default {
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default CopyToClipboardMixin;
|
||||
|
||||
@@ -71,6 +71,7 @@ export default {
|
||||
giftData,
|
||||
gemsBlock,
|
||||
sku,
|
||||
g1g1,
|
||||
} = data;
|
||||
let { url } = data;
|
||||
|
||||
@@ -80,6 +81,10 @@ export default {
|
||||
paymentType: type,
|
||||
};
|
||||
|
||||
if (type === 'gift-subscription') {
|
||||
appState.g1g1 = g1g1;
|
||||
}
|
||||
|
||||
if (type === 'subscription') {
|
||||
appState.subscriptionKey = this.subscriptionPlan || this.subscription.key;
|
||||
}
|
||||
@@ -164,6 +169,9 @@ export default {
|
||||
paymentCompleted: false,
|
||||
paymentType,
|
||||
};
|
||||
if (paymentType === 'gift-subscription') {
|
||||
appState.g1g1 = data.g1g1;
|
||||
}
|
||||
if (paymentType === 'subscription') {
|
||||
appState.subscriptionKey = sub.key;
|
||||
} else if (paymentType === 'groupPlan') {
|
||||
|
||||
+574
-414
File diff suppressed because it is too large
Load Diff
+3
-3
@@ -62,7 +62,7 @@
|
||||
|
||||
<script>
|
||||
import moment from 'moment';
|
||||
import userLabel from '../userLabel';
|
||||
import userLabel from '../../components/userLabel.vue';
|
||||
|
||||
import dots from '@/assets/svg/dots.svg';
|
||||
import block from '@/assets/svg/block.svg';
|
||||
@@ -117,7 +117,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '~@/assets/scss/colors.scss';
|
||||
@import '~@/assets/scss/colors';
|
||||
|
||||
.action-padding {
|
||||
height: 24px !important;
|
||||
@@ -153,7 +153,7 @@ export default {
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~@/assets/scss/colors.scss';
|
||||
@import '~@/assets/scss/colors';
|
||||
|
||||
.conversation {
|
||||
padding: 1rem 1.5rem;
|
||||
@@ -0,0 +1,64 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="filtersConversations.length > 0"
|
||||
class="conversations"
|
||||
>
|
||||
<conversation-item
|
||||
v-for="conversation in filtersConversations"
|
||||
:key="conversation.key"
|
||||
:active-key="selectedConversation?.key"
|
||||
:contributor="conversation.contributor"
|
||||
:backer="conversation.backer"
|
||||
:uuid="conversation.key"
|
||||
:display-name="conversation.name"
|
||||
:username="conversation.username"
|
||||
:last-message-date="conversation.date"
|
||||
:last-message-text="conversation.lastMessageText
|
||||
? removeTags(parseMarkdown(conversation.lastMessageText)) : ''"
|
||||
@click="selectConversation(conversation.key)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.conversations {
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
|
||||
import { defineComponent } from 'vue';
|
||||
import habiticaMarkdown from 'habitica-markdown';
|
||||
import conversationItem from '@/pages/private-messages/pm-conversation-item.vue';
|
||||
|
||||
export default defineComponent({
|
||||
components: { conversationItem },
|
||||
props: {
|
||||
filtersConversations: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
selectedConversation: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
removeTags (html) {
|
||||
const tmp = document.createElement('DIV');
|
||||
tmp.innerHTML = html;
|
||||
return tmp.textContent || tmp.innerText || '';
|
||||
},
|
||||
parseMarkdown (text) {
|
||||
if (!text) return null;
|
||||
return habiticaMarkdown.render(String(text));
|
||||
},
|
||||
selectConversation (conversationKey) {
|
||||
this.$emit('selectConversation', conversationKey);
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,37 @@
|
||||
<template>
|
||||
<div
|
||||
class="pm-disabled-caption text-center"
|
||||
>
|
||||
<h4>{{ disabledTexts.title }}</h4>
|
||||
<p>{{ disabledTexts.description }}</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '~@/assets/scss/colors.scss';
|
||||
|
||||
.pm-disabled-caption {
|
||||
padding-top: 1.5em;
|
||||
z-index: 2;
|
||||
|
||||
h4, p {
|
||||
color: $gray-200;
|
||||
}
|
||||
|
||||
h4 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0.4em;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 12px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['disabledTexts'],
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,71 @@
|
||||
<template>
|
||||
<div
|
||||
class="empty-messages m-auto text-center empty-sidebar"
|
||||
>
|
||||
<div class="no-messages-box">
|
||||
<div
|
||||
v-once
|
||||
class="svg-icon envelope mb-4"
|
||||
v-html="icons.mailIcon"
|
||||
></div>
|
||||
<strong
|
||||
v-once
|
||||
class="mb-1"
|
||||
>
|
||||
{{ $t('emptyMessagesLine1') }}
|
||||
</strong>
|
||||
<p v-if="!chatRevoked">
|
||||
{{ $t('emptyMessagesLine2') }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="btn btn-primary mt-4 d-flex align-items-center"
|
||||
@click="$emit('newMessageClicked')"
|
||||
>
|
||||
<div
|
||||
class="svg-icon icon-10 color mr-2"
|
||||
v-html="icons.positive"
|
||||
></div>
|
||||
{{ $t('newMessage') }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '~@/assets/scss/colors.scss';
|
||||
|
||||
strong {
|
||||
line-height: 1.71;
|
||||
color: $gray-100;
|
||||
}
|
||||
|
||||
.svg-icon.icon-10 {
|
||||
margin: 3px;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 24px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import mailIcon from '@/assets/svg/mail.svg';
|
||||
import positiveIcon from '@/assets/svg/positive.svg';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
chatRevoked: Boolean,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
mailIcon,
|
||||
positive: positiveIcon,
|
||||
}),
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,69 @@
|
||||
<template>
|
||||
<div
|
||||
v-once
|
||||
class="centered empty-messages m-auto text-center"
|
||||
>
|
||||
<avatar
|
||||
v-if="memberObj"
|
||||
:member="memberObj"
|
||||
:avatar-only="true"
|
||||
:show-weapon="false"
|
||||
:hide-class-badge="true"
|
||||
:override-top-padding="'0px'"
|
||||
:sprites-margin="'0 0 0 -30px'"
|
||||
:debug-mode="false"
|
||||
:center-avatar="true"
|
||||
class="mb-3"
|
||||
/>
|
||||
|
||||
<strong>{{ memberObj.profile.name }}</strong>
|
||||
<div class="username mb-3">
|
||||
@{{ memberObj.auth.local.username }}
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="kind-text"
|
||||
v-html="$t('rememberToBeKind')"
|
||||
></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '~@/assets/scss/colors.scss';
|
||||
|
||||
.centered {
|
||||
align-content: center;
|
||||
}
|
||||
|
||||
.center-avatar {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
strong {
|
||||
line-height: 1.71;
|
||||
}
|
||||
|
||||
.username {
|
||||
font-size: 12px;
|
||||
line-height: 1.33;
|
||||
color: $gray-100;
|
||||
margin-top: -4px;
|
||||
}
|
||||
|
||||
.kind-text {
|
||||
width: 330px;
|
||||
line-height: 1.71;
|
||||
color: $gray-100;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import Avatar from '@/components/avatar.vue';
|
||||
|
||||
export default {
|
||||
components: { Avatar },
|
||||
props: {
|
||||
memberObj: null,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,44 @@
|
||||
export namespace PrivateMessages {
|
||||
// Shared properties between message types
|
||||
interface SharedMessageProps {
|
||||
username: string;
|
||||
contributor: Record<string, unknown>;
|
||||
userStyles: Record<string, unknown>;
|
||||
canReceive: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the Type we get from our API
|
||||
*/
|
||||
interface ConversationSummaryMessageEntry extends SharedMessageProps {
|
||||
uuid: string;
|
||||
user: string;
|
||||
|
||||
timestamp: string;
|
||||
text: string;
|
||||
count: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Visual (Sidebar) Entry
|
||||
*/
|
||||
interface ConversationEntry extends SharedMessageProps {
|
||||
/**
|
||||
* UUID
|
||||
*/
|
||||
key: string;
|
||||
name: string;
|
||||
|
||||
|
||||
lastMessageText: '',
|
||||
canLoadMore: boolean;
|
||||
page: 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Loaded Private Messages, partial type
|
||||
*/
|
||||
interface PrivateMessageEntry extends SharedMessageProps {
|
||||
text: string;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
<template>
|
||||
<div class="ml-4">
|
||||
<strong
|
||||
v-once
|
||||
v-html="$t('to')"
|
||||
></strong>
|
||||
<validated-text-input
|
||||
id="selectUser"
|
||||
ref="targetUserInput"
|
||||
v-model="targetUserInputValue"
|
||||
class="mx-2"
|
||||
:is-valid="foundUser._id"
|
||||
:only-show-invalid-state="foundUser._id === undefined"
|
||||
|
||||
:hide-error-line="true"
|
||||
:placeholder="$t('usernameOrUserId')"
|
||||
:invalid-issues="userInputInvalidIssues"
|
||||
@enter="triggerNewConversation"
|
||||
/>
|
||||
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
:disabled="preventTrigger"
|
||||
@click="triggerNewConversation()"
|
||||
>
|
||||
{{ $t('confirm') }}
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="ml-2 btn btn-secondary"
|
||||
@click="$emit('cancelNewConversation')"
|
||||
>
|
||||
{{ $t('cancel') }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '~@/assets/scss/colors.scss';
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
div > * {
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
strong {
|
||||
line-height: 1.71;
|
||||
align-content: center;
|
||||
}
|
||||
|
||||
input {
|
||||
border-radius: 2px;
|
||||
border-width: 2px;
|
||||
|
||||
width: 420px;
|
||||
}
|
||||
|
||||
#selectUser {
|
||||
/* changing the style of validate-text-input to the same as others */
|
||||
::v-deep {
|
||||
.input-group {
|
||||
border-width: 2px;
|
||||
|
||||
input {
|
||||
width: 420px;
|
||||
height: 100%;
|
||||
color: $gray-50;
|
||||
}
|
||||
}
|
||||
|
||||
.input-group {
|
||||
&:focus, &:active, &:focus-within {
|
||||
border: solid 2px $purple-400;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<script>
|
||||
|
||||
import debounce from 'lodash/debounce';
|
||||
import isUUID from 'validator/es/lib/isUUID';
|
||||
import ValidatedTextInput from '@/components/ui/validatedTextInput.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ValidatedTextInput,
|
||||
},
|
||||
mixins: [],
|
||||
data () {
|
||||
return {
|
||||
targetUserInputValue: '',
|
||||
userNotFound: false,
|
||||
foundUser: {},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
preventTrigger () {
|
||||
return this.targetUserInputValue.length < 2;
|
||||
},
|
||||
userInputInvalidIssues () {
|
||||
return this.targetUserInputValue.length > 0 && this.userNotFound
|
||||
? [this.$t('userWithUsernameOrUserIdNotFound')]
|
||||
: [''];
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
targetUserInputValue: {
|
||||
handler () {
|
||||
this.searchUser(this.targetUserInputValue.replace('@', ''));
|
||||
},
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
this.$refs.targetUserInput.focus();
|
||||
},
|
||||
methods: {
|
||||
close () {
|
||||
this.$root.$emit('bv::hide::modal', 'select-user-modal');
|
||||
},
|
||||
searchUser: debounce(async function userSearch (searchTerm = '') {
|
||||
this.foundUser = {};
|
||||
if (searchTerm.length < 1) {
|
||||
this.userNotFound = false;
|
||||
return;
|
||||
}
|
||||
let result;
|
||||
if (isUUID(searchTerm)) {
|
||||
try {
|
||||
result = await this.$store.dispatch('members:fetchMember', {
|
||||
memberId: searchTerm,
|
||||
});
|
||||
} catch {
|
||||
result = null;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
result = await this.$store.dispatch('members:fetchMemberByUsername', {
|
||||
username: searchTerm,
|
||||
});
|
||||
} catch {
|
||||
result = null;
|
||||
}
|
||||
}
|
||||
if (!result) {
|
||||
this.userNotFound = true;
|
||||
return;
|
||||
}
|
||||
this.userNotFound = false;
|
||||
this.foundUser = result;
|
||||
}, 500),
|
||||
triggerNewConversation () {
|
||||
const userWithoutAt = this.$refs.targetUserInput.value.replace('@', '');
|
||||
|
||||
this.$emit('startNewConversation', userWithoutAt);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -49,7 +49,7 @@ const GroupPlanIndex = () => import(/* webpackChunkName: "group-plans" */ '@/com
|
||||
const GroupPlanTaskInformation = () => import(/* webpackChunkName: "group-plans" */ '@/components/group-plans/taskInformation');
|
||||
const GroupPlanBilling = () => import(/* webpackChunkName: "group-plans" */ '@/components/group-plans/billing');
|
||||
|
||||
const MessagesIndex = () => import(/* webpackChunkName: "private-messages" */ '@/pages/private-messages');
|
||||
const MessagesIndex = () => import(/* webpackChunkName: "private-messages" */ '@/pages/private-messages/index.vue');
|
||||
|
||||
// Challenges
|
||||
const ChallengeIndex = () => import(/* webpackChunkName: "challenges" */ '@/components/challenges/index');
|
||||
|
||||
@@ -43,7 +43,14 @@ export async function deleteChat (store, payload) {
|
||||
}
|
||||
|
||||
export async function like (store, payload) {
|
||||
const url = `/api/v4/groups/${payload.groupId}/chat/${payload.chatId}/like`;
|
||||
let url = '';
|
||||
|
||||
if (payload.groupId === 'privateMessage') {
|
||||
url = `/api/v4/inbox/like-private-message/${payload.chatMessageId}`;
|
||||
} else {
|
||||
url = `/api/v4/groups/${payload.groupId}/chat/${payload.chatMessageId}/like`;
|
||||
}
|
||||
|
||||
const response = await axios.post(url);
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
+5
-3
@@ -1,14 +1,16 @@
|
||||
import Vue from 'vue';
|
||||
import { shallowMount, createLocalVue } from '@vue/test-utils';
|
||||
|
||||
import ChatCard from '@/components/chat/chatCard.vue';
|
||||
import BootstrapVue from 'bootstrap-vue';
|
||||
import MessageCard from '@/components/messages/messageCard.vue';
|
||||
import Store from '@/libs/store';
|
||||
|
||||
const localVue = createLocalVue();
|
||||
localVue.use(Store);
|
||||
localVue.use(Vue.directive('b-tooltip', {}));
|
||||
localVue.use(BootstrapVue);
|
||||
|
||||
describe('ChatCard', () => {
|
||||
describe('MessageCard', () => {
|
||||
function createMessage (text) {
|
||||
return { text, likes: {} };
|
||||
}
|
||||
@@ -26,7 +28,7 @@ describe('ChatCard', () => {
|
||||
let wrapper;
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = shallowMount(ChatCard, {
|
||||
wrapper = shallowMount(MessageCard, {
|
||||
propsData: { msg: message },
|
||||
store: new Store({
|
||||
state: {
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"achievement": "Постижение",
|
||||
"achievement": "Достижения",
|
||||
"onwards": "Напред!",
|
||||
"levelup": "Изпълнявайки целите си в истинския живот, Вие се качихте ниво и здравето Ви беше запълнено!",
|
||||
"reachedLevel": "Достигнахте Ниво <%= level %>",
|
||||
|
||||
@@ -789,7 +789,7 @@
|
||||
"backgroundBirthdayBashNotes": "Habitica feiert eine Geburtstagsparty und alle sind eingeladen!",
|
||||
"eventBackgrounds": "Ereignis-Hintergründe",
|
||||
"backgroundBirthdayBashText": "Geburtstagsparty",
|
||||
"backgroundInsideACrystalNotes": "Schaue aus einem Kristall hinaus.",
|
||||
"backgroundInsideACrystalNotes": "Schau aus dem Inneren eines Kristalls heraus.",
|
||||
"backgrounds072023": "SET 110: Veröffentlicht im Juli 2023",
|
||||
"backgroundOnAPaddlewheelBoatText": "Auf einem Schaufelradboot",
|
||||
"backgroundOnAPaddlewheelBoatNotes": "Fahre mit einem Schaufelradboot.",
|
||||
@@ -885,5 +885,11 @@
|
||||
"backgrounds102024": "Set 124: Veröffentlicht im September 2024",
|
||||
"backgroundCastleHallWithHearthText": "Schlosshalle mit Feuerstelle",
|
||||
"backgrounds112024": "SET 126: Veröffentlicht im November 2024",
|
||||
"backgroundCastleHallWithHearthNotes": "Entspanne dich in der Wärme einer Schlosshalle mit einer Feuerstelle."
|
||||
"backgroundCastleHallWithHearthNotes": "Entspanne dich in der Wärme einer Schlosshalle mit einer Feuerstelle.",
|
||||
"backgrounds122024": "SET 127: Veröffentlicht im Dezember 2024",
|
||||
"backgroundFirstSnowForestText": "Der erste Schnee im Wald",
|
||||
"backgroundFirstSnowForestNotes": "Tritt in den ersten Schnee im Wald.",
|
||||
"backgrounds012025": "Set 128: Veröffentlicht im Januar 2025",
|
||||
"backgroundWinterLandscapeWithCabinText": "Winterlandschaft mit Hütte",
|
||||
"backgroundWinterLandscapeWithCabinNotes": "Macht es dir in einer Winterlandschaft mit einer Hütte gemütlich."
|
||||
}
|
||||
|
||||
@@ -391,5 +391,6 @@
|
||||
"questEggRaccoonAdjective": "ein gefräßiger",
|
||||
"questEggDogText": "Welpe",
|
||||
"questEggDogMountText": "Hund",
|
||||
"questEggDogAdjective": "ein freundlicher"
|
||||
"questEggDogAdjective": "ein freundlicher",
|
||||
"hatchingPotionGingerbread": "Lebkuchen"
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
"webFaqAnswer34": "Haustiere mögen Futter, das zu ihrer Farbe passt. Basis-Tiere sind die Ausnahme, aber alle Basis-Tiere mögen den gleichen Gegenstand. Im Folgenden siehst du, welche Nahrungsmittel jedes Haustier mag:\n\n * Basistiere mögen Fleisch\n * Weiße Haustiere mögen Milch\n * Wüstenhaustiere mögen Kartoffeln\n * Rote Haustiere mögen Erdbeeren\n * Schattentiere mögen Schokolade\n * Skelett-Tiere mögen Fisch\n * Zombie-Tiere mögen verdorbenes Fleisch\n * Zuckerwatte rosa Haustiere mögen rosa Zuckerwatte\n * Zuckerwatte blaue Haustiere mögen blaue Zuckerwatte\n * Goldene Haustiere mögen Honig",
|
||||
"webFaqAnswer35": "Sobald du dein Haustier genug gefüttert hast, um es zu einem Reittier zu machen, musst du diese Art von Haustier erneut ausbrüten, um es in deinem Stall zu haben.\n\nUm Reittiere in den mobilen Apps zu sehen:\n\n * Wähle im Menü \"Haustiere & Reittiere\" und wechseln zur Registerkarte \"Reittiere\".\n\nSo zeigst du Reittiere auf der Website an:\n\n * Wähle im Menü \"Inventar\" die Option \"Haustiere und Reittiere\" und scrollen nach unten zum Abschnitt \"Reittiere\"",
|
||||
"webFaqAnswer37": "Kontrolliere, ob die Option Kostüm aktiviert ist. Wenn dein Avatar ein Kostüm trägt, wird dieses Ausrüstungsset anstelle deiner Kampfausrüstung angezeigt.\n\nSo schaltest du das Kostüm in den mobilen Apps ein:\n * Wähle im Menü \"Ausrüstung\", um den Schalter für das Kostüm zu finden.\n\nSo schaltest du das Kostüm auf der Website um:\n * Wähle in deinem Inventar \"Ausrüstung\" und suche den Schalter \"Kostüm\" auf der Registerkarte \"Kostüm\" in der Ausrüstungsschublade",
|
||||
"webFaqAnswer41": "Mystische Sanduhren sind die exklusive Abonnentenwährung von Habitica, die im Mysteriöse Zeitreisende Laden verwendet wird! Sanduhren werden nach einem bestimmten Zeitplan geliefert, der auf Ihrem Abonnementplan basiert.\n\nZeitplan für die Lieferung von Sanduhren:\n * 1-Monats-Abonnenten erhalten 1 Sanduhr am Anfang des Monats nach der 3. aufeinanderfolgenden Zahlung.\n * 3-Monats-Abonnenten erhalten 1 Sanduhr sofort nach Abschluss des Abonnements, dann 1 weitere Sanduhr zu Beginn des Monats nach jeder Erneuerung.\n * 6-Monats-Abonnenten erhalten 2 Sanduhren sofort nach Abschluss des Abonnements, dann 2 weitere Sanduhren zu Beginn des Monats nach jeder Verlängerung.\n * 12-Monats-Abonnenten erhalten 4 Sanduhren sofort nach Abschluss des Abonnements, dann 4 weitere Sanduhren zu Beginn des Monats nach jeder Verlängerung.",
|
||||
"webFaqAnswer41": "Mystische Sanduhren sind die exklusive Abonnentenwährung von Habitica, die im Zeitreisenden-Shop verwendet wird. Abonnenten erhalten 1 Mystische Sanduhr am Anfang jedes Monats, in dem sie Abonnenten-Vorteile haben, zusammen mit einigen weiteren Vorteilen. Bitte beachte unsere Abonnement-Optionen, wenn Du an den besonderen Hintergründen-, Haustier-, Quest- und Ausrüstungsangeboten im Zeitreisenden-Shop interessiert bist!",
|
||||
"webFaqAnswer42": "Eine der besten Möglichkeiten, sich zu motivieren und sich selbst für die Erledigung von Aufgaben verantwortlich zu machen, ist der Beitritt zu einer Gruppe! Eine Party mit anderen Habitica-Spielern ist eine großartige Möglichkeit, Quests anzunehmen, um Haustiere und Ausrüstung zu erhalten, Stärkungszauber von den Fertigkeiten der Party-Mitglieder zu bekommen und deine Motivation zu steigern.\n\nEine weitere Möglichkeit, die Verantwortlichkeit zu erhöhen, ist die Teilnahme an einer Herausforderung. Herausforderungen fügen eurer Liste automatisch Aufgaben hinzu, die mit einem bestimmten Ziel verbunden sind! Außerdem bieten sie ein Element des Wettbewerbs mit anderen Habitica-Spielern, das dir einen Motivationsschub geben kann, während du nach dem Edelsteinpreis strebst. Es gibt offizielle Herausforderungen, die vom Habitica-Team erstellt wurden, sowie Herausforderungen, die von anderen Spielern erstellt wurden.",
|
||||
"webFaqAnswer44": "Du musst die Challenge verlassen oder warten, bis die Challenge geschlossen wird, um die zugehörigen Aufgaben zu löschen. Ein rotes Megaphon-Symbol bedeutet, dass die Challenge geschlossen wurde, ein graues Megaphon bedeutet, dass die Challenge noch läuft.\n\nSo löschst du Challenge-Aufgaben in der **Android**-App:\n 1. Tippe auf eine Aufgabe, die zur Challenge gehört.\n 2. Tippe auf \"Löschen\" in der oberen rechten Ecke des Bildschirms.\n 3. Wähle, um die Aufgaben der Herausforderung aus deiner Aufgabenliste zu entfernen.\n\nSo löschst du Challenge-Aufgaben in der **iOS**-App:\n 1. Suche die Challenge-Aufgabe, die du löschen möchtest, und sieh dir das Megaphon-Symbol an.\n 2. Wenn das Megaphon-Symbol rot ist, tippe auf die Aufgabe und wähle unten \"Löschen\".\n 3. Wenn das Megaphon-Symbol grau ist, musst du die Herausforderung finden und sie verlassen.\n\nSo löschst du Challenge-Aufgaben auf der **Website**:\n 1. Suche die Challenge-Aufgabe, die du löschen möchtest, und sieh dir das Megaphon-Symbol an.\n 2. Wenn das Megaphon-Symbol rot ist, klicke darauf und wähle dann, die Aufgabe aus deiner Aufgabenliste zu entfernen.\n 3. Wenn das Megaphon-Symbol grau ist, musst du die Herausforderung finden und sie verlassen, um die Aufgabe zu entfernen.",
|
||||
"sunsetFaqPara5": "Wenn Sie mehr über die Änderungen erfahren möchten, ließ bitte die folgenden Informationen.",
|
||||
|
||||
@@ -2924,7 +2924,7 @@
|
||||
"armorSpecialFall2024HealerText": "Space Invader Rüstung",
|
||||
"armorSpecialFall2024HealerNotes": "Sei eins mit der Galaxis und hypnotisiere Zuschauer mit dieser Rüstung. Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe 2024 Herbstausrüstung.",
|
||||
"armorSpecialFall2024MageText": "Unterwelt Hexer Rüstung",
|
||||
"armorSpecialFall2024MageNotes": "Sei eins mit der Unterwelt und umarme die Macht der Magier, die vor dir diese Rüstung trugen. Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe 2024 Herbstaausrüstung.",
|
||||
"armorSpecialFall2024MageNotes": "Sei eins mit der Unterwelt und umarme die Macht der Magier, die vor dir diese Rüstung trugen. Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe 2024 Herbstausrüstung.",
|
||||
"weaponArmoireFunnyFoolBatonNotes": "Du kannst mit einem Schwung Deines Stabes eine Pointe vortragen, die Aufmerksamkeit erregen oder Beifall ernten. Erhöht Ausdauer und Stärke jeweils um <%= attrs %>. Verzauberter Schrank: Lustiges Narren-Set (Gegenstand 3 von 3)",
|
||||
"armorArmoireTeaGownText": "Teeparty Kleid",
|
||||
"armorArmoireTeaGownNotes": "Du bist zäh, kreativ, brilliant und so modisch! Erhöht Stärke und Intelligenz um jeweils <%= attrs %>. Verzauberter Schrank: Teeparty Set (Gegenstand 1 von 3).",
|
||||
@@ -2969,5 +2969,225 @@
|
||||
"armorArmoireBasketballUniformNotes": "Fragst du dich, was auf dem Rücken dieser Uniform aufgedruckt ist? Deine Glückszahl, natürlich! Erhöht Wahrnehmung um <%= per %>.Verzauberter Schrank: Altertümliches Basketballset (Gegenstand 1 von 2).",
|
||||
"armorArmoireShawlCollarCoatNotes": "Ein weiser Zauberer sagte einst, dass nichts besser ist als es sowohl gemütlich zu haben als auch produktiv zu sein! Trage diesen warmen und stylischen Mantel, wenn du die diesjährigen Herausforderungen meisterst. Erhöht Ausdauer um <%= con %>.",
|
||||
"armorArmoirePaintersApronText": "Schürze des Malers",
|
||||
"armorArmoirePaintersApronNotes": "Diese Schürze kann deine Kleidung vor Farbe und deine kreativen Projekte vor harschen Kritiken schützen. Erhöht Ausdauer um <%= con %>. Verzauberter Schrank: Maler-Set (Gegenstand 1 von 4)."
|
||||
"armorArmoirePaintersApronNotes": "Diese Schürze kann deine Kleidung vor Farbe und deine kreativen Projekte vor harschen Kritiken schützen. Erhöht Ausdauer um <%= con %>. Verzauberter Schrank: Maler-Set (Gegenstand 1 von 4).",
|
||||
"weaponSpecialWinter2025WarriorText": "Axt des Elchkriegers",
|
||||
"weaponSpecialWinter2025WarriorNotes": "Eine mächtige Axt für einen mächtigen Elch! Du wirst unaufhaltbar sein! Erhöht Stärke um <%= str %>. Limitierte Ausgabe 2024-2025 Winterausrüstung.",
|
||||
"weaponSpecialWinter2025RogueText": "Schneeflockenausbruch",
|
||||
"weaponSpecialWinter2025RogueNotes": "Stampfe und blende diese schwierigen Aufgaben zur Unterwerfung! Du wirst unaufhaltbar sein! Erhöht Stärke um <%= str %>.Limitierte Ausgabe 2024-2025 Winterausrüstung.",
|
||||
"weaponSpecialWinter2025HealerText": "Sternenzauberstab",
|
||||
"weaponSpecialWinter2025HealerNotes": "Was du jetzt brauchst, sind mehr Lichter und ein leuchtender Stern obendrauf! Du wirst unaufhaltbar sein! Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe 2024-2025 Winterausrüstung.",
|
||||
"weaponSpecialWinter2025MageText": "Nordlicht-Display",
|
||||
"weaponSpecialWinter2025MageNotes": "Diese beeindruckende, farbenfrohe Show bietet die perfekte Kulisse! Du wirst unaufhaltbar sein! Erhöht Intelligenz um <%= int %> und Wahrnehmung um <%= per %>. Limitierte Ausgabe 2024-2025 Winterausrüstung.",
|
||||
"armorSpecialWinter2025WarriorText": "Rüstung des Elchkriegers",
|
||||
"armorSpecialWinter2025RogueText": "Schneekostüm",
|
||||
"armorSpecialWinter2025HealerText": "Lichterketten-Robe",
|
||||
"armorSpecialWinter2025HealerNotes": "Funkle Deinen Weg durch deine Aufgaben. Sei nur vorsichtig - wenn eine Birne ausgeht, gehen alle aus. Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe 2024-2025 Winterausrüstung.",
|
||||
"armorSpecialWinter2025MageText": "Aurora-Umhang",
|
||||
"armorSpecialWinter2025MageNotes": "Wunder, Exzentrik, Verzauberung und Pracht werden Deine Tage füllen, wenn Du in diesem Umhang tanzt. Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe 2024-2025 Winterausrüstung.",
|
||||
"armorSpecialWinter2025WarriorNotes": "Jeder wird beiseitetreten und Dir Platz machen, wenn Du diese Rüstung trägst. Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe 2024-2025 Winterausrüstung.",
|
||||
"armorSpecialWinter2025RogueNotes": "Auch wenn Du so ausiehst, als wärst Du mit kaltem Schnee bedeckt, bist Du angenehm gewärmt, ausgelassen und glücklich, wenn du dieses Kostüm trägst. Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe 2024-2025 Winterausrüstung.",
|
||||
"armorMystery202412Text": "Zuckerstangen-Waldkaninchen-Umhang",
|
||||
"armorMystery202412Notes": "Ein unterhaltsamer und fluffiger Look, um dich an einem Wintertag gemütlich zu halten. Gewährt keinen Attributbonus. Dezember 2024 Abonnentengegenstand.",
|
||||
"armorArmoireDragonKnightsArmorText": "Drachenritterrüstung",
|
||||
"armorArmoireFunnyFoolCostumeText": "Kostüm des lustigen Narren",
|
||||
"armorArmoireStormKnightArmorText": "Rüstung des Sturmritters",
|
||||
"armorArmoireCorsairsCoatAndCapeNotes": "Ob Du nun deine Zeit an den Docks totschlägst oder auf dem offenen Meer nach Gefahren Aussschau hältst, werden diese Dich mit Sicherheit trocken halten und Dich dramatisch aussehen lassen. Halte nur das Gleichgewicht an Deck. Erhöht Ausdauer um <%= con %>. Verzauberter Schrank: Korsaren-Set (Gegenstand 1 von 3)",
|
||||
"armorArmoireDragonKnightsArmorNotes": "Bündle die Stärke und Macht eines Drachen mit dieser Rüstung aus Silber und verlorenen Schuppen. Erhöht Stärke um <%= str %>. Verzauberter Schrank: Drachenritter-Set (Gegenstand 2 von 3)",
|
||||
"armorArmoireFunnyFoolCostumeNotes": "Dum-di-dum! Sicher scherzest Du. Dieses farbenfrohe Outfit steht Dir ausgezeichnet! Erhöht Stärke um <%= str %>. Verzauberter Schrank: Lustiger Narr-Set (Gegenstand 2 von 3)",
|
||||
"armorArmoireStormKnightArmorNotes": "In dieser Rüstung bist Du fast unverwundbar. Deine Feinde werden niemals das Ende des Sturms sehen. Erhöht Wahrnehmung um <%= per %>. Verzauberter Schrank: Sturmritter-Set (Gegenstand 2 von 3)",
|
||||
"headSpecialWinter2023WarriorNotes": "Dieser Walrosshelm eignet sich hervorragend um mit einem Freund zu plaudern oder an einer pfiffigen Mahlzeit teilzunehmen. Erhöht Stärke um <%= str %>. Limitierte Ausgabe 2022-2023 Winterausrüstung.",
|
||||
"armorArmoireFestiveHelperOverallsText": "Festliche Helfer-Latzhosen",
|
||||
"headSpecialWinter2023WarriorText": "Walrosshelm",
|
||||
"armorArmoireFestiveHelperOverallsNotes": "Diese strapazierfähige und bequeme Latzhose eignet sich hervorragend um zu arbeiten, zu spielen und andere zu unterstützen. Außerdem hat sie Taschen! Erhöht Ausdauer um <%= con %>. Verzauberter Schrank: Festliches Helferset (Gegenstand 2 von 2)",
|
||||
"eyewearMystery202308Text": "Schläfrige Augen",
|
||||
"headSpecialWinter2023RogueText": "Geschenkschleife",
|
||||
"headSpecialWinter2023RogueNotes": "Die Versuchung der Leute, dein Haar „auszupacken“, gibt dir Gelegenheit, das Ducken und Ausweichen zu üben. Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe 2022-2023 Winterausrüstung.",
|
||||
"headSpecialWinter2023MageText": "Feenlicht-Diadem",
|
||||
"headSpecialSpring2023RogueText": "Raupen-Kutte",
|
||||
"headSpecialWinter2023MageNotes": "Wurdest du mit einem Sternennacht-Elixier ausgebrütet? Denn ich habe für dich Sterne in meinen Augen. Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe 2022-2023 Winterausrüstung.",
|
||||
"headSpecialWinter2023HealerNotes": "Dieser kardinalrote Helm eignet sich perfekt, um die Wintersaison durch pfeifen und singen einzuläuten. Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe 2022-2023 Winterausrüstung.",
|
||||
"headSpecialWinter2023HealerText": "Kardinalroter Helm",
|
||||
"headSpecialSpring2023RogueNotes": "Achte darauf, dass du diese verlockenden Fühler einziehst, wenn Vögel über dir jagen! Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe 2023 Frühlingsausrüstung.",
|
||||
"headSpecialFall2024MageNotes": "Ob Du nun geheimnisvoll oder skurril bist, man wird Dich nicht übersehen, wenn Du dies trägst! Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe Herbst-Ausrüstung 2024.",
|
||||
"headSpecialFall2024MageText": "Zauberer-Maske der Unterwelt",
|
||||
"shieldSpecialWinter2025HealerNotes": "Das perfekte Geschenk wartet nur darauf, geöffnet zu werden. Was könnte drin sein? Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe Wintergegenstand 2024-2025.",
|
||||
"shieldSpecialWinter2025HealerText": "Das Perfekte Geschenk",
|
||||
"eyewearArmoireJewelersEyeLoupeNotes": "Diese Augenlupe vergrößert das zu bearbeitende Objekt, sodass Du jedes Detail sehen kannst. Erhöht Wahrnehmung um <%= per %>. Verzauberter Schrank: Juwelierset (Gegenstand 1 von 2).",
|
||||
"eyewearArmoireJewelersEyeLoupeText": "Juwelier-Augenlupe",
|
||||
"headSpecialSpring2023WarriorText": "Kolibri Helm",
|
||||
"headSpecialSpring2023MageNotes": "Du solltest diese Gläser in der Nacht tragen, damit du bei Mondlicht klar sehen kannst. Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe 2023 Frühlingsausrüstung.",
|
||||
"headSpecialSpring2023WarriorNotes": "Bedecke dein Gesicht mit irisierenden Federn, wenn du in die Schlacht fliegst. Erhöht Stärke um <%= str %>. Limitierte Ausgabe 2023 Frühlingsausrüstung.",
|
||||
"headSpecialSpring2023MageText": "Mondstein Visier",
|
||||
"headSpecialSummer2023RogueText": "Guppy Kappe",
|
||||
"headSpecialSummer2023WarriorText": "Goldfisch Flosse",
|
||||
"headSpecialSummer2023WarriorNotes": "Diese fabelhafte Flosse gibt dir Stabilität, wenn du mühsamen, vor dir liegenden Aufgaben entgegenschwimmst. Erhöht Stärke um <%= str %>. Limitierte Ausgabe 2023 Sommerausrüstung.",
|
||||
"headSpecialSummer2023RogueNotes": "Gup, zwo, drei vier! Keine Zeit, gegessen zu werden, muß Aufgaben abhaken! Erhöht Wahrnehmung um <%= per %>.Limitierte Ausgabe 2023 Sommerausrüstung.",
|
||||
"headSpecialSpring2023HealerText": "Lilien Blüte",
|
||||
"headSpecialSummer2023MageText": "Korallen-Geweih",
|
||||
"headSpecialSummer2023MageNotes": "Die Weisheit eines ganzen Ökosystems ist mit dir, wenn du deine maritime Magie wirkst. Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe 2023 Sommerausrüstung.",
|
||||
"headSpecialSummer2023HealerNotes": "Das sind keine Schlangen! Du kannst deine Augen öffnen, es ist sicher! Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe 2023 Sommerausrüstung.",
|
||||
"headSpecialSummer2023HealerText": "Seetang Krone",
|
||||
"headSpecialFall2023RogueNotes": "Dieser verhexte Eintopf hat dir das haarige Gesicht und die langen Ohren eines Esels beschert! Wie überaus shakespeareisch. Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe 2023 Herbstausrüstung.",
|
||||
"headSpecialFall2023RogueText": "Verzaubertes Gesicht",
|
||||
"headSpecialFall2023WarriorText": "Spukschirm",
|
||||
"headSpecialFall2023WarriorNotes": "Welcher Horror lauert in diesem Reich der Verzerrung und des Rauschens? Du musst am Ball bleiben, um das herauszufinden! Erhöht Stärke um <%= str %>. Limitierte Ausgabe 2023 Herbstausrüstung.",
|
||||
"headSpecialFall2023MageText": "Scharlachrote Hexenmeister Maske",
|
||||
"headSpecialFall2023MageNotes": "Mit stechenden Augen und pointiertem Flair macht es jede Illusion plötzlich zu einer Möglichkeit. Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe 2023 Herbstausrüstung.",
|
||||
"headSpecialWinter2024RogueText": "Schneeeulen Haube",
|
||||
"headSpecialNye2023Notes": "Du hast einen Lächerlichen Partyhut erhalten! Trage ihn mit Stolz, wenn du das neue Jahr einläutest! Gewährt keinen Attributbonus.",
|
||||
"headSpecialWinter2024RogueNotes": "Wen wirst du sehen, wenn du diese Hauuuube trägst? Nun, wen wirst du NICHT sehen? Du wirst jede Bewegung, jede Geste, jedes Detail um dich herum erfassen. Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe Winter 2023-2024 Ausrüstung.",
|
||||
"headSpecialNye2023Text": "Lächerlicher Partyhut",
|
||||
"headSpecialSpring2023HealerNotes": "Dieses brillante und farbenfrohe Bild hat die gleiche Farbgebung wie die Sphäre der Wiedergeburt! Wie symbolträchtig! Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe 2023 Frühlingsausrüstung.",
|
||||
"headSpecialFall2023HealerText": "Sumpfkreaturen-Maske",
|
||||
"headSpecialFall2023HealerNotes": "Mit Augen, so dunkel wie das Moor, aus dem es entstieg, fixiert es seine Gegner. Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe 2023 Herbstausrüstung.",
|
||||
"headSpecialWinter2024WarriorNotes": "Noch nie war es so köstlich, seine Birne zu schützen! Erhöht Stärke um <%= str %>. Limitierte Ausgabe Winter 2023-2024 Ausrüstung.",
|
||||
"headSpecialWinter2024HealerNotes": "Oh oh, ein missglückter Zauberspruch hat dich im Eis gefangen! Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe Winter 2023-2024 Ausrüstung.",
|
||||
"headSpecialWinter2024HealerText": "Gefrorener Helm",
|
||||
"headSpecialWinter2024MageNotes": "Die mit Fleece gefütterte Kapuze schützt dich vor Kälte, aber auch vor negativen Gedanken und Vibes. Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe Winter 2023-2024 Ausrüstung.",
|
||||
"headSpecialSpring2024MageText": "Hibiskus-Hut",
|
||||
"headSpecialWinter2024WarriorText": "Pfefferminz-Schokobruch-Helm",
|
||||
"headSpecialSpring2024WarriorText": "Fluorit Kopfputz",
|
||||
"headSpecialWinter2024MageText": "Narwal Zauberer Haube",
|
||||
"headSpecialSpring2024MageNotes": "Was könnte einschüchternder auf Feinde wirken, als diesen mit Pollen bedeckten Hut zu zeigen? Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe Frühling 2024 Ausrüstung.",
|
||||
"headSpecialSpring2024RogueText": "Nass-Schnee-Kapuze",
|
||||
"headSpecialSpring2024WarriorNotes": "Was könnte atemberaubender sein, als diese Kristallkrone im Kampf zu tragen? Erhöht Stärke um <%= str %>. Limitierte Ausgabe Frühling 2024 Ausrüstung.",
|
||||
"headSpecialSpring2024HealerNotes": "Welche fröhlichen Lieder wirst du singen, wenn du diesen Helm trägst? Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe Frühling 2024 Ausrüstung.",
|
||||
"headSpecialSpring2024RogueNotes": "Welche Wünsche und Hoffnungen werden auftauchen, wenn Eis und Schnee einem fruchtbaren Boden weichen? Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe Frühling 2024 Ausrüstung.",
|
||||
"armorArmoireSnowyFluffTrimmedCoatText": "Schneeweißer Flauschmantel",
|
||||
"armorArmoireSnowyFluffTrimmedCoatNotes": "Wenn die ersten Flocken um dich herum fallen, hält dich dieser Mantel nicht nur warm, sondern sorgt auch dafür, dass du dich perfekt in die verschneite Umgebung einfügst. Gleite mit Stil über das Eis! Erhöht Stärke und Intelligenz um jeweils <%= attrs %>. Verzauberter Schrank: Schneebedeckter Schlappergut-Set (Gegenstand 2 von 2).",
|
||||
"headSpecialSummer2024HealerNotes": "Diese spiralförmige Muschel erinnert dich daran, nicht durchzudrehen. Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe Sommer 2024 Ausrüstung.",
|
||||
"headMystery202301Text": "Tapfere Vulpinaohren",
|
||||
"headSpecialSummer2024MageNotes": "Dieser Hut schwingt sanft in den Meeresströmungen und hilft dir, deine Weisheit zu kanalisieren. Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe Sommer 2024 Ausrüstung.",
|
||||
"headSpecialWinter2025RogueNotes": "Dieser Hut hat definitiv etwas Magisches an sich, denn er verwandelt dich in einen Schneemenschen. Lass den Hasen nur nicht zu nahe an deine Karottennase herankommen. Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe Winterausrüstung 2024-2025.",
|
||||
"headMystery202403Notes": "Du kannst dich glücklich schätzen, diese feine Mütze aus smaragdgrünem Samt mit ihrem feinen meergrünen Edelstein tragen zu können. Gewährt keinen Attributbonus. März 2024 Abonnentengegenstand.",
|
||||
"headMystery202312Text": "Winterlich Blaues Haar",
|
||||
"headSpecialSummer2024RogueText": "Nacktschnecken-Helm",
|
||||
"headMystery202403Text": "Aquamarin-Glückskappe",
|
||||
"headSpecialSummer2024WarriorText": "Walhai-Helm",
|
||||
"headSpecialFall2024RogueNotes": "Ob du nun geschmeidig oder gerissen bist, wenn du das trägst, wirst du nicht übersehen! Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe Herbstausrüstung 2024.",
|
||||
"headMystery202312Notes": "Diese ausgefallene Frisur erinnert an die frostigen Farben der Saison. Gewährt keinen Attributbonus. Dezember 2023 Abonnentengegenstand.",
|
||||
"headSpecialSummer2024RogueNotes": "Dieser Helm mit seinen hornartigen Tentakeln hilft dir, dich zu verstecken, damit du zu deinen eigenen Bedingungen zuschlagen kannst. Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe Sommer 2024 Ausrüstung.",
|
||||
"headSpecialSummer2024WarriorNotes": "Mit diesem hilfreichen Helm lassen sich knifflige Aufgaben in zwei Teile zerlegen. Erhöht Stärke um <%= str %>. Limitierte Ausgabe Sommer 2024 Ausrüstung.",
|
||||
"headSpecialFall2024HealerNotes": "Ob du deinen Planeten verteidigst oder einen neuen erkundest, wenn du das trägst, wirst du nicht übersehen! Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe Herbstausrüstung 2024.",
|
||||
"headSpecialWinter2025WarriorText": "Elchkrieger-Helm",
|
||||
"headSpecialWinter2025WarriorNotes": "Also, hör zu: Jetzt siehst du aus wie ein Elch. Trag dieses Geweih mit Stolz. Erhöht Stärke um <%= str %>. Limitierte Ausgabe Winterausrüstung 2024-2025.",
|
||||
"headSpecialFall2024RogueText": "Schwarze Katzenmaske",
|
||||
"headSpecialFall2024HealerText": "Space Invader-Maske",
|
||||
"headSpecialWinter2025HealerNotes": "Es ist nicht nötig, sie zu entwirren, da sie bereits die Form eines Hutes haben. Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe Winterausrüstung 2024-2025.",
|
||||
"headSpecialWinter2025MageText": "Aurorahut",
|
||||
"headSpecialWinter2025MageNotes": "Dieser Hut ist mehr als nur ein schicker Fascinator, er lässt dich wie das Polarlicht selbst aussehen. Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe Winterausrüstung 2024-2025.",
|
||||
"headSpecialSummer2024MageText": "Seeanemonen-Hut",
|
||||
"headSpecialSummer2024HealerText": "Seeschneckenhaus",
|
||||
"headSpecialFall2024WarriorText": "Feurige Koboldmaske",
|
||||
"headSpecialFall2024WarriorNotes": "Egal, ob du schelmisch oder bedrohlich bist, wenn du das trägst, wirst du nicht übersehen! Erhöht Stärke um <%= str %>. Limitierte Ausgabe Herbstausrüstung 2024.",
|
||||
"headSpecialWinter2025RogueText": "Schneemaske",
|
||||
"headSpecialWinter2025HealerText": "Lichterketten-Wirrwarr",
|
||||
"headMystery202402Notes": "Diese hübsche rosa Mähne ist das perfekte Accessoire für den Februar und darüber hinaus. Gewährt keinen Attributbonus. Februar 2024 Abonnentengegenstand.",
|
||||
"headMystery202402Text": "Paradiesisches Rosa Haar",
|
||||
"headMystery202301Notes": "Dein Gehör wird so scharf sein, dass du das Hereinbrechen des Morgens und das Glitzern des Taus hören wirst. Gewährt keinen Attributbonus. Jänner 2023 Abonnentengegenstand.",
|
||||
"headMystery202304Text": "Tiptop Teekannen-Deckel",
|
||||
"headMystery202304Notes": "Dieser Helm gewährt dir Immuni-Tee-t. April 2023 Abonnentengegenstand.",
|
||||
"headMystery202310Text": "Narrenkappe",
|
||||
"headMystery202311Text": "Zauberweberhut",
|
||||
"headMystery202311Notes": "Verwebe sogar Raum und Zeit mit deinem Willen. Gewährt keinen Attributbonus. November 2023 Abonnentengegenstand.",
|
||||
"headMystery202310Notes": "Sie verbirgt dein Gesicht und verleiht deinen Augen dennoch einen beunruhigenden und gespenstischen Glanz. Gewährt keinen Attributbonus. Oktober 2023 Abonnentengegenstand.",
|
||||
"headMystery202303Text": "Künstlermähnen-Haar",
|
||||
"headMystery202303Notes": "Wie könnte man besser zeigen, dass man der Star dieser Geschichte ist, als mit blauem und unwahrscheinlich stacheligem Haar? Gewährt keinen Attributbonus. März 2023 Abonnentengegenstand.",
|
||||
"headMystery202308Text": "Lila Protagonistenhaar",
|
||||
"headMystery202308Notes": "Steht die widerspenstige Kutte, die aus der Mitte deines Kopfes ragt, für deine Hartnäckigkeit oder deinen Hang zum Unfug? Gewährt keinen Attributbonus. August 2023 Abonnentengegenstand.",
|
||||
"headMystery202407Notes": "Mit diesen magischen Kiemen kannst du unter Wasser atmen! Gewährt keinen Attributbonus. Juli 2024 Abonnentengegenstand.",
|
||||
"headMystery202411Notes": "Dieser Helm ist für deine Aufgaben ziemlich einschüchternd, wenn du dich kopfüber in die Arbeit stürzt! Gewährt keinen Attributbonus. November 2024 Abonnentengegenstand.",
|
||||
"headMystery202501Notes": "Dieser glitzernde Hut erzeugt ständig ein leichtes und festliches Gewusel um dich herum. Gewährt keinen Attributbonus. Jänner 2025 Abonnentengegenstand.",
|
||||
"headArmoireBeaniePropellerHatText": "Propeller-Beaniemütze",
|
||||
"headMystery202409Text": "Sonnwend-Magierhut",
|
||||
"headMystery202409Notes": "Die verzauberten Sonnenblumen auf diesem Hut sind mehr als nur eine fröhliche Dekoration, sie erfüllen den Träger mit mächtiger magischer Energie. Gewährt keinen Attributbonus. September 2024 Abonnentengegenstand.",
|
||||
"headMystery202407Text": "Sympathische Axolotl-Haube",
|
||||
"headMystery202411Text": "Borstenhelm",
|
||||
"headMystery202412Text": "Zuckerstangen-Kaninchenhaube",
|
||||
"headMystery202412Notes": "Warm und gemütlich, wie eine Tasse heißer Kakao mit Minze in einer Winternacht! Gewährt keinen Attributbonus. Dezember 2024 Abonnentengegenstand.",
|
||||
"headMystery202501Text": "Frostbinder-Hut",
|
||||
"headMystery202406Notes": "Die geisterhaften Federn, die diesen Hut zieren, leuchten schwach, wie die Wellen eines gespenstischen Meeres. Gewährt keinen Attributbonus. Juni 2024 Abonnentengegenstand.",
|
||||
"headArmoireTeaHatText": "Teepartyhut",
|
||||
"headArmoirePaintersBeretText": "Malermütze",
|
||||
"headArmoireAdmiralsBicorneText": "Admirals-Zweispitz",
|
||||
"headArmoireAdmiralsBicorneNotes": "Hut ab! Wenn du diesen Zweispitz trägst, wirst du weiser, klüger, mutiger... und größer sein. Erhöht Intelligenz und Wahrnehmung um jeweils <%= attrs %>. Verzauberter Schrank: Admiralsset (Gegenstand 1 von 2).",
|
||||
"headArmoireBeaniePropellerHatNotes": "Jetzt ist nicht die Zeit, um am Boden zu bleiben! Drehe diesen kleinen Propeller und erhebe dich so hoch, wie dein Ehrgeiz dich tragen wird. Erhöht alle Eigenschaften um <%= attrs %>. Verzauberter Schrank: Unabhängiger Gegenstand.",
|
||||
"headArmoirePaintersBeretNotes": "Mit dieser flotten Baskenmütze siehst du die Welt mit einem künstlerischen Auge. Erhöht Wahrnehmung um <%= per %>. Verzauberter Schrank: Malerset (Gegenstand 2 von 4).",
|
||||
"headArmoireTeaHatNotes": "Dieser elegante Hut ist so schick wie funktional. Erhöht Wahrnehmung um <%= per %>. Verzauberter Schrank: Teepartyset (Gegenstand 2 von 3).",
|
||||
"headArmoirePurpleSpookySorceryHatText": "Gespenstischer Lila Magierhut",
|
||||
"headArmoirePurpleSpookySorceryHatNotes": "Purpurrot wie die Dämmerung und voller Geheimnisse, ist dieser Hut für all deine zauberhaften Bedürfnisse geeignet. Erhöht Wahrnehmung um <%= per %> und Ausdauer um <%= con %>. Verzauberter Schrank: Gespenstisches Magie-Set (Gegenstand 2 von 3).",
|
||||
"headArmoireBlackSpookySorceryHatText": "Gespenstischer Schwarzer Magierhut",
|
||||
"headArmoireBlackSpookySorceryHatNotes": "Schwarz wie die Nacht und voller Geheimnisse, ist dieser Hut für all deine zauberhaften Bedürfnisse geeignet. Erhöht Intelligenz um <%= per %> und Ausdauer um <%= con %>. Verzauberter Schrank: Gespenstisches Magie-Set (Gegenstand 3 von 3).",
|
||||
"headArmoireDragonKnightsHelmText": "Drachenritterhelm",
|
||||
"headArmoireCorsairsBandanaText": "Piratenbandana",
|
||||
"headArmoireFunnyFoolCapText": "Lustige Narrenkappe",
|
||||
"headArmoireWhiteFloppyHatNotes": "Viele Zaubersprüche wurden in diesen einfachen Hut eingenäht und verleihen ihm eine wundersame weiße Farbe. Erhöht Stärke, Intelligenz und Ausdauer um jeweils <%= attrs %>. Verzauberter Schrank: Weißes Loungewear -Set (Gegenstand 1 von 3).",
|
||||
"headArmoireCorsairsBandanaNotes": "Egal, ob du deinen Kopf bedecken willst, falls eine Möwe über dich hinwegfliegt, oder ob du sicherstellen willst, dass deine Feinde dich nicht schwitzen sehen, dieses Tuch ist unverzichtbar. Füge einfach eine Zierperle für jedes Abenteuer hinzu, das du bestehst. Erhöht Intelligenz um <%= int %>. Verzauberter Schrank: Korsaren-Set (Gegenstand 2 von 3)",
|
||||
"headArmoireFunnyFoolCapNotes": "Die Glöckchen an diesem Hut könnten deine Gegner zum Kichern bringen, aber dir helfen sie nur, dich zu konzentrieren. Erhöht Ausdauer um <%= con %>. Verzauberter Schrank: Lustiges Narren-Set (Gegenstand 1 von 3)",
|
||||
"headArmoireDragonKnightsHelmNotes": "Mit den feurigen Elementen auf diesem Helm könnten Drachen dich für einen der ihren halten. Erhöht Intelligenz um <%= int %>. Verzauberter Schrank: Drachenritter-Set (Gegenstand 1 von 3)",
|
||||
"headArmoireStormKnightHelmText": "Sturmritterhelm",
|
||||
"headArmoireGreenTrapperHatText": "Grüne Trappermütze",
|
||||
"headArmoireGreenTrapperHatNotes": "Alle sagen, dass deine Mütze so warm aussieht! Und das ist sie tatsächlich. Achte nur darauf, dass du die Klappen von deinen Ohren ziehst, wenn die Leute mit dir reden, sonst hört sich das Ganze eher nach „dne ütze sht ss wrrm ss!“ an. Erhöht Ausdauer und Wahrnehmung um jeweils <%= attrs %> . Verzauberter Schrank: Trappermützen-Set (Gegenstand 1 von 2).",
|
||||
"headArmoireStormKnightHelmNotes": "Nutze die Blitze dieses Geweihs, wenn du die Burg stürmst. Erhöht Ausdauer um <%= con %>. Verzauberter Schrank: Sturmritter-Set (Gegenstand 1 von 3)",
|
||||
"shieldSpecialWinter2024HealerText": "Salzstreuer",
|
||||
"shieldMystery202408Text": "Geheimnisvolles Glitzern",
|
||||
"shieldArmoireTrustyPencilText": "Treuer Bleistift",
|
||||
"shieldSpecialWinter2024WarriorText": "Keksschild",
|
||||
"shieldSpecialFall2024WarriorText": "Flammenschild",
|
||||
"shieldArmoireSaucepanText": "Kochtopf",
|
||||
"shieldArmoireBuoyantBeachBallText": "Strandball",
|
||||
"shieldSpecialSummer2023WarriorText": "Goldfischseele",
|
||||
"shieldSpecialFall2024HealerText": "Weltraumschild",
|
||||
"shieldMystery202409Text": "Sonnwendmagierstab",
|
||||
"shieldArmoireSafetyFlashlightText": "Sicherheitstaschenlampe",
|
||||
"headArmoireFestiveHelperHatText": "Festlicher Helferhut",
|
||||
"headArmoireSnowyTrapperHatText": "Verschneiter Trapperhut",
|
||||
"headArmoireSnowyTrapperHatNotes": "Blaue, erfrorene Ohren gehören der Vergangenheit an. Freue Dich auf kuschelige Wärme mit Stil! Erhöht Ausdauer und Wahrnehmung um jeweils <%= attrs %> . Verzauberter Schrank: Verschneiter Trapperhut-Set (Gegenstand 1 von 2).",
|
||||
"shieldSpecialSummer2024WarriorText": "Walhaiflosse",
|
||||
"shieldSpecialSummer2024HealerText": "Meeresschneckenschild",
|
||||
"shieldSpecialFallRogue2024Text": "Bänderstab",
|
||||
"shieldSpecialWinter2025WarriorText": "Elchkriegerschild",
|
||||
"shieldMystery202501Text": "Frostbinderstab",
|
||||
"shieldSpecialWinter2023WarriorText": "Austernschild",
|
||||
"shieldSpecialWinter2023WarriorNotes": "„Die Zeit ist reif“, das Walroß sprach, „Von mancherlei zu reden – Von Austernschal'n – und Schneegeläut – Von Liedern die da schweben. – Und wohin die Perle des Schilds verschwunden ist – oder wie wir im neuen Jahr leben. Erhöht Ausdauer um <%= con %>.Limitierte Ausgabe 2022-2023 Winterausrüstung.",
|
||||
"shieldSpecialSpring2023WarriorText": "Blumenstrauß",
|
||||
"shieldSpecialSummer2023HealerText": "Seeigel",
|
||||
"shieldArmoireTeaKettleText": "Teekessel",
|
||||
"shieldSpecialFall2023RogueText": "Verhexte Flasche",
|
||||
"shieldSpecialFall2023WarriorText": "Bequemes Kissen",
|
||||
"shieldSpecialFall2023HealerText": "Moosiger Felsen",
|
||||
"shieldArmoireBucketText": "Eimer",
|
||||
"shieldArmoireBasketballText": "Basketball",
|
||||
"backMystery202301Text": "Fünf Schweife der Tapferkeit",
|
||||
"shieldArmoirePaintersPaletteText": "Malerpalette",
|
||||
"shieldSpecialSpring2023HealerText": "Lilienmieder",
|
||||
"shieldSpecialWinter2023HealerNotes": "Dein Lied von Frost und Schnee besänftigt die Geister aller, die es hören. Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe 2022-2023 Winterausrüstung.",
|
||||
"shieldMystery202409Notes": "Der leuchtende Rubin auf diesem Stab bezieht seine Kraft aus der Spätsommersonne. Gewährt keinen Attributbonus. September 2024 Abonnentengegenstand.",
|
||||
"backMystery202410Text": "Kandiszucker-Schweif",
|
||||
"headAccessoryMystery202410Text": "Kandiszucker-Ohren",
|
||||
"headAccessoryMystery202410Notes": "Sind das die Geräusche von „Süßes-oder-Saures“-Kindern an deiner Tür? Gewährt keinen Attributbonus. Oktober 2024 Abonnentengegenstand.",
|
||||
"bodyMystery202411Text": "Stachelige Schulterplatten",
|
||||
"headArmoireFestiveHelperHatNotes": "Urlaubstipp Nr. 27: Halten Sie einen Helferhut bereit. Dieser ist groß genug, um ein Notfallspielzeug darunter zu verstecken! Erhöht Intelligenz um <%= int %>. Verzauberter Schrank: Festliches Helferset (Gegenstand 1 von 2)",
|
||||
"shieldMystery202501Notes": "Dekoriere jede Außenumgebung mit einer diamantenen Schicht aus schimmerndem Frost. Gewährt keinen Attributbonus. Jänner 2025 Abonnentengegenstand.",
|
||||
"shieldSpecialWinter2025WarriorNotes": "Blocke alle unerwünschten Ablenkungen mit diesem Schild, das so stark wie ein Elch ist. Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe Winterausrüstung 2024-2025.",
|
||||
"backMystery202410Notes": "Dieser Schweif wird bei der Erwähnung von gruseligen Leckereien aktiv. Gewährt keinen Attributbonus. Oktober 2024 Abonnentengegenstand.",
|
||||
"shieldArmoireSafetyFlashlightNotes": "Warte, hast du das Geräusch gehört? Schnell! Leuchte mit deiner Taschenlampe in den Schatten dort drüben. Hmmm. Sieht aus, als wäre es nur der Wind gewesen. Oder war es...? Erhöht Ausdauer um <%= con %>. Verzauberter Schrank: Gruselnacht-Set (Gegenstand 1 von 2)",
|
||||
"bodyMystery202411Notes": "Die furchterregenden Stacheln auf diesen Schulterplatten sind perfekt, um deine Aufgabenliste in Angriff zu nehmen. Gewährt keinen Attributbonus. November 2024 Abonnentengegenstand.",
|
||||
"shieldSpecialSpring2023WarriorNotes": "Sammle die schönsten Blumen des Frühlings in diesem farbenfrohen Blumenstrauß. Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe 2023 Frühlingsausrüstung.",
|
||||
"shieldSpecialWinter2023HealerText": "Coole Lieder",
|
||||
"shieldSpecialSpring2023HealerNotes": "Ein Beitrag zu einem Genesungsbesuch oder Teil eines Rituals für einen Frühlingstanz! Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe 2023 Frühlingsausrüstung.",
|
||||
"shieldSpecialWinter2024WarriorNotes": "Du bist ein tougher Keks, der niemals bröselt! Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe Winter 2023-2024 Ausrüstung.",
|
||||
"shieldSpecialSummer2023HealerNotes": "Du verbirgst und beschützt es. Es hält neugierige Monster davon ab, zu nahe zu kommen. Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe 2023 Sommerausrüstung.",
|
||||
"shieldSpecialFall2023RogueNotes": "Mit den stärksten Zaubern verstärkt, um mächtige Tränke zu halten. Erhöht Stärke um <%= str %>. Limitierte Ausgabe 2023 Herbstausrüstung.",
|
||||
"shieldSpecialFall2023WarriorNotes": "Perfekt, um es dir bequem zu machen, während du einen Horrorfilm genießt... Aber wir verraten es niemand, wenn du es bei den grusligen Szenen in den Arm nehmen musst! Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe 2023 Herbstausrüstung.",
|
||||
"shieldSpecialSummer2023WarriorNotes": "Beschwöre diesen Goldfischgeist für einen extra Schub Bestärkung und Begleitung während eines Kampfes. Ausdauer um <%= con %>. Limitierte Ausgabe 2023 Sommerausrüstung.",
|
||||
"shieldSpecialWinter2024HealerNotes": "Wie praktisch, dass du beim Einfrieren eisschmelzende Materialien dabei hattest! Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe Winter 2023-2024 Ausrüstung.",
|
||||
"shieldSpecialSummer2024WarriorNotes": "Zu denen, die behaupten, du könntest deine Ziele nicht erreichen, sag einfach: Sprich zu meiner Hand, äh, Flosse! Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe Sommer 2024 Ausrüstung.",
|
||||
"shieldSpecialSummer2024HealerNotes": "Dieses glänzende Schild ist sogar stärker als ein Meeresschneckenstab. Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe Sommer 2024 Ausrüstung.",
|
||||
"shieldSpecialFall2023HealerNotes": "Mit seinem festen Kern und dem weichen Bezug ist er ideal, um ihn auf Feinde zu schleudern oder um sich darauf zu setzen, wenn man eine Pause von seinen Abenteuern braucht. Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe 2023 Herbstausrüstung.",
|
||||
"shieldSpecialFall2024HealerNotes": "Neue Aufgaben, die nach deiner Aufmerksamkeit greifen, prallen ab, bis du deine aktuelle Mission erledigt hast. Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe Herbstausrüstung 2024.",
|
||||
"shieldSpecialFall2024WarriorNotes": "Komplikationen bei Aufgaben werden von deinem Schild absorbiert und machen dich entschlossener. Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe Herbstausrüstung 2024.",
|
||||
"shieldSpecialFallRogue2024Notes": "Die Aufgaben selbst werden von den Wirbeln und Spiralen dieser hypnotischen Waffe überwältigt. Erhöht Stärke um <%= str %>. Limitierte Ausgabe Herbstausrüstung 2024.",
|
||||
"headAccessoryMystery202212Notes": "Mit dieser verschnörkelten goldenen Tiara werden deine Herzlichkeit und Freundschaft neue Höhen erreichen. Gewährt keinen Attributbonus. Dezember 2022 Abonnentengegenstand.",
|
||||
"headAccessoryMystery202212Text": "Eis-Tiara"
|
||||
}
|
||||
|
||||
@@ -291,13 +291,13 @@
|
||||
"worldBossBullet4": "Besuche regelmäßig die Taverne um den Fortschritt des Weltbosses und seine Raserei-Angriffe zu prüfen",
|
||||
"worldBoss": "Weltboss",
|
||||
"groupPlanTitle": "Brauchst Du mehr Leute für Deine Crew?",
|
||||
"groupPlanDesc": "Ein kleines Team leiten oder Hausarbeiten organisieren? Unsere Gruppenpläne gewähren Dir exklusiven Zugang zu einem privaten Task-Board und Chat-Bereich, der Dir und Deinen Gruppenmitgliedern gewidmet ist!",
|
||||
"groupPlanDesc": "Hausarbeiten organisieren oder ein kleines Klassenprojekt leiten? Habiticas Gruppenpläne bieten gemeinsame Aufgaben und einen eigenen Chat-Bereich, damit du und dein Team motiviert bleiben.",
|
||||
"billedMonthly": "*verrechnet als monatliches Abonnement",
|
||||
"teamBasedTasksList": "Gruppenbasierte Aufgabenliste",
|
||||
"teamBasedTasksListDesc": "Richte eine übersichtliche, gemeinsame Aufgabenliste für die Gruppe ein. Weise Deinen Gruppenmitgliedern Aufgaben zu oder lasse sie ihre eigenen Aufgaben beanspruchen, um deutlich zu machen, woran alle arbeiten!",
|
||||
"groupManagementControls": "Gruppen-Management-Steuerungen",
|
||||
"groupManagementControlsDesc": "Zeige den Aufgabenstatus an, um zu überprüfen, ob eine Aufgabe abgeschlossen wurde, füge Gruppen-Manager hinzu, um Verantwortlichkeiten zu teilen, und genieße einen privaten Gruppenchat für alle Gruppenmitglieder.",
|
||||
"inGameBenefits": "Vorteile im Spiel",
|
||||
"teamBasedTasksList": "Gemeinsame Aufgabenliste",
|
||||
"teamBasedTasksListDesc": "Alle Gruppenmitglieder können an derselben Aufgabenliste arbeiten, um sicherzustellen, dass die Gruppe immer auf dem Laufenden bleibt. Erledige Aufgaben auf der gemeinsamen Aufgabenliste oder kopiere sie zu deinen persönlichen Aufgaben, um sie unterwegs zu erledigen.",
|
||||
"groupManagementControls": "Flexible Verantwortlichkeit",
|
||||
"groupManagementControlsDesc": "Teile Verantwortlichkeiten auf, indem du Aufgaben einer beliebigen Anzahl von Mitgliedern zuweist, oder stelle Aufgaben als Herausforderung ein, um zu sehen, wer sie zuerst erledigen kann. Die Gruppenmitglieder können sich über den Fortschritt der Aufgaben informieren, indem sie den Status aller Aufgaben einsehen.",
|
||||
"inGameBenefits": "Alle Vorteile!",
|
||||
"inGameBenefitsDesc": "Gruppenmitglieder erhalten ein exklusives Wolpertinger-Reittier sowie volle Abonnementvorteile, einschließlich spezieller monatlicher Ausrüstungssets und der Möglichkeit, Edelsteine mit Gold zu kaufen.",
|
||||
"letsMakeAccount": "Lass uns Dir als erstes einen Account erstellen",
|
||||
"nameYourGroup": "Wähle als nächstes einen Namen für Deine Gruppe",
|
||||
@@ -378,7 +378,7 @@
|
||||
"descriptionOptional": "Beschreibung",
|
||||
"descriptionOptionalText": "Füge eine Beschreibung hinzu",
|
||||
"nameStarText": "Füge einen Titel hinzu",
|
||||
"nextPaymentMethod": "Weiter: Zahlungsmethode",
|
||||
"nextPaymentMethod": "Weiter: Zahlung",
|
||||
"dayStart": "<strong>Tageswechsel</strong>: <%= startTime %>",
|
||||
"viewStatus": "Status",
|
||||
"newGroupsWhatsNew": "Schau nach, was neu ist:",
|
||||
|
||||
@@ -255,7 +255,7 @@
|
||||
"dayTen": "Tag 10",
|
||||
"birthdaySet": "Geburtstags-Set",
|
||||
"fourForFreeText": "Um die Party am Laufen zu halten, verschenken wir Party Gewänder, 20 Edelsteine, und eine limitierte Geburtstags-Hintergrund Ausgabe und ein Gegenstände Set, das ein Cape, ein Schulterstück und eine Augenmaske enthält.",
|
||||
"partyRobes": "Party Gewänder",
|
||||
"partyRobes": "Party-Roben",
|
||||
"twentyGems": "20 Edelsteine",
|
||||
"dayOne": "Tag 1",
|
||||
"summer2024WhaleSharkWarriorSet": "Walhai Set (Krieger)",
|
||||
@@ -266,5 +266,9 @@
|
||||
"fall2024UnderworldSorcerorMageSet": "Unterwelt Hexer Set (Magier)",
|
||||
"fall2024SpaceInvaderHealerSet": "Space Invader Set (Heiler)",
|
||||
"fall2024BlackCatRogueSet": "Schwarzes Katzen Set (Schurke)",
|
||||
"gemSaleLimitationsText": "Dieses Angebot gilt nur während der zeitlich beschränkten Aktion. Diese Aktion startet am <%= eventStartMonth %> <%= eventStartOrdinal %> um <%= eventStartTime %> lokale Zeit (<%= eventStartUTC %> UTC) und endet am <%= eventEndMonth %> <%= eventEndOrdinal %> um <%= eventEndTime %> lokale Zeit (<%= eventEndUTC %> UTC). Das Aktionsangebot ist nur verfügbar, wenn du Edelsteine für dich selbst kaufst."
|
||||
"gemSaleLimitationsText": "Dieses Angebot gilt nur während der zeitlich beschränkten Aktion. Diese Aktion startet am <%= eventStartMonth %> <%= eventStartOrdinal %> um <%= eventStartTime %> <%= timeZone %> und endet am <%= eventEndMonth %> <%= eventEndOrdinal %> um <%= eventEndTime %> <%= timeZone %>. Das Aktionsangebot ist nur verfügbar, wenn du Edelsteine für dich selbst kaufst.",
|
||||
"winter2025StringLightsHealerSet": "Lichterketten Heiler Set",
|
||||
"winter2025SnowRogueSet": "Schneeschurken Set",
|
||||
"winter2025MooseWarriorSet": "Elchkrieger Set",
|
||||
"winter2025AuroraMageSet": "Aurora Magier Set"
|
||||
}
|
||||
|
||||
@@ -19,11 +19,11 @@
|
||||
"sleepDescription": "Brauchst Du eine Pause? Pausiere Schaden (unter Einstellungen), um ein paar der kniffligeren Habitica-Spielmechanismen zu pausieren:",
|
||||
"sleepBullet1": "Deine verpassten Tagesaufgaben werden Dir nicht schaden (Bosse werden dennoch Deiner Party Schaden zufügen, wenn andere Partymitglieder ihre Täglichen Aufgaben verpassen)",
|
||||
"sleepBullet2": "Deine Aufgaben-Strähnen und Gewohnheits-Zähler werden nicht zurückgesetzt",
|
||||
"sleepBullet3": "Dein Schaden gegen Quest-Bosse oder Deine gefundenen Sammelgegenstände bleiben pausiert, bis Du Schaden wieder aktivierst.",
|
||||
"sleepBullet3": "Dein Schaden gegen Quest-Bosse oder Deine gefundenen Sammelgegenstände bleiben pausiert, bis Du Schaden wieder aktivierst",
|
||||
"pauseDailies": "Schaden pausieren",
|
||||
"unpauseDailies": "Schaden wieder aktivieren",
|
||||
"staffAndModerators": "Mitarbeiter und Moderatoren",
|
||||
"communityGuidelinesIntro": "Habitica versucht, eine einladende Umgebung für Benutzer aller Alterstufen zu schaffen, vor allem an Plätzen wie Gruppen und Parties. Wenn Du unsicher bist oder noch Fragen hast, lies bitte unsere <a href='/static/community-guidelines' target='_blank'>Community-Richtlinien</a>.",
|
||||
"communityGuidelinesIntro": "Habitica versucht, eine einladende Umgebung für Benutzer aller Alterstufen zu schaffen, vor allem an Plätzen wie Gruppen und Parties. Wenn Du unsicher bist oder noch Fragen hast, lies bitte unsere <a href='/static/community-guidelines' target='_blank'>Community-Richtlinien</a>.",
|
||||
"acceptCommunityGuidelines": "Ich stimme zu, mich an die Community-Richtlinien zu halten",
|
||||
"worldBossEvent": "Weltboss-Ereignis",
|
||||
"worldBossDescription": "Weltboss-Beschreibung",
|
||||
@@ -79,7 +79,7 @@
|
||||
"newBaileyUpdate": "Neues Update von Bailey!",
|
||||
"tellMeLater": "Erzähl es mir später",
|
||||
"dismissAlert": "Als gelesen markieren",
|
||||
"donateText3": "Als Open-Source-Projekt ist Habitica auf die Hilfe unserer Benutzer angewiesen. Das Geld, was Du für Edelsteine ausgibst, hilft uns dabei unsere Server am Laufen zu halten, ein paar Mitarbeiter zu bezahlen, neue Features zu entwickeln und unseren ehrenamtlichen Helferlein Anreize zu bieten.",
|
||||
"donateText3": "Als Open-Source-Projekt ist Habitica auf die Hilfe unserer Benutzer angewiesen. Das Geld, was Du für Edelsteine ausgibst, hilft uns dabei unsere Server am Laufen zu halten, ein paar Mitarbeiter zu bezahlen, neue Features zu entwickeln und unseren ehrenamtlichen Helferlein Anreize zu bieten",
|
||||
"card": "Kreditkarte",
|
||||
"paymentMethods": "Kauf mit",
|
||||
"paymentSuccessful": "Die Zahlung war erfolgreich!",
|
||||
@@ -117,7 +117,7 @@
|
||||
"paymentAutoRenew": "Dieses Abonnement wird automatisch erneuert bis es gekündigt wird. Wenn Du dieses Abonnement kündigen musst, kannst Du dies in Deinen Einstellungen tun.",
|
||||
"paymentCanceledDisputes": "Wir haben eine Bestätigung der Kündigung an Deine E-Mailadresse gesendet. Falls Du die E-Mail nicht erhältst, kontaktiere uns bitte um zu verhindern, dass es zu Zahlungsstreitigkeiten kommt.",
|
||||
"cannotUnpinItem": "Dieser Gegenstand kann nicht von der Pinnwand entfernt werden.",
|
||||
"paymentSubBillingWithMethod": "Dein Abonnement wird in Höhe von <strong>$<%= amount %></strong> alle <strong><%= months %> Monat(e)</strong> per <strong><%= paymentMethod %></strong> abgerechnet.",
|
||||
"paymentSubBillingWithMethod": "Dein Abonnement wird in Höhe von <br><strong>$<%= amount %>.00 USD</strong> alle <strong><%= months %> Monat(e)</strong> per <strong><%= paymentMethod %></strong> abgerechnet",
|
||||
"invalidUnlockSet": "Dieses Set an Gegenständen ist abgelaufen und kann nicht freigeschaltet werden.",
|
||||
"nGems": "<%= nGems %> Edelsteine",
|
||||
"nMonthsSubscriptionGift": "<%= nMonths %> Monat(e) Abonnement (Geschenk)",
|
||||
@@ -131,5 +131,6 @@
|
||||
"groupsPaymentAutoRenew": "Dieses Abonnement läuft automatisch weiter, bis es gekündigt wird. Du kannst es im Gruppen-Abrechnungs-Tab kündigen.",
|
||||
"sellItems": "Items verkaufen",
|
||||
"customizationsShopText": "Willst du deinen Style ändern? Hier bist du richtig! Wir haben die frischesten Looks, passend zur Saison, auf Lager.",
|
||||
"notAvailable": "Dieser Gegenstand ist nicht verfügbar."
|
||||
"notAvailable": "Dieser Gegenstand ist nicht verfügbar.",
|
||||
"paymentYouSentSubscriptionG1G1": "Du hast <strong><%- name %></strong><br> ein <%= months %>-Monat(e)-Abo für Habitica geschickt und dasselbe Abo wurde deinem Account im Zuge der \"Schenk' Eins, Bekomm' Eins\"-Aktion gutgeschrieben!"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"stable": "Stall",
|
||||
"stable": "Haus- und Reittiere",
|
||||
"pets": "Haustiere",
|
||||
"activePet": "Aktives Haustier",
|
||||
"noActivePet": "Kein aktives Haustier",
|
||||
@@ -57,11 +57,11 @@
|
||||
"mountMasterText2": " und hat alle 90 Reittiere <%= count %> mal freigelassen",
|
||||
"triadBingoName": "Triaden-Bingo",
|
||||
"triadBingoText": "Hat alle 90 Haustiere gesammelt, alle 90 Reittiere gezähmt, und WIEDER alle 90 Haustiere gefunden (WIE HAST DU DAS GESCHAFFT?!)",
|
||||
"triadBingoText2": " und hat seinen kompletten Stall <%= count %> mal freigelassen",
|
||||
"triadBingoText2": " und hat alle Haus- und Reittiere <%= count %> mal freigelassen",
|
||||
"triadBingoAchievement": "Du hast den Erfolg \"Triaden-Bingo\" erhalten, da Du alle Haustiere gefunden, alle Reittiere gezähmt und wieder alle Haustiere gefunden hast!",
|
||||
"hatchedPet": "Du hast ein neues <%= potion %> <%= egg %> ausgebrütet!",
|
||||
"hatchedPetGeneric": "Du hast ein neues Haustier ausgebrütet!",
|
||||
"hatchedPetHowToUse": "Geh in den [Stall](<%= stableUrl %>) um Dein neuestes Haustier zu füttern und auszurüsten!",
|
||||
"hatchedPetHowToUse": "Geh zu den [Haus- und Reittieren](<%= stableUrl %>) um Dein neuestes Haustier zu füttern und auszurüsten!",
|
||||
"petNotOwned": "Du besitzt dieses Haustier nicht.",
|
||||
"mountNotOwned": "Du besitzt dieses Reittier nicht.",
|
||||
"feedPet": "<%= text %> an <%= name %> verfüttern?",
|
||||
@@ -83,7 +83,7 @@
|
||||
"petsReleased": "Haustiere freigelassen.",
|
||||
"mountsAndPetsReleased": "Reit- und Haustiere freigelassen",
|
||||
"mountsReleased": "Reittiere freigelassen",
|
||||
"welcomeStable": "Willkommen im Stall!",
|
||||
"welcomeStable": "Willkommen bei deinen Haus- und Reittieren!",
|
||||
"welcomeStableText": "Willkommen im Stall! Ich bin Matt, der Bestienmeister. Jedes Mal, wenn Du eine Aufgabe erledigst, besteht die Chance, zufällig ein Ei oder ein Schlüpfelixier zu erhalten, mit deren Hilfe Haustiere ausgebrütet werden können. Wenn Du ein Haustier ausgebrütet hast, taucht es hier auf! Klicke auf ein Haustier damit es sich zu Deinem Avatar gesellt. Füttere sie mit dem Futter, das Du findest, und sie wachsen zu kräftigen Reittieren heran.",
|
||||
"petLikeToEat": "Was frisst mein Haustier gern?",
|
||||
"petLikeToEatText": "Haustiere wachsen, egal welches Futter Du ihnen gibst, aber sie wachsen schneller, wenn Du ihnen ihre Lieblingsspeise fütterst. Experimentiere herum, um das Muster zu finden, oder sieh hier nach: <br/> <a href=\"https://habitica.fandom.com/de/wiki/Futter#Bevorzugtes_Futter\" target=\"_blank\">https://habitica.fandom.com/de/wiki/Futter#Bevorzugtes_Futter</a>",
|
||||
|
||||
@@ -779,13 +779,36 @@
|
||||
"questGiraffeUnlockText": "Schält Giraffen Eier zum Kauf im Marktplatz frei.",
|
||||
"questChameleonUnlockText": "Schält Chamäleon Eier zum Kauf im Marktplatz frei",
|
||||
"questGiraffeText": "Die Gear-affe",
|
||||
"questCrabRageTitle": "Ablenkendes Gefummel",
|
||||
"questCrabRageTitle": "Ablenkender Zeitvertreib",
|
||||
"questCrabText": "Die fummelnde Krabbe",
|
||||
"questCrabBoss": "Fummelnde Krabbe",
|
||||
"questCrabBoss": "Herumtrödelnde Krabbe",
|
||||
"questGiraffeNotes": "Du schlenderst durch das hohe Gras der Sloenstedi Savanne und genießt einen netten Spaziergang in der Natur als Auszeit von deinen Aufgaben. Als du die hügelige Landschaft durchstreifst, fällt dir eine Ansammlung von Gegenständen in der Ferne auf. Es ist ein Stapel aus Musikinstrumenten, Kunstzubehör, elektronischer Ausrüstung und mehr! Du wagst dich näher für einen besseren Blick.<br><br>“Hey, was glaubst du, was du da machst?“ ruft eine Stimme hinter einer Akazie hervor. Eine große und imposante Giraffe, die eine modische Sonnenbrille, eine Gitarre und eine ausgefallene Kamera um ihren langen Hals trägt, taucht auf. „Das ist alles meine Ausrüstung, sei vorsichtig und berühre nichts!“<br><br>Du bemerkst Staub auf vielen der Gegenstände. „Wow, du hast echt eine Menge Hobbies!“ sagst du. „Kannst du mir einige Kunstwerke zeigen oder ein Lied auf der Gitarre spielen?“<br><br>Die Giraffe zieht die Mundwinkel herunter, als sie all ihr Zubehör anschaut. „Ich habe so viel von diesem Zeug, aber ich weiß nicht, wo ich anfangen soll! Warum gibst du mir nicht ein bisschen von deiner Motivation, um mir die produktive Energie zu verleihen, die ich brauche, um endlich starten zu können!“",
|
||||
"questChameleonNotes": "Es ist ein schöner Tag in einer warmen, regnerischen Ecke der Aufgabenwälder. Du bist auf der Jagd nach Neuzugängen für deine Blattsammlung, als ein Ast vor dir ohne Vorwarnung seine Farbe ändert! Und dann bewegt er sich!<br><br>Rückwärts stolpernd realisierst du, dass dies überhaupt kein Ast ist, sondern ein großes Chamäleon! Jeder Teil seines Körpers wechselt andauernd seine Farbe, während seine Augen in unterschiedliche Richtungen zucken.<br><br>“Geht es dir gut?“ fragst du das Chamäleon.<br><br>“Ahhh, na ja,“ sagt es und wirkt ein wenig durcheinander. „Ich habe versucht, mich anzupassen… aber es ist so überwältigend… die Farben kommen und gehen ständig! Es ist schwer, sich auf nur eine zu konzentrieren….“<br><br>“Aha,“ sagst du, „Ich glaube, ich kann helfen. Wir schärfen deine Konzentration mit einer kleinen Herausforderung! Halte deine Farben bereit!“<br><br>“Die Wette gilt!“ erwidert das Chamäleon.",
|
||||
"questGiraffeBoss": "Gear-affe",
|
||||
"questGiraffeCompletion": "Nachdem du der Gear-affe mit ein bisschen grundlegender Organisation ihres Stapels geholfen hast, fühlt ihr euch beide energiegeladener und motivierter!<br><br>Sie nimmt ihre Gitarre und ein Heft mit Anfängerübungen und spielt ein paar Noten. \"Es fühlt sich gut an, einen Schritt in die richtige Richtung zu machen, selbst wenn es nur ein kleiner ist. Vielen Dank, dass du mir geholfen hast! Nimm diese hier, ich habe gehört, du hast einige Haustiere und diese Kameraden könnten eine nette Ergänzung sein!\"",
|
||||
"questCrabDropCrabEgg": "Kabbe (Ei)",
|
||||
"questCrabUnlockText": "Schaltet Krabbeneier zum Kauf auf dem Marktplatz frei."
|
||||
"questCrabUnlockText": "Schaltet Krabbeneier zum Kauf auf dem Marktplatz frei.",
|
||||
"questChameleonCompletion": "Nach ein paar lebhaften Drehungen durchlief das Chamäleon alle Farben des Regenbogens und traf perfekt alle Farben, die du verlangt hattest.<br><br>\"Wow,\" sagt es, \"zusammenzuarbeiten, und es zu einem Spiel zu machen, hat mir wirklich geholfen, mich zu konzentrieren! Bitte nimm diese als Belohnung, du hast sie verdient! Bring diesen kleinen Jungen bei, wie man in alle Regenbogenfarben wechselt, wenn sie schlüpfen.\"",
|
||||
"questCrabNotes": "Es ist ein warmer, sonniger Morgen, und Du genießt einen Besuch am Strand, um ein paar Bücher von Deiner Sommerleseliste zu lesen. Du schreckst auf, als du fast auf einen glänzenden Kristall in der Nähe eines flachen Lochs im Sand trittst.<br><br>„Ey, pass auf, wo du hingehst! Ich baue hier eine Wohnhöhle!“, sagt eine Stimme. Eine überraschend große Krabbe mit einem dekorativen Panzer buddelt sich vor Deinen Zehen aus dem Loch und schnappt mit ihrer Schere, während sie spricht.<br><br>„Hm, ist das eine Höhle?“, fragst Du und betrachtest die flache Vertiefung. Es sind Muscheln und Kristalle um sie herum angeordnet, aber es deutet nicht viel auf einen Rückzugsort hin.<br><br>Die Krabbe stottert. „Ey, das ist eine vorurteilsfreie Zone! Ich komme schon noch dazu, ich komme schon noch dazu... Ich bin gerade beim Dekorieren hängen geblieben. Manchmal muss eine Krabbe eben ein wenig Zeit vertrödeln“, sagt sie und rückt eine Schale zurecht.<br><br>„Warum hilfst Du nicht mit, wenn Du schon so großartige Vorstellungen davon hast, wie eine Höhle aussehen soll?“",
|
||||
"questCrabCompletion": "Du und die Krabbe schafft es gemeinsam, alles an der richtigen Stelle zu platzieren, damit ein feiner Sandbau entsteht. Die Krabbe kuschelt sich fröhlich hinein.<br><br>„Danke!“, sagt sie und macht es sich gemütlich. „Das ist eine Höhle, die nur für mich gemacht ist. Endlich kann ich all meine perfekt platzierten Dekorationen genießen. Hier, nimm diese kleinen Kerlchen als Zeichen meiner Wertschätzung. Das ist ein Angebot, das du nicht ablehnen kannst!“",
|
||||
"questCrabRageDescription": "Diese Leiste füllt sich, wenn du deine Tagesaufgaben nicht erledigst. Wenn sie voll ist, nimmt die Herumtrödelnde Krabbe einen Teil der MP deiner Party weg!",
|
||||
"questCrabRageEffect": "Die Herumtrödelnde Krabbe lenkt dich mit Dekorationen ab, verlangsamt deine Arbeit beim Graben und entzieht dir einen Teil deiner Magie. Die MP der Party sind reduziert!",
|
||||
"questRaccoonText": "Waschbär-Tycoon",
|
||||
"questRaccoonCompletion": "„Ich glaube, es gibt wirklich genug schöne Steine für uns beide“, sagst du, während du die letzten deiner Gegenstände einsammelst. „Hier sind ein paar, die du von dem haben kannst, was ich gesammelt habe, ich habe genug zum Teilen!“<br><br>„Oh, das ist aber nett von dir“, sagt der Waschbär. „Hier sind auch ein paar nette kleine Geschenke für dich!“",
|
||||
"questRaccoonBoss": "Gieriger Waschbär",
|
||||
"questRaccoonRageTitle": "Schmuck-Tsunami",
|
||||
"questRaccoonRageDescription": "Diese Leiste füllt sich, wenn du deine Tagesaufgaben nicht erledigst. Wenn sie voll ist, erhält der Waschbär-Tycoon einen Teil seiner Gesundheit zurück!",
|
||||
"questRaccoonRageEffect": "Der Gierige Waschbär nimmt einige von dir gerettete Gegenstände an sich und stopft sie in den Baumstamm zurück. Der Boss erhält 30% seiner Gesundheit zurück!",
|
||||
"questRaccoonDropRaccoonEgg": "Waschbär (Ei)",
|
||||
"questRaccoonUnlockText": "Schaltet Waschbären-Eier zum Kauf am Marktplatz frei.",
|
||||
"questRaccoonNotes": "Es ist ein warmer Herbsttag in Habitica und du machst einen langsamen Spaziergang entlang des Conquest Creek. Am Ufer siehst du ein paar hübsche Halbedelsteine, die sich perfekt für ein Projekt eignen, das du schon lange geplant hast.<br><br>Du fängst an, deine besten Funde in einem Haufen unter einem Baum zu sammeln. Seltsamerweise scheint der Haufen jedes Mal, wenn du zurückkommst, kleiner zu werden, nicht größer...<br><br>Da stimmt doch was nicht. Du blickst dich um, aber es fällt dir nichts Merkwürdiges auf. Gerade als du dich umdrehst, um zum Bach zurückzukehren, bemerkst du eine handähnliche Pfote, die aus einer Vertiefung im Baumstamm herausragt und dir einige deiner Steine entreißt!<br><br>„Hey!“, rufst du, “ich habe hart gearbeitet, um die Steine zu sammeln. Es ist nicht in Ordnung, sie zu nehmen, ohne zu fragen!“<br><br>Ein maskiertes Gesicht taucht aus dem Loch auf und grinst dich an. „Wer's findet, dem gehört's!“, sagt der Waschbär. Er schlüpft zurück in den Baum, die Säcke mit den Steinen in der Hand. Du springst ihm hinterher! Für diese Steine lohnt es sich zu kämpfen.",
|
||||
"questDogText": "Dreifache Hundeprüfung!",
|
||||
"questDogBoss": "Shiberus",
|
||||
"questDogRageTitle": "Dreifacher Spielzeugwurf",
|
||||
"questDogRageDescription": "Diese Leiste füllt sich, wenn du deine Tagesaufgaben nicht erledigst. Wenn sie voll ist, nimmt Shiberus einen Teil der MP deiner Party weg!",
|
||||
"questDogRageEffect": "Shiberus wirft mit Spielzeug nach dir und blockiert deine Zaubersprüche! Die MP der Party werden reduziert!",
|
||||
"questDogDropDogEgg": "Hund (Ei)",
|
||||
"questDogUnlockText": "Schaltet den Kauf von Hundeeiern auf dem Marktplatz frei.",
|
||||
"questDogNotes": "Du wurdest für eine Expedition ausgewählt, um die unterirdischen Höhlensysteme von Habitica zu kartieren! Forscher in Habit City vermuten, dass es in diesen Tiefen neue Werkzeuge für die Bewältigung von Aufgaben oder sogar unentdeckte Kreaturen geben könnte.<br><br>Während du felsige Tunnel in der Nähe der Ausläufer des Wandernden Gebirges erkundest, bemerkst du ein Leuchten, das von einem zerklüfteten Eingang vor dir ausgeht. Als du näher kommst, siehst du... Spielzeug? Plüschtiere und Gummibälle liegen auf dem Höhlenboden verstreut. Hörst du da ein Bellen?<br><br>Ein riesiger, dreiköpfiger Hund springt heraus und stürzt sich auf das Spielzeug, das du gerade aufheben wolltest! Du erstarrst und verlierst dabei fast deinen Arm! Aber... die Mäuler des Hundes scheinen zu sehr mit Spielzeug beschäftigt zu sein, um anzugreifen?<br><br>„Wuff!“, bellt eines der Hundemäuler und lässt einen zerrissenen Spielzeugwaschbären fallen. „Bist du hier, um mir beim Aufräumen zu helfen? Ich muss wirklich aufräumen, aber jedes Mal, wenn ich ein Spielzeug in die Hand nehme, spiele ich nur damit... Hier, denk schnell!!!“<br><br> Der Hund wirft dir einen Ball zu, und dann noch einen und noch einen. Diese zusätzlichen Köpfe machen das Ausweichen zu einem echten Training!",
|
||||
"questDogCompletion": "Nachdem du alle Spielzeuge eingesammelt hast, denen du (zum Glück) ausgewichen bist, gibst du Shiberus einen sanften Klaps auf seinen mittleren Kopf.<br><br>„Es ist schön, sich auf eine große Aufgabe zu freuen, aber es könnte hilfreich sein, mit einem Plan vorzugehen. Vielleicht solltest du das nächste Mal am Eingang anfangen und dich rückwärts vorarbeiten? Oder 30 Minuten am Stück arbeiten und dann eine kurze Spielpause einschieben.\"<br><br>„Das ist eine gute Idee“, meldet sich der linke Kopf des Hundes zu Wort. Der rechte Kopf legt ein paar Gegenstände in deine Nähe, darunter auch etwas, das aussieht wie Eier... „Ich habe ein paar Dinge gefunden, die dir gefallen könnten, während wir gespielt haben. Danke für deine Hilfe!“"
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"rebirthOrb": "Hat eine Sphäre der Wiedergeburt verwendet um noch einmal von vorne zu beginnen, nachdem Level <%= level %> erreicht wurde.",
|
||||
"rebirthOrb100": "Hat eine Sphäre der Wiedergeburt verwendet um noch einmal von vorne zu beginnen, nachdem Level 100 oder höher erreicht wurde.",
|
||||
"rebirthOrbNoLevel": "Hat eine Sphäre der Wiedergeburt verwendet um noch einmal von vorne zu beginnen.",
|
||||
"rebirthPop": "Beginne sofort von vorn mit einem Charakter auf Level 1, aber behalte Erfolge, Sammelgegenstände und Ausrüstung. Deine Aufgaben und ihre Verläufe bleiben erhalten, werden aber auf gelb zurückgesetzt. Deine Strähnen verfallen, außer für Aufgaben, die von aktiven Herausforderungen oder Gruppenplänen stammen. Gold, Erfahrung, Mana und alle Effekte von Fähigkeiten werden entfernt. All das wird sofort in Kraft treten. Für mehr Informationen, schau im Wiki auf der Seite <a href='https://habitica.fandom.com/de/wiki/Sphäre_der_Wiedergeburt' target='_blank'>Sphäre der Wiedergeburt</a> nach.",
|
||||
"rebirthPop": "Beginne sofort von vorn mit einem Charakter auf Level 1, aber behalte Erfolge, Sammelgegenstände und Ausrüstung. Deine Aufgaben und ihre Verläufe bleiben erhalten, werden aber auf gelb zurückgesetzt. Deine Strähnen verfallen, außer für Aufgaben, die von aktiven Herausforderungen oder Gruppenplänen stammen. Gold, Erfahrung, Mana und alle Effekte von Fähigkeiten werden entfernt. All das wird sofort in Kraft treten.",
|
||||
"rebirthName": "Sphäre der Wiedergeburt",
|
||||
"rebirthComplete": "Du wurdest wiedergeboren!",
|
||||
"nextFreeRebirth": "<strong><%= days %> Tage</strong> bis zur <strong>KOSTENLOSEN</strong> Sphäre der Wiedergeburt"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"settings": "Einstellungen",
|
||||
"language": "Sprache",
|
||||
"americanEnglishGovern": "Im Fall von Bedeutungsunterschieden gilt die englische Version.",
|
||||
"helpWithTranslation": "Möchtest Du bei der Übersetzung von Habitica helfen? Toll! Dann besuche doch die <a href=\"/groups/guild/7732f64c-33ee-4cce-873c-fc28f147a6f7\">Aspiring Linguists Guild</a>!",
|
||||
"helpWithTranslation": "Hast du Interesse, bei der Übersetzung von Habitica helfen? Toll! Dann besuche doch die <a href=\"/groups/guild/7732f64c-33ee-4cce-873c-fc28f147a6f7\">Aspiring Linguists Guild</a>!",
|
||||
"stickyHeader": "Kopfzeile anheften",
|
||||
"newTaskEdit": "Neue Aufgaben im Bearbeiten-Modus öffnen",
|
||||
"reverseChatOrder": "Zeige die Chat-Nachrichten in umgekehrter Reihenfolge",
|
||||
@@ -18,7 +18,7 @@
|
||||
"resetAccPop": "Starte neu, dabei werden alle Level, Gold, Ausrüstung, Verlauf und Aufgaben entfernt.",
|
||||
"deleteAccount": "Konto löschen",
|
||||
"deleteAccPop": "Kündige und entferne Dein Habitica-Konto.",
|
||||
"feedback": "Wenn Du uns Feedback geben möchtest, gib es bitte unten ein - wir freuen uns darauf zu erfahren, was Dir an Habitica gefällt - oder auch nicht gefällt! Und falls Du Schwierigkeiten mit Englisch hast? Kein Problem! Schreib' in der Sprache, die Dir liegt.",
|
||||
"feedback": "Wenn Du uns Feedback geben möchtest, gib es bitte unten ein - wir freuen uns darauf deine Meinung zu hören! Und falls Du Schwierigkeiten mit Englisch hast? Kein Problem! Schreib' in der Sprache, die Dir liegt.",
|
||||
"dataExport": "Daten exportieren",
|
||||
"saveData": "Hier sind ein paar Möglichkeiten, Deine Daten zu sichern.",
|
||||
"habitHistory": "Habitica-Verlauf",
|
||||
@@ -27,8 +27,8 @@
|
||||
"userData": "Benutzerdaten",
|
||||
"exportUserData": "Benutzerdaten exportieren:",
|
||||
"export": "Exportieren",
|
||||
"xml": "(XML)",
|
||||
"json": "(JSON)",
|
||||
"xml": "XML",
|
||||
"json": "JSON",
|
||||
"customDayStart": "Tageswechsel einstellen",
|
||||
"sureChangeCustomDayStartTime": "Bist Du sicher, dass Du Deinen individuellen Tageswechsel umstellen willst? Deine Tagesaufgaben werden das nächste Mal zurückgesetzt, wenn Du Habitica nach <%= time %> verwendest. Stelle sicher, dass Du bis dahin Deine Aufgaben erledigt hast!",
|
||||
"customDayStartHasChanged": "Dein persönlicher Tagesstart wurde geändert.",
|
||||
@@ -45,10 +45,10 @@
|
||||
"confirmPass": "Neues Passwort bestätigen",
|
||||
"newUsername": "Neuer Benutzername",
|
||||
"dangerZone": "Gefahrenzone",
|
||||
"resetText1": "WARNUNG! Es werden große Teile Deines Accounts zurückgesetzt. Wir raten dringend davon ab. Jedoch finden einige Spieler diese Funktion sinnvoll, um nach einem anfänglichen Testen der Seite neu beginnen zu können.",
|
||||
"resetText2": "Du verlierst alle Deine Level, Dein Gold und Deine Erfahrungspunkte. Alle Deine Aufgaben (außer Aufgaben aus Herausforderungen) werden permanent gelöscht, und Du verlierst alle ihre historischen Daten. Du verlierst Deine gesamte Ausrüstung außer Abonnement-Überraschungsgegenstände und gratis Erinnerungsgegenstände. Du wirst die Möglichkeit haben, alle gelöschten Gegenstände zurückzukaufen, inklusive allen Gegenständen limitierter Ausgabe (Du musst für klassenspezifische Ausrüstung der richtigen Klasse angehören, um sie zurückzukaufen). Du behältst Deine aktuelle Klasse, Deine Erfolge, und Deine Haus- und Reittiere. Möglicherweise möchtest Du lieber die Sphäre der Wiedergeburt nutzen, die eine weit sicherere Option darstellt und Deine Aufgaben und Ausrüstung beibehält.",
|
||||
"deleteLocalAccountText": "Bist Du sicher? Dies wird Dein Konto für immer löschen und es kann nicht wiederhergestellt werden! Wenn Du Habitica wieder verwenden möchtest, musst Du ein neues Konto registrieren. Gesparte oder verbrauchte Edelsteine werden nicht ersetzt. Wenn Du absolut sicher bist, dann tippe Dein Passwort in das Textfeld unten ein.",
|
||||
"deleteSocialAccountText": "Bist Du sicher? Dies wird Dein Konto für immer löschen und es kann nicht wiederhergestellt werden! Wenn Du Habitica wieder verwenden möchtest, musst Du ein neues Konto registrieren. Gesparte oder verbrauchte Edelsteine werden nicht ersetzt. Wenn Du absolut sicher bist, dann tippe \"<%= magicWord %>\" in das Textfeld unten ein.",
|
||||
"resetText1": "Sei vorsichtig! Es werden große Teile Deines Accounts zurückgesetzt. Wir raten dringend davon ab. Jedoch finden einige Spieler diese Funktion sinnvoll, um nach einem anfänglichen Testen der Seite neu beginnen zu können.",
|
||||
"resetText2": "Eine andere Möglichkeit ist die Verwendung einer <b>Sphäre der Wiedergeburt</b>, die alles andere zurücksetzt, während deine Aufgaben und Ausrüstung erhalten bleiben.",
|
||||
"deleteLocalAccountText": "<b>Bist Du sicher?</b> Dies wird Dein Konto für immer löschen und es kann nicht wiederhergestellt werden! Wenn Du Habitica wieder verwenden möchtest, musst Du ein neues Konto registrieren. Gesparte oder verbrauchte Edelsteine werden nicht ersetzt. Wenn Du absolut sicher bist, dann tippe Dein Passwort in das Textfeld unten ein.",
|
||||
"deleteSocialAccountText": "<b>Bist Du sicher?</b> Dies wird Dein Konto für immer löschen und es kann nicht wiederhergestellt werden! Wenn Du Habitica wieder verwenden möchtest, musst Du ein neues Konto registrieren. Gesparte oder verbrauchte Edelsteine werden nicht ersetzt. Wenn Du absolut sicher bist, dann tippe <b>\"<%= magicWord %>\"</b> in das Textfeld unten ein.",
|
||||
"API": "API",
|
||||
"APIv3": "API v3",
|
||||
"APIText": "Kopiere sie zur Anwendung in Applikationen von Drittanbietern. Sieh Dein API-Token aber als Passwort an und verbreite es nicht. Du wirst vielleicht gelegentlich nach Deiner Benutzer-ID gefragt, aber poste niemals Dein API-Token öffentlich wo es andere sehen können, auch nicht auf GitHub.",
|
||||
@@ -60,8 +60,8 @@
|
||||
"resetDo": "Ja, setzt mein Konto jetzt zurück!",
|
||||
"resetComplete": "Zurückgesetzt!",
|
||||
"fixValues": "Werte reparieren",
|
||||
"fixValuesText1": "Wenn Du Opfer eines Bugs geworden bist oder einen Fehler gemacht hast, der Deinen Charakter unfair beeinflusst hat (Schaden, den Du nicht hättest erleiden dürfen, Gold das Du nicht verdient hast, usw.), dann kannst Du das hier manuell korrigieren. Ja, das eröffnet die Möglichkeit zu cheaten: Verwende dieses Feature mit Bedacht, oder Du verdirbst Dir das Ausbilden Deiner Gewohnheiten!",
|
||||
"fixValuesText2": "Beachte, dass Du hier keine Strähnen einzelner Aufgaben wiederherstellen kannst. Um das zu tun, bearbeite eine Tagesaufgabe unter erweiterte Optionen. Dort wirst Du ein \"Strähne wiederherstellen\"-Feld finden.",
|
||||
"fixValuesText1": "Wenn Du etwas bemerkst, das Deinen Charakter unfair beeinflusst hat (Schaden, den Du nicht hättest erleiden dürfen, Gold das Du nicht verdient hast, usw.), dann kannst Du das hier manuell korrigieren. Ja, das eröffnet die Möglichkeit zu cheaten: Verwende dieses Feature mit Bedacht, oder Du verdirbst Dir das Ausbilden Deiner Gewohnheiten!",
|
||||
"fixValuesText2": "<b>Aufgepasst</b>: Um Strähnen einzelner Aufgaben wiederherzustellen, bearbeite die Aufgabe und verwende das \"Strähne wiederherstellen\"-Feld.",
|
||||
"fix21Streaks": "21-Tage-Strähnen",
|
||||
"discardChanges": "Änderungen verwerfen",
|
||||
"deleteDo": "Ja, löscht jetzt mein Konto!",
|
||||
@@ -86,26 +86,26 @@
|
||||
"giftedSubscriptionInfo": "<%= name %> hat Dir ein <%= months %>-monatiges Abonnement geschenkt",
|
||||
"giftedSubscriptionFull": "Hallo <%= username %>, <%= sender %> hat Dir <%= monthCount %> Monate Abonnement geschickt!",
|
||||
"invitedParty": "Du wurdest in eine Party eingeladen",
|
||||
"invitedGuild": "Du wurdest in eine Gilde eingeladen",
|
||||
"invitedGuild": "Du wurdest in eine Gruppe eingeladen",
|
||||
"importantAnnouncements": "Erinnerungen zur Anmeldung, um Aufgaben zu komplettieren und Preise zu erhalten",
|
||||
"weeklyRecaps": "Zusammenfassung Deiner Account-Aktivitäten in dieser Woche (Notiz: Ist zurzeit wegen Performance-Problemen deaktiviert. Wir hoffen, dass es bald wieder zurück ist und werden demnächst wieder E-Mails verschicken!)",
|
||||
"onboarding": "Hilfe, um Dein Habitica-Konto einzurichten",
|
||||
"majorUpdates": "Wichtige Ankündigungen",
|
||||
"questStarted": "Dein Quest hat begonnen",
|
||||
"invitedQuest": "Zu einem Quest eingeladen",
|
||||
"kickedGroup": "Aus der Gruppe rausgeworfen",
|
||||
"kickedGroup": "Aus der Gruppe entfernt",
|
||||
"remindersToLogin": "Erinnerungen, bei Habitica reinzuschauen",
|
||||
"unsubscribedSuccessfully": "Erfolgreich abgemeldet!",
|
||||
"unsubscribedTextUsers": "Du hast Dich erfolgreich von allen Habitica Emails abgemeldet. Du kannst die Emails, die Du erhalten möchtest, unter <a href=\"/user/settings/notifications\">Einstellungen>> Mitteilungen</a> freischalten (erfordert Anmeldung).",
|
||||
"unsubscribedTextOthers": "Du wirst keine weitere E-Mails von Habitica erhalten.",
|
||||
"unsubscribeAllEmails": "Häkchen setzen, um keine weiteren E-Mails zu erhalten",
|
||||
"unsubscribeAllEmailsText": "Indem ich hier ein Häkchen gesetzt habe, bestätige ich, dass ich verstanden habe, dass ich aus allen Habitica-E-Mail-Listen ausgetragen wurde. Habitica kann mir keine E-Mails mehr zu wichtigen Änderungen der Seite oder meines Accounts schicken.",
|
||||
"unsubscribeAllPush": "Abhaken um keine weiteren Push-Nachrichten zu erhalten",
|
||||
"unsubscribeAllEmails": "Keine weiteren E-Mails erhalten",
|
||||
"unsubscribeAllEmailsText": "Habitica wird dir keine E-Mails mehr zu wichtigen Änderungen der Seite oder deinem Account schicken können.",
|
||||
"unsubscribeAllPush": "Keine weiteren Push-Nachrichten erhalten",
|
||||
"correctlyUnsubscribedEmailType": "Erfolgreich \"<%= emailType %>\"-E-Mails abbestellt.",
|
||||
"subscriptionRateText": "Abonnement über <strong>$<%= price %> USD</strong> erneuert jede(n) <strong><%= months %> Monat(e)</strong>",
|
||||
"benefits": "Vorteile",
|
||||
"coupon": "Gutschein",
|
||||
"couponText": "Manchmal verteilen wir auf Events Promo-Codes für spezielle Ausrüstung (z. B. an unserem WonderCon-Stand)",
|
||||
"couponText": "Manchmal verteilen wir auf Events Promo-Codes für spezielle Ausrüstung.",
|
||||
"apply": "Anwenden",
|
||||
"promoCode": "Aktionscode",
|
||||
"promoCodeApplied": "Promo-Code aktiviert! Überprüfe Dein Inventar",
|
||||
@@ -117,7 +117,7 @@
|
||||
"generate": "Erstelle",
|
||||
"getCodes": "Codes erhalten",
|
||||
"webhooks": "WebHooks",
|
||||
"webhooksInfo": "Habitica stellt WebHooks zur Verfügung, damit bei bestimmten Aktionen in Deinem Konto Informationen an ein Skript auf einer anderen Website gesendet werden können. Du kannst diese Skripte hier anführen. Sei vorsichtig mit dieser Funktion, denn die Angabe einer falschen URL kann in Habitica zu Fehlern oder Verzögerungen führen. Weitere Informationen findest Du auf der <a target=\"_blank\" href=\"https://habitica.fandom.com/wiki/Webhooks\">WebHooks-Seite</a> des Wikis.",
|
||||
"webhooksInfo": "WebHooks bieten Entwicklern die Möglichkeit, Benachrichtigngen zu erhalten, wenn eine bestimmte Aktion durchgeführt wird, z. B. das Bewerten oder Aktualisieren einer Aufgabe oder das Senden einer Nachricht in einer Gruppe. Indem du einen WebHook erstellst, kannst du Änderungen in Habitica wahrnehmen und Anwendungen entwickeln, die auf diese Änderungen reagieren. <br><br> Weitere Informationen und Beispiele findest Du bei den <a target=\"_blank\" href=\"https://habitica.fandom.com/wiki/Webhooks\">API Docs</a>.",
|
||||
"enabled": "Aktiviert",
|
||||
"webhookURL": "WebHook-URL",
|
||||
"invalidUrl": "Ungültige URL",
|
||||
@@ -188,16 +188,16 @@
|
||||
"transaction_release_pets": "Haustiere freigelassen",
|
||||
"transaction_release_mounts": "Reittiere freigelassen",
|
||||
"addPasswordAuth": "Passwort hinzufügen",
|
||||
"nextHourglassDescription": "Abonnierende erhalten Mystische Sanduhren\ninnerhalb der ersten drei Tages des Monats.",
|
||||
"nextHourglassDescription": "Abonnierende erhalten eine Mystische Sanduhr, ein Mystisches Ausrüstungsset und Edelsteine, die innerhalb der ersten zwei Tage des Monats auf dem Markt wieder aufgefüllt werden.",
|
||||
"gemCap": "Edelsteinobergrenze",
|
||||
"nextHourglass": "Nächste Sanduhr",
|
||||
"nextHourglass": "Nächste Lieferung einer Mystischen Sanduhr",
|
||||
"adjustment": "Änderung",
|
||||
"dayStartAdjustment": "Änderung des Tageswechsel",
|
||||
"passwordSuccess": "Passwort erfolgreich geändert",
|
||||
"giftSubscriptionRateText": "<strong>$<%= price %> $(USD)</strong> für <strong><%= months %> Monate</strong>",
|
||||
"transaction_admin_update_balance": "<b>Admin</b> gegeben",
|
||||
"transaction_admin_update_hourglasses": "<b>Admin</b> aktualisiert",
|
||||
"transaction_create_bank_challenge": "Herausforderung mit Edelsteinen des Gildenbankkontos erstellt",
|
||||
"transaction_create_bank_challenge": "Mit Edelsteinen des Gildenbankkontos <b>erstellte Herausforderungen</b>",
|
||||
"passwordIssueLength": "Passwörter müssen zwischen 8 und 64 Zeichen lang sein.",
|
||||
"timestamp": "Zeitstempel",
|
||||
"amount": "Menge",
|
||||
@@ -257,5 +257,6 @@
|
||||
"connect": "Verbinden",
|
||||
"changeClassDisclaimer": "Bei Änderung deiner Klasse bekommst du alle deine vorhandenen Attributspunkte erstattet. Passe deine Attributspunkte im Attributwerte-Abschnitt deines Profils an, sobald du eine neue Klasse gewählt hast.",
|
||||
"APITokenDisclaimer": "<b>Dein API Token ist wie ein Passwort. Teile es nicht öffentlich.</b>Es kann sein, daß du gelegentlich nach deiner User ID gefragt wirst, aber poste niemals dein API Token, wo andere es sehen können, einschließlich Github.<br><br><b>Hinweis:</b> Wenn du ein neues API Token brauchst (z.B., wenn du es aus Versehen geteilt hast), schreib eine Email an <a href='mailto:admin@habitica.com' target='_blank'>admin@habitica.com</a> mit deiner User ID und deinem aktuellen Token. Wenn es dann zurückgesetzt ist, musst du alles wieder neu authorisieren, indem du dich auf der Website und der mobilen App abmeldest und das neue Token bei allen anderen Habitica Tools, die du nutzt, angibst.",
|
||||
"thirdPartyTools": "Drittanbieter Apps, Erweiterungen, und alle möglichen anderen Tools, die du mit deinem Account nutzen kannst, findest du im <a href='https://habitica.fandom.com/wiki/Extensions,_Add-Ons,_and_Customizations' target='_blank'>Habitica Wiki</a>."
|
||||
"thirdPartyTools": "Drittanbieter Apps, Erweiterungen, und alle möglichen anderen Tools, die du mit deinem Account nutzen kannst, findest du im <a href='https://habitica.fandom.com/wiki/Extensions,_Add-Ons,_and_Customizations' target='_blank'>Habitica Wiki</a>.",
|
||||
"transaction_subscription_bonus": "<b>Abonnement</b>-Bonus"
|
||||
}
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
"subscription": "Abonnement",
|
||||
"subscriptions": "Abonnements",
|
||||
"sendGems": "Verschicke Edelsteine",
|
||||
"buyGemsGold": "Kaufe Edelsteine mit Gold",
|
||||
"buyGemsGold": "Kostenlose Monatliche Edelsteine",
|
||||
"mustSubscribeToPurchaseGems": "Du musst ein Abonnement abschließen, um Edelsteine mit Gold kaufen zu können",
|
||||
"reachedGoldToGemCapQuantity": "Deine angeforderte Menge von <%= quantity %> übersteigt den Betrag, den Du diesen Monat noch kaufen darfst (<%= convCap %>). Der volle Betrag wird innerhalb der ersten drei Tage eines Monats verfügbar gemacht. Danke, dass Du ein Abonnement hast!",
|
||||
"mysteryItem": "Exklusive monatliche Gegenstände",
|
||||
"mysteryItemText": "Du wirst jeden Monat einen einzigartigen kosmetischen Gegenstand für Deinen Avatar erhalten! Zusätzlich gewähren Dir die Mysteriösen Zeitreisenden für je drei aufeinanderfolgende Abonnement-Monate Zugang zu historischen (oder futuristischen) kosmetischen Gegenständen.",
|
||||
"exclusiveJackalopePet": "Exklusives Haustier",
|
||||
"exclusiveJackalopePet": "Besonderes Haustier",
|
||||
"giftSubscription": "Willst Du jemand anderem die Vorteile eines Abonnements schenken?",
|
||||
"giftSubscriptionText4": "Danke, dass Du Habitica unterstützt!",
|
||||
"groupPlans": "Gruppen-Pläne",
|
||||
@@ -91,7 +91,7 @@
|
||||
"mysterySet301703": "Pfauen-Steampunk-Set",
|
||||
"mysterySet301704": "Fasanen-Steampunk-Set",
|
||||
"mysterySetwondercon": "Wondercon",
|
||||
"subUpdateCard": "Aktualisiere Deine Kreditkarte",
|
||||
"subUpdateCard": "Bearbeite Deine Kreditkarte",
|
||||
"subUpdateTitle": "Aktualisiere",
|
||||
"notEnoughHourglasses": "Du hast nicht genügend mystische Sanduhren.",
|
||||
"petsAlreadyOwned": "Bereits im Besitz dieses Haustieres.",
|
||||
@@ -120,14 +120,14 @@
|
||||
"gemBenefit2": "Hintergründe, die Deinen Avatar in die Welt von Habitica eintauchen lassen!",
|
||||
"gemBenefit3": "Aufregende Questlinien, welche Haustier-Eier zurücklassen.",
|
||||
"gemBenefit4": "Die Attributspunkte Deines Avatars zurücksetzen und seine Klasse ändern.",
|
||||
"subscriptionBenefit1": "Alexander der Händler wird Dir von nun an auf dem Marktplatz Edelsteine für 20 Goldmünzen das Stück verkaufen!",
|
||||
"subscriptionBenefit3": "Finde noch mehr Gegenstände in Habitica mit der verdoppelten Obergrenze für Beutefunde.",
|
||||
"subscriptionBenefit4": "Einzigartiger Verkleidungsgegenstand für Deinen Avatar jeden Monat.",
|
||||
"subscriptionBenefit5": "Erhalte das Königlich purpurfarbene Wolpertinger Haustier, indem Du ein Abonnement abschließt.",
|
||||
"subscriptionBenefit6": "Verdiene Dir Mystische Sanduhren, um im Laden der Mysteriösen Zeitreisenden Gegenstände zu erwerben!",
|
||||
"subscriptionBenefit1": "Erhalte nun bis zu 50 mit Gold kaufbare Edelsteine auf dem Marktplatz, um Quests, Individualisierungen, Haustiere und vieles mehr zu kaufen!",
|
||||
"subscriptionBenefit3": "Finde die doppelte Anzahl an Eiern, Schlüpfelixieren und Futter am Tag, um deine Haustiersammlung zu erweitern!",
|
||||
"subscriptionBenefit4": "Staffiere dich mit der neuesten exklusiven Ausrüstung aus. Abonniere jetzt, um <%= month %>’s <%= currentMysterySetName %> zu erhalten!",
|
||||
"subscriptionBenefit5": "Erhalte den exklusiven Königlich purpurfarbenen Wolpertinger, wenn Du heute ein Abonnement abschließt!",
|
||||
"subscriptionBenefit6": "Verpasse nie wieder einen Gegenstand mit einer Mystischen Sanduhr pro Monat, die du im Laden der Mysteriösen Zeitreisenden benutzen kannst!",
|
||||
"purchaseAll": "Set kaufen",
|
||||
"gemsRemaining": "Verbleibende Edelsteine",
|
||||
"notEnoughGemsToBuy": "Du kannst die gewünschte Anzahl Edelsteine nicht kaufen",
|
||||
"gemsRemaining": "verbleibende",
|
||||
"notEnoughGemsToBuy": "Keine weiteren Edelsteine zum Kauf in diesem Monat erhältlich. Mehr werden innerhalb der ersten 3 Tage jedes Monats verfügbar sein.",
|
||||
"mysterySet201903": "Ei-nzigartiges Set",
|
||||
"mysterySet201902": "Geheimnisvolles Verliebten-Set",
|
||||
"confirmCancelSub": "Bist Du sicher, dass Du Dein Abonnement kündigen willst? Du verlierst alle Vorteile des Abonnements.",
|
||||
@@ -147,12 +147,12 @@
|
||||
"backgroundAlreadyOwned": "Hintergrund bereits im Besitz.",
|
||||
"mysticHourglassNeededNoSub": "Dieser Gegenstand erfordert eine Mystische Sanduhr. Du erhältst Mystische Sanduhren durch Abschluss eines Habitica-Abonnements.",
|
||||
"mysterySet202002": "Stilvolles Schätzchen-Set",
|
||||
"cancelYourSubscription": "Abonnement aufheben?",
|
||||
"subscriptionInactiveDate": "Deine Abonnementvorteile werden ab dem <strong><%= date %></strong> deaktiviert",
|
||||
"cancelYourSubscription": "Möchtest Du Dein Abonnement beenden?",
|
||||
"subscriptionInactiveDate": "Deine Abonnementvorteile werden ab dem <br><strong><%= date %></strong> deaktiviert",
|
||||
"subscriptionCanceled": "Dein Abonnement ist aufgehoben",
|
||||
"youAreSubscribed": "Du hast Habitica abonniert",
|
||||
"monthlyMysteryItems": "Monatliche Überraschungsgegenstände",
|
||||
"subscribersReceiveBenefits": "Abonnenten erhalten diese nützlichen Vorteile!",
|
||||
"monthlyMysteryItems": "Limitierte Monatliche Ausrüstungs-Sets",
|
||||
"subscribersReceiveBenefits": "Bleibe mit noch mehr Belohnungen motiviert, wenn Du abonnierst",
|
||||
"giftASubscription": "Schenke ein Abonnement",
|
||||
"cancelSubAlternatives": "Solltest Du technische Probleme haben oder Habitica bei Dir nicht richtig funktionieren, bitte <a href='mailto:admin@habitica.com'>kontaktiere uns</a>. Wir möchten Dir helfen, Habitica optimal zu nutzen.",
|
||||
"readyToResubscribe": "Bereit, erneut zu abonnieren?",
|
||||
@@ -170,7 +170,7 @@
|
||||
"usuallyGems": "Normalerweise <%= originalGems %>",
|
||||
"supportHabitica": "Unterstütze Habitica",
|
||||
"cancelSubInfoApple": "Bitte folge der <a href=\"https://support.apple.com/de-de/HT202039\">offiziellen Anleitung von Apple</a>, um Dein Abonnement zu kündigen oder um das Kündigungsdatum zu sehen, wenn Du das Abonnement bereits gekündigt hast. Diese Ansicht kann Dir nicht anzeigen, ob Dein Abonnement beendet wurde.",
|
||||
"cancelSubInfoGoogle": "Bitte gehe zum Abschnitt \"Account\" > \"Abonnements\" im Google Play Store, um Dein Abonnement zu kündigen oder um das Kündigungsdatum zu sehen, wenn Du das Abonnement bereits gekündigt hast. Diese Ansicht kann Dir nicht anzeigen, ob Dein Abonnement beendet wurde.",
|
||||
"cancelSubInfoGoogle": "Um Dein Abonnement zu kündigen oder um das Kündigungsdatum zu sehen, wenn Du das Abonnement bereits gekündigt hast, gehe zum <a href='https://play.google.com/store/account/subscriptions'>Google Play Store</a>. Alle verbleibenden Monate an Abonnement-Credits werden Deinem Enddatum nach der Kündigung hinzugefügt.",
|
||||
"organization": "Organisation",
|
||||
"mysterySet202010": "Verführerisches Fledermaus-Set",
|
||||
"dropCapExplanation": "Morgen, wenn Deine Tagesaufgaben zurückgesetzt werden, wird es auch wieder Beute zu finden geben. Bis dahin machst Du aber auch weiterhin Questfortschritte und verdienst Goldstücke und Erfahrung, wenn Du Aufgaben abschließt.",
|
||||
@@ -235,5 +235,29 @@
|
||||
"mysterySet202407": "Liebenswertes Axolotl Set",
|
||||
"mysterySet202408": "Arkanes Aegis Set",
|
||||
"mysterySet202409": "Heliotrop Magier Set",
|
||||
"mysterySet202410": "Candy Corn Fuchs Set"
|
||||
"mysterySet202410": "Candy Corn Fuchs Set",
|
||||
"subscribeTo": "Abonniere",
|
||||
"monthlyMysticHourglass": "Monatliche Mystische Sanduhr",
|
||||
"recurringMonthly": "Monatlich wiederkehrend",
|
||||
"recurringNMonthly": "Alle <%= length %> Monate wiederkehrend",
|
||||
"unlockNGems": "Schalte <strong><%= count %> Edelsteine</strong> pro Monat im Markt frei",
|
||||
"maxGemCap": "Starte automatisch mit der maximalen <strong>Edelsteinobergrenze</strong>",
|
||||
"monthlyGemsLabel": "Monatliche Edelsteine",
|
||||
"popular": "Beliebt",
|
||||
"immediate12Hourglasses": "Erhalte <strong>12 Mystische Sanduhren</strong> unmittelbar nach deinem ersten 12-Monats-Abonnement!",
|
||||
"subscribe": "Abonniere",
|
||||
"selectPayment": "Wähle Deine Bezahlmethode",
|
||||
"giftSubscriptionLeadText": "Wähle unten das Abonnement aus, das du verschenken willst! Dieser Kauf erneuert sich nicht automatisch.",
|
||||
"oneMonthGift": "Für 1 Monat",
|
||||
"nMonthsGift": "Für <%= months %> Monate",
|
||||
"unlockNGemsGift": "Sie schalten <strong><%= count %> Edelsteine</strong> pro Monat im Markt frei",
|
||||
"earn2GemsGift": "Sie verdienen <strong>+2 Edelsteine</strong> für jeden Monat, in dem sie abonniert haben",
|
||||
"maxGemCapGift": "Sie werden die maximale <strong>Edelsteinobergrenze</strong> haben",
|
||||
"mysterySet202412": "Zuckerstangen-Waldkaninchen-Set",
|
||||
"resubscribeToPickUp": "Abonniere erneut, um dort weiterzumachen, wo Du aufgehört hast!",
|
||||
"subscriptionChangeAnnouncement": "<strong>Abonnementvorteile und die Art und Weise, wie sie ausgeschüttet werden, ändert sich am 19. November. </strong> <%= linkStart %>Klicke hier</a>, um mehr über diese Änderung zu lesen.",
|
||||
"earn2Gems": "Verdiene <strong>+2 Edelsteine</strong> für jeden Monat, in dem du abonniert hast",
|
||||
"subscribeAgainContinueHourglasses": "Erneuere Dein Abonnement, um weiterhin Mystische Sanduhren zu erhalten",
|
||||
"mysterySet202411": "Borstenkämpfer Set",
|
||||
"mysterySet202501": "Frostbinder-Set"
|
||||
}
|
||||
|
||||
@@ -1007,6 +1007,10 @@
|
||||
"backgroundFirstSnowForestText": "First Snow in the Forest",
|
||||
"backgroundFirstSnowForestNotes": "Step into the First Snow in the Forest.",
|
||||
|
||||
"backgrounds012025": "SET 128: Released January 2025",
|
||||
"backgroundWinterLandscapeWithCabinText": "Winter Landscape with Cabin",
|
||||
"backgroundWinterLandscapeWithCabinNotes": "Stay cozy in a Winter Landscape with a Cabin.",
|
||||
|
||||
"timeTravelBackgrounds": "Steampunk Backgrounds",
|
||||
"backgroundAirshipText": "Airship",
|
||||
"backgroundAirshipNotes": "Become a sky sailor on board your very own Airship.",
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
"webFaqAnswer40": "Gems are Habitica’s in-app paid currency used to purchase Equipment, Avatar Customizations, Backgrounds, and more! Gems can be purchased in bundles or with Gold if you’re a Habitica subscriber. You can also win Gems by being selected as the winner of a Challenge.",
|
||||
|
||||
"faqQuestion41": "What are Mystic Hourglasses, and how do I get them?",
|
||||
"webFaqAnswer41": "Mystic Hourglasses are Habitica’s exclusive Subscriber currency used in the Time Travelers Shop! Hourglasses are delivered on a set schedule based on your subscription plan.\n\nHourglass delivery schedule:\n * 1-Month subscribers get 1 Hourglass at the start of the month after the 3rd consecutive payment.\n * 3-Month subscribers get 1 Hourglass immediately after subscribing, then 1 more Hourglass at the start of the month after each renewal.\n * 6-Month subscribers get 2 Hourglasses immediately after subscribing, then 2 more Hourglasses at the start of the month after each renewal.\n * 12-Month subscribers get 4 Hourglasses immediately after subscribing, then 4 more Hourglasses at the start of the month after each renewal.",
|
||||
"webFaqAnswer41": "Mystic Hourglasses are Habitica’s exclusive Subscriber currency used in the Time Travelers Shop. Subscribers receive a Mystic Hourglass at the start of each month they have subscription benefits, along with a bunch of other perks. Be sure to check out our subscription options if you’re interested in the special Backgrounds, Pets, Quests, and Equipment offered in the Time Travelers Shop!",
|
||||
|
||||
"faqQuestion42": "What can I do to increase accountability?",
|
||||
"webFaqAnswer42": "One of the best ways to motivate yourself and hold yourself accountable for accomplishing your tasks is to join a Party! Partying with other Habitica players is a great way to take on Quests to receive Pets and Equipment, receive buffs from Party members’ Skills, and boost your motivation.\n\nAnother way to increase accountability is to join a Challenge. Challenges automatically add tasks related to a specific goal to your lists! They also add an element of competition against other Habitica players that may give you a motivation boost as you strive for the Gem prize. There are official Challenges created by the Habitica Team as well Challenges made by other players.",
|
||||
|
||||
@@ -1679,6 +1679,8 @@
|
||||
"armorArmoireStormKnightArmorNotes": "In this armor, you are nearly invincible. Your enemies will never see the storm’s end. Increases Perception by <%= per %>. Enchanted Armoire: Storm Knight Set (Item 2 of 3)",
|
||||
"armorArmoireFestiveHelperOverallsText": "Festive Helper Overalls",
|
||||
"armorArmoireFestiveHelperOverallsNotes": "Durable and comfortable, these overalls are great for working, playing, and assisting others. Plus, it has pockets! Increases Constitution by <%= con %>. Enchanted Armoire: Festive Helper Set (Item 2 of 2)",
|
||||
"armorArmoireSnowyFluffTrimmedCoatText": "Snowy Fluff-Trimmed Coat",
|
||||
"armorArmoireSnowyFluffTrimmedCoatNotes": "As the first flakes fall around you, this coat will not only keep you toasty but also help you blend in perfectly with your snowy surroundings. Glide along the ice in style! Increases Strength and Intelligence by <%= attrs %> each. Enchanted Armoire: Snowy Trapper Hat Set (Item 2 of 2).",
|
||||
|
||||
"headgear": "helm",
|
||||
"headgearCapitalized": "Headgear",
|
||||
@@ -2368,6 +2370,8 @@
|
||||
"headMystery202411Notes": "This helm is quite intimidating to your tasks when you dive in headfirst! Confers no benefit. November 2024 Subscriber Item.",
|
||||
"headMystery202412Text": "Candy Cane Cottontail Hood",
|
||||
"headMystery202412Notes": "Warm and cozy, just like a cup of minty hot cocoa on a winter night! Confers no benefit. December 2024 Subscriber Item.",
|
||||
"headMystery202501Text": "Frostbinder’s Hat",
|
||||
"headMystery202501Notes": "This sparkling hat generates a light and festive flurry around you at all times. Confers no benefit. January 2025 Subscriber Item.",
|
||||
|
||||
"headMystery301404Text": "Fancy Top Hat",
|
||||
"headMystery301404Notes": "A fancy top hat for the finest of gentlefolk! January 3015 Subscriber Item. Confers no benefit.",
|
||||
@@ -2574,6 +2578,8 @@
|
||||
"headArmoireStormKnightHelmNotes": "Harness lightning through these antlers as you storm the castle. Increases Constitution by <%= con %>. Enchanted Armoire: Storm Knight Set (Item 1 of 3)",
|
||||
"headArmoireFestiveHelperHatText": "Festive Helper Hat",
|
||||
"headArmoireFestiveHelperHatNotes": "Holiday tip #27: have a helper hat handy. This one is big enough to keep an emergency toy underneath! Increases Intelligence by <%= int %>. Enchanted Armoire: Festive Helper Set (Item 1 of 2)",
|
||||
"headArmoireSnowyTrapperHatText": "Snowy Trapper Hat",
|
||||
"headArmoireSnowyTrapperHatNotes": "Blue, frostbitten ears will be a thing of the past. Embrace cozy warmth in style! Increases Constitution and Perception by <%= attrs %> each. Enchanted Armoire: Snowy Trapper Hat Set (Item 1 of 2).",
|
||||
|
||||
"offhand": "off-hand item",
|
||||
"offHandCapitalized": "Off-Hand Item",
|
||||
@@ -2887,6 +2893,8 @@
|
||||
"shieldMystery202408Notes": "Magic lights will illuminate the inside of your bubble hideout, or anywhere else you need a little light! Confers no benefit. August 2024 Subscriber Item.",
|
||||
"shieldMystery202409Text": "Heliotrope Magus Staff",
|
||||
"shieldMystery202409Notes": "The glowing ruby on this staff draws its power from the late summer sun. Confers no benefit. September 2024 Subscriber Item.",
|
||||
"shieldMystery202501Text": "Frostbinder's Staff",
|
||||
"shieldMystery202501Notes": "Decorate any outdoor scenery with a diamond coat of shimmering frost. Confers no benefit. January 2025 Subscriber Item.",
|
||||
|
||||
"shieldMystery301405Text": "Clock Shield",
|
||||
"shieldMystery301405Notes": "Time is on your side with this towering clock shield! Confers no benefit. June 3015 Subscriber Item.",
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
"user": "User",
|
||||
"market": "Market",
|
||||
"newSubscriberItem": "You have new <span class=\"notification-bold-blue\">Mystery Items</span>",
|
||||
"subscriberItemText": "Each month, subscribers will receive a mystery item. It becomes available at the beginning of the month. See the wiki's 'Mystery Item' page for more information.",
|
||||
"subscriberItemText": "Subscribers receive a new mystery gear set at the beginning of each month!",
|
||||
"all": "All",
|
||||
"none": "None",
|
||||
"more": "<%= count %> more",
|
||||
@@ -207,7 +207,8 @@
|
||||
"dismissAll": "Dismiss All",
|
||||
"messages": "Messages",
|
||||
"emptyMessagesLine1": "You don't have any messages",
|
||||
"emptyMessagesLine2": "You can send a new message to a user by visiting their profile and clicking the \"Message\" button.",
|
||||
"emptyMessagesLine2": "Send a message to start a conversation with your Party members or another Habitica player",
|
||||
"newMessage": "New Message",
|
||||
"userSentMessage": "<span class=\"notification-bold\"><%- user %></span> sent you a message",
|
||||
"letsgo": "Let's Go!",
|
||||
"selected": "Selected",
|
||||
@@ -238,5 +239,7 @@
|
||||
"submitQuestion": "Submit Question",
|
||||
"whyReportingPlayer": "Why are you reporting this player?",
|
||||
"whyReportingPlayerPlaceholder": "Reason for report",
|
||||
"playerReportModalBody": "You should only report a player who violates the <%= firstLinkStart %>Community Guidelines<%= linkEnd %> and/or <%= secondLinkStart %>Terms of Service<%= linkEnd %>. Submitting a false report is a violation of Habitica’s Community Guidelines."
|
||||
"playerReportModalBody": "You should only report a player who violates the <%= firstLinkStart %>Community Guidelines<%= linkEnd %> and/or <%= secondLinkStart %>Terms of Service<%= linkEnd %>. Submitting a false report is a violation of Habitica’s Community Guidelines.",
|
||||
"targetUserNotExist": "Target User: '<%= userName %>' does not exist.",
|
||||
"rememberToBeKind": "Please remember to be kind, respectful, and follow the <a href='/static/community-guidelines' target='_blank'>Community Guidelines</a>."
|
||||
}
|
||||
|
||||
@@ -114,9 +114,7 @@
|
||||
"whyReportingPostPlaceholder": "Reason for report",
|
||||
"optional": "Optional",
|
||||
"needsTextPlaceholder": "Type your message here.",
|
||||
"copyMessageAsToDo": "Copy message as To Do",
|
||||
"copyAsTodo": "Copy as To Do",
|
||||
"messageAddedAsToDo": "Message copied as To Do.",
|
||||
"messageCopiedToClipboard": "Message copied to clipboard.",
|
||||
"leaderOnlyChallenges": "Only group leader can create challenges",
|
||||
"sendGift": "Send a Gift",
|
||||
"selectGift": "Select Gift",
|
||||
@@ -288,7 +286,7 @@
|
||||
"guildSummaryPlaceholder": "Write a short explanation of your Group. What is the main purpose of the Group and what will its members do?",
|
||||
"groupDescription": "Description",
|
||||
"guildDescriptionPlaceholder": "Use this section to go into more detail about everything that members should know about your Group. Useful tips, helpful links, and encouraging statements all go here!",
|
||||
"markdownFormattingHelp": "[Markdown formatting help](https://habitica.fandom.com/wiki/Markdown_Cheat_Sheet)",
|
||||
"markdownFormattingHelp": "[Markdown formatting help](https://github.com/HabitRPG/habitica/wiki/Markdown-in-Habitica)",
|
||||
"partyDescriptionPlaceholder": "This is our Party's description. It describes what we do in this Party. If you want to learn more about what we do in this Party, read the description. Party on.",
|
||||
"guildGemCostInfo": "A Gem cost promotes high quality Guilds and is transferred into your Guild's bank.",
|
||||
"noGuildsTitle": "You aren't a member of any Guilds.",
|
||||
|
||||
@@ -51,8 +51,6 @@
|
||||
"messageNotAbleToBuyInBulk": "This item cannot be purchased in quantities above 1.",
|
||||
"notificationsRequired": "Notification ids are required.",
|
||||
"unallocatedStatsPoints": "You have <span class=\"notification-bold-blue\"><%= points %> unallocated Stat Points</span>",
|
||||
"beginningOfConversation": "This is the beginning of your conversation with <%= userName %>.",
|
||||
"beginningOfConversationReminder": "Remember to be kind, respectful, and follow the Community Guidelines!",
|
||||
"messageDeletedUser": "Sorry, this user has deleted their account.",
|
||||
"messageMissingDisplayName": "Missing display name.",
|
||||
"reportedMessage": "You have reported this message to moderators.",
|
||||
|
||||
@@ -96,6 +96,7 @@
|
||||
"paymentYouReceived": "You received:",
|
||||
"paymentYouSentGems": "You sent <strong><%- name %></strong>:",
|
||||
"paymentYouSentSubscription": "You sent <strong><%- name %></strong><br> a <%= months %> month(s) Habitica subscription.",
|
||||
"paymentYouSentSubscriptionG1G1": "You sent <strong><%- name %></strong><br> a <%= months %> month(s) Habitica subscription, and the same subscription was applied to your account for our Gift One Get One promotion!",
|
||||
"paymentSubBilling": "Your subscription will be billed <strong>$<%= amount %></strong> every <strong><%= months %> months</strong>.",
|
||||
"groupsPaymentSubBilling": "Your next billing date is <strong><%= renewalDate %></strong>.",
|
||||
"paymentSubBillingWithMethod": "Your subscription will be billed<br><strong>$<%= amount %>.00 USD</strong> every <strong><%= months %> months</strong> via <strong><%= paymentMethod %></strong>",
|
||||
|
||||
@@ -90,8 +90,8 @@
|
||||
"mountsReleased": "Mounts released",
|
||||
"welcomeStable": "Welcome to your Pets and Mounts!",
|
||||
"welcomeStableText": "Welcome to the stable! I’m Matt, the beastmaster. Every time you complete a task, you'll have a random chance at receiving an Egg or a Hatching Potion to hatch Pets. When you hatch a Pet, it will appear here! Click a Pet's image to add it to your Avatar. Feed them with the Pet Food you find and they'll grow into hardy Mounts.",
|
||||
"petLikeToEat": "What does my pet like to eat?",
|
||||
"petLikeToEatText": "Pets will grow no matter what you feed them, but they'll grow faster if you feed them the one Pet Food that they like best. Experiment to find out the pattern, or see the answers here: <br/> <a href=\"https://habitica.fandom.com/wiki/Food_Preferences\" target=\"_blank\">https://habitica.fandom.com/wiki/Food_Preferences</a>",
|
||||
"petLikeToEat": "What does my Pet like to eat?",
|
||||
"petLikeToEatText": "Pets will grow no matter what you feed them, but they'll grow faster if you feed them the one Pet Food that they like best. Experiment to find out the pattern, or see the answers here: <br/> <a href=\"/static/faq#pet-foods\" target=\"_blank\">https://habitica.com/static/faq#pet-foods</a>",
|
||||
"filterByStandard": "Standard",
|
||||
"filterByMagicPotion": "Magic Potion",
|
||||
"filterByQuest": "Quest",
|
||||
|
||||
@@ -169,6 +169,7 @@
|
||||
"mysterySet202410": "Candy Corn Fox Set",
|
||||
"mysterySet202411": "Bristled Brawler Set",
|
||||
"mysterySet202412": "Candy Cane Cottontail Set",
|
||||
"mysterySet202501": "Frostbinder Set",
|
||||
"mysterySet301404": "Steampunk Standard Set",
|
||||
"mysterySet301405": "Steampunk Accessories Set",
|
||||
"mysterySet301703": "Peacock Steampunk Set",
|
||||
@@ -240,9 +241,9 @@
|
||||
"switchToRecurring": "Switch to a recurring subscription?",
|
||||
"recurringMonthly": "Recurring every month",
|
||||
"recurringNMonthly": "Recurring every <%= length %> months",
|
||||
"unlockNGems": "Unlock <strong><%= count %> Gems</strong> per month instantly",
|
||||
"unlockNGems": "Unlock <strong><%= count %> Gems</strong> per month in the Market",
|
||||
"earn2Gems": "Earn <strong>+2 Gems</strong> every month you're subscribed",
|
||||
"maxGemCap": "Max <strong>Gem Cap</strong>",
|
||||
"maxGemCap": "Instantly start at the max <strong>Gem Cap</strong>",
|
||||
"monthlyGemsLabel": "Monthly Gems",
|
||||
"continueGiftSubBenefits": "Want to continue your benefits? You can start a new subscription before your gifted one runs out to keep your benefits active.",
|
||||
"subscriptionCreditConversion": "Starting a new subscription will convert any remaining months to credit that will be used after the recurring subscription is canceled.",
|
||||
@@ -255,7 +256,7 @@
|
||||
"giftSubscriptionLeadText": "Choose the subscription you'd like to gift below! This purchase will not automatically renew.",
|
||||
"oneMonthGift": "For 1 month",
|
||||
"nMonthsGift": "For <%= months %> months",
|
||||
"unlockNGemsGift": "They'll unlock <strong><%= count %> Gems</strong> per month instantly",
|
||||
"unlockNGemsGift": "They'll unlock <strong><%= count %> Gems</strong> per month in the Market",
|
||||
"earn2GemsGift": "They'll earn <strong>+2 Gems</strong> every month they're subscribed",
|
||||
"maxGemCapGift": "They'll have the max <strong>Gem Cap</strong>",
|
||||
"subscribeAgainContinueHourglasses": "Subscribe again to continue receiving Mystic Hourglasses"
|
||||
|
||||
@@ -885,5 +885,11 @@
|
||||
"backgrounds102024": "CONJUNTO125: Publicado en Octubre 2024",
|
||||
"backgrounds112024": "CONJUNTO 126: Publicado en Noviembre 2024",
|
||||
"backgroundCastleHallWithHearthText": "Salón de Castillo con Chimenea",
|
||||
"backgroundCastleHallWithHearthNotes": "Deléitate de la calidez de este salón del castillo con chimenea."
|
||||
"backgroundCastleHallWithHearthNotes": "Deléitate de la calidez de este salón del castillo con chimenea.",
|
||||
"backgrounds122024": "CONJUNTO 127: Publicado en Diciembre 2024",
|
||||
"backgroundFirstSnowForestText": "Primeras Nieves en el Bosque",
|
||||
"backgroundFirstSnowForestNotes": "Da un aterrador primer paso en las Primeras Nieves en el Bosque.",
|
||||
"backgroundWinterLandscapeWithCabinNotes": "Mantente cómodo en un paisaje invernal con una cabaña.",
|
||||
"backgrounds012025": "CONJUNTO 128: Publicado en enero de 2025",
|
||||
"backgroundWinterLandscapeWithCabinText": "Paisaje invernal con cabaña"
|
||||
}
|
||||
|
||||
@@ -391,5 +391,6 @@
|
||||
"questEggRaccoonAdjective": "uno voraz",
|
||||
"questEggDogText": "Cachorro",
|
||||
"questEggDogMountText": "Perro",
|
||||
"questEggDogAdjective": "un amistoso"
|
||||
"questEggDogAdjective": "un amistoso",
|
||||
"hatchingPotionGingerbread": "Pan de Jengibre"
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
"webFaqAnswer45": "¡Uno de los miembros de tu Equipo ha usado contigo un objeto de transformación de la Tienda de Temporada! Tu Avatar volverá a la normalidad al día siguiente. Si quieres deshacer la transformación antes, puedes comprar un antídoto (Sal, Arena, Antipétalo o Poción opaca) en el menú Recompensas.",
|
||||
"faqQuestion47": "¿Puedo ver información de mi progreso con las tareas y hábitos?",
|
||||
"webFaqAnswer47": "Por ahora Habitica no dispone de una representación visual de la información de tareas a lo largo del tiempo. Sin embargo, en la página web de Habitica podrás exportar esta información desde la opción \"Site Data\" en el menú de Ajustes.",
|
||||
"webFaqAnswer41": "Los Relojes de Arena Místicos son una moneda de Habitica exclusiva para los Suscriptores y se usan en la Tienda de los Viajeros del Tiempo. Recibirás los relojes de arena en los momentos establecidos a partir de tu plan de Suscripción.\n\nPlazos de entrega de Relojes de Arena:\n * Los suscriptores de 1 Mes reciben 1 Reloj de Arena al inicio del mes después de su tercer pago consecutivo.\n * Los suscriptores de 3 Meses reciben 1 Reloj de Arena inmediatamente al suscribirse, y otro al inicio del mes tras cada renovación. \n * Los suscriptores de 6 Meses reciben 2 Relojes de Arena inmediatamente al suscribirse, y otros dos al inicio del mes tras cada renovación. \n * Los suscriptores de 12 Meses reciben 4 Relojes de Arena inmediatamente al suscribirse, y otros cuatro al inicio del mes tras cada renovación.",
|
||||
"webFaqAnswer41": "Los Relojes de Arena Místicos son un recurso de Habitica exclusivo para los Suscriptores y se gastan en la Tienda de los Viajeros del Tiempo. Los suscriptores reciben un Reloj de arena Místico al inicio de cada uno de los meses en los que obtengan beneficios derivados de la misma, aparte de un buen montón de otras ventajas. ¡Asegúrate de comprobar todas las opciones de tu suscripción si estás interesado en Paisajes especiales, Mascotas, Misiones y equipamiento procedente de la Tienda de los Viajeros del Tiempo!",
|
||||
"webFaqAnswer43": "Para comenzar una Misión, necesitarás formar parte de un Equipo. Los Equipos pueden ser aventuras en solitario si te embarcas en Misiones solo, pero también puedes invitar a otros jugadores de Habitica para enfrentarte a las Misiones con más rapidez.\n\nEn tu Equipo, pulsa el botón \"Emprender Misión\" y elige uno de los Pergaminos de Misión de tu inventario . ¡Completa tus tareas con normalidad para progresar en tu Misión! Podrás causar daños a un monstruo, si estás embarcado en una Misión de Jefe, o encontrar objetos, si estás en una Misión de recolección. Todo el progreso pendiente se aplica el día siguiente.\n\n¡Cuando hayas producido el daño suficiente o hayas recolectado todos los objetos, la Misión se completará y recibirás tus recompensas!",
|
||||
"faqQuestion46": "¿Cómo reporto un error?",
|
||||
"webFaqAnswer46": "Si piensas que has encontrado un error, ¡haznos saber!\n\nPara reportar un error en las aplicaciones móviles:\n *Desde el menú, selecciona Apoyo y luego \"Obtén Ayuda\" y desplázate hacia abajo a \"Reportar un Error\"\n\nPara reportar un error desde la página web:\n * Desde el menú de Ayuda, selecciona \"Reportar un error\"",
|
||||
|
||||
@@ -1347,7 +1347,7 @@
|
||||
"shieldSpecialWinter2016WarriorText": "Escudo de Trineo",
|
||||
"shieldSpecialWinter2016WarriorNotes": "Utiliza este trineo para bloquear ataques, ¡o deslízate con él hacia la batalla! Aumenta la Constitución en <%= con %>. Equipamiento de edición limitada de invierno 2015-2016.",
|
||||
"shieldSpecialWinter2016HealerText": "Regalo de Hada",
|
||||
"shieldSpecialWinter2016HealerNotes": "¡¡¡¡¡¡¡¡¡Ábrelo ábrelo ábrelo ábrelo ábrelo ábrelo!!!!!!!!! Aumenta la Constitución en <%= con %>. Equipamiento de edición limitada de invierno 2015-2016.",
|
||||
"shieldSpecialWinter2016HealerNotes": "¡¡¡¡¡¡¡¡¡Ábrelo, ábrelo, ábrelo, ábrelo, ábrelo, ábrelo!!!!!!!!! Aumenta la Constitución en <%= con %>. Equipamiento de edición limitada de invierno 2015-2016.",
|
||||
"shieldSpecialSpring2016WarriorText": "Rueda de Queso",
|
||||
"shieldSpecialSpring2016WarriorNotes": "Te enfrentaste a diabólicas trampas para conseguir esta comida que aumenta la defensa. Aumenta la Constitución en <%= con %>. Equipamiento de edición limitada de primavera 2016.",
|
||||
"shieldSpecialSpring2016HealerText": "Escudo Floral",
|
||||
@@ -2696,7 +2696,7 @@
|
||||
"armorSpecialSummer2023RogueText": "Envoltura de pez Guppy (Poecilia reticulata)",
|
||||
"armorSpecialSummer2023RogueNotes": "¡Hasta arriba! ¡Vale, baja lento! ¡No! Demasiado lento... Aumenta la percepcion en <%= per %>. Equipamiento Edición Limitada Verano 2023.",
|
||||
"armorSpecialSummer2023WarriorText": "Armadura de Carpa Dorada",
|
||||
"armorSpecialSpring2023WarriorNotes": "Ese zumbido que escuchas, no, no es una abeja, son tus alas de colibrí aleteando más rápido de lo que alcanza tu imaginación. Aumenta la Constitución en <%= con %>. Equipamiento Edición Limitada Primavera 2023.",
|
||||
"armorSpecialSpring2023WarriorNotes": "Ese zumbido que oyes son tus alas moviéndose más rápido de lo que crees. Aumenta la Constitución en <%= con %>. Equipamiento Edición Limitada Primavera 2023.",
|
||||
"armorSpecialSpring2023MageText": "Traje Piedra Lunar",
|
||||
"armorSpecialSpring2023MageNotes": "Este soberbio traje primaveral amplifica la magia de una pequeña piedra lunar. Aumenta la Inteligencia en <%= int %>. Equipamiento Edición Limitada Primavera 2023.",
|
||||
"armorSpecialSpring2023HealerText": "Vestido Hoja de Lirio",
|
||||
@@ -3209,5 +3209,49 @@
|
||||
"headMystery202411Text": "Yelmo Erizado",
|
||||
"headMystery202411Notes": "¡Este yelmo resulta bastante intimidante para tus tareas cuando te lanzas hacia ellas de cabeza! No otorga ningún beneficio. Artículo de Suscriptor Noviembre 2024.",
|
||||
"headArmoireStormKnightHelmNotes": "En pleno asedio a un castillo utiliza las antenas de este yelmo para llamar el rayo de la tormenta y embestir las murallas exteriores. Aumenta la Constitución en <%= con %>. Armario Encantado: Conjunto Caballero Llamatormentas (Artículo 1 de 3)",
|
||||
"bodyMystery202411Text": "Hombreras Erizadas"
|
||||
"bodyMystery202411Text": "Hombreras Erizadas",
|
||||
"weaponSpecialWinter2025WarriorText": "Hacha de Guerrero Alce",
|
||||
"weaponSpecialWinter2025WarriorNotes": "¡Por Crom! ¡Una poderosa hacha digna de un poderoso alce! ¡Vas a ser literalmente imparable! Aumenta la Fuerza en <%= str %>. Equipamiento de edición limitada Invierno 2024-2025.",
|
||||
"weaponSpecialWinter2025RogueText": "Ráfaga de Copos de Nieve",
|
||||
"weaponSpecialWinter2025HealerText": "Varita Estrella",
|
||||
"weaponSpecialWinter2025HealerNotes": "¡Lo que necesitas ahora para convertirte en el mejor es más luces y una estrella brillante! ¡Serás simbólicamente imparable! Aumenta la Inteligencia en <%= int %>. Equipamiento de edición limitada Invierno 2024-2025.",
|
||||
"weaponSpecialWinter2025MageText": "Despliegue de Aurora Boreal",
|
||||
"armorSpecialWinter2025RogueText": "Disfraz Muñeco de Nieve",
|
||||
"armorSpecialWinter2025HealerText": "Ropa compuesta de Tiras de Luces",
|
||||
"armorSpecialWinter2025HealerNotes": "En una mazmorra te ilumina y te abre el camino a través de las tareas. Sólo ten cuidado: si se apaga una bombilla, se apagan todas. Y te lo digo yo, no te gustaría estar a oscuras en uno de esos pozos. Aumenta la Constitución en <%= con %>. Equipamiento de edición limitada Invierno 2024-2025.",
|
||||
"armorSpecialWinter2025MageText": "Capa de la Aurora",
|
||||
"armorSpecialWinter2025MageNotes": "La maravilla, la fantasía, el encanto y el esplendor llenarán tus hechizos que requieran un baile al usar esta capa. Aumenta la Inteligencia en <%= int %>. Equipamiento de edición limitada Invierno 2024-2025.",
|
||||
"armorMystery202412Text": "Abrigo Cola Algodonada de Bastón de Caramelo",
|
||||
"armorMystery202412Notes": "Un look extremadamente divertido y suavemente esponjoso para mantenerte abrigado en un día de invierno. No otorga ningún beneficio. Artículo de Suscriptor Diciembre 2024.",
|
||||
"armorArmoireFestiveHelperOverallsText": "Mono de Ayudante Festivo",
|
||||
"armorArmoireFestiveHelperOverallsNotes": "Feo, aunque resistente y cómodo, con este mono vas a dar la campanada cuando estés trabajando, jugando y ayudando a otros. Además por si faltaba algo, ¡tiene bolsillos! Aumenta la Constitución en <%= con %>. Armario Encantado: Conjunto de Ayudante Festivo (Artículo 2 de 2)",
|
||||
"headSpecialWinter2025WarriorText": "Casco de Guerrero Alce",
|
||||
"headSpecialWinter2025WarriorNotes": "Gracias Crom ahora sí que soy un verdadero alce. Llevaré este casco con honor mientras infrinjo a mi enemigo una aplastante derrota. Aumenta la Fuerza en <%= str %>. Equipamiento de edición limitada Invierno 2024-2025.",
|
||||
"headSpecialWinter2025RogueText": "Máscara Muñeco de Nieve",
|
||||
"headSpecialWinter2025RogueNotes": "No sabrías decir pero puede que haya algún encantamiento de nigromante implantado en este sombrero por qué transforma tu carne en la de un muñeco de nieve. El reto va a ser ahora conseguir que ese conejo que ves aparecer por allí no te ampute la apetecible nariz-zanahoria. Aumenta la percepcion en <%= per %>. Equipamiento de edición limitada Invierno 2024-2025.",
|
||||
"headSpecialWinter2025HealerText": "Tira de Luces Enmarañada",
|
||||
"headSpecialWinter2025HealerNotes": "Vale, no pierdas el tiempo tratando de desenredar esta maraña de luces, mejor póntela como sombrero ganarás tiempo. Aumenta la Inteligencia en <%= int %>. Equipamiento de edición limitada Invierno 2024-2025.",
|
||||
"headSpecialWinter2025MageText": "Sobrero Aurora Boreal",
|
||||
"headSpecialWinter2025MageNotes": "Me lo cuentan y no me lo creo, este sombrero te transforma literalmente en la Aurora boreal. Aumenta la percepcion en <%= per %>. Equipamiento de edición limitada Invierno 2024-2025.",
|
||||
"armorSpecialWinter2025WarriorText": "Armadura de Guerreo Alce",
|
||||
"armorSpecialWinter2025WarriorNotes": "Crom va a sentirse muy complacido cuando tus enemigos aterrorizados huyan dejándote un pasillo triunfal al ver que llevas puesta esta armadura. Aumenta la Constitución en <%= con %>. Equipamiento de edición limitada Invierno 2024-2025.",
|
||||
"weaponSpecialWinter2025RogueNotes": "¡Golpea y deslumbra esas tareas difíciles hasta someterlas! ¡Serás literalmente imparable! Aumenta la fuerza en <%= str %>. Equipamiento de edición limitada Invierno 2024-2025.",
|
||||
"weaponSpecialWinter2025MageNotes": "¡Este asombroso y colorido despliegue proporciona el telón de fondo perfecto! ¡Serás simbólicamente imparable! Aumenta la inteligencia en <%= int %> y la percepción en <%= per %>. Equipamiento de edición limitada Invierno 2024-2025.",
|
||||
"armorSpecialWinter2025RogueNotes": "Aunque pareces estar cubierto de nieve fría, cuando usas este disfraz estás calentito y muy feliz con la ropa interior térmica. Tenía razón tu madre. Aumenta la Percepción en <%= per %>. Equipamiento de edición limitada Invierno 2024-2025.",
|
||||
"headMystery202412Text": "Capucha Cola Algodonada de Bastón de Caramelo",
|
||||
"headMystery202412Notes": "Cálido y acogedor, ¡como una taza de chocolate caliente con menta en una noche de invierno! No otorga ningún beneficio. Artículo de Suscriptor Diciembre 2024.",
|
||||
"headArmoireFestiveHelperHatText": "Sombrero de Ayudante Festivo",
|
||||
"headArmoireFestiveHelperHatNotes": "Consejo vacacional gratis #27: ten en todo momento un sombreo de ayudante a mano. ¡Si es tan grande como este quizás puedas esconder algún juguete para no aburrirte debajo! Aumenta la Inteligencia en <%= int %>. Armario Encantado: Conjunto Ayudante Festivo (Artículo 1 de 2)",
|
||||
"shieldSpecialWinter2025WarriorText": "Escudo de Guerreo Alce",
|
||||
"shieldSpecialWinter2025WarriorNotes": "Crom ha sido muy generoso contigo, te ha concedido este escudo tan robusto como un alce para que evites distracciones. Aumenta la Constitución en <%= con %>. Equipamiento de edición limitada Invierno 2024-2025.",
|
||||
"shieldSpecialWinter2025HealerText": "El Regalo Perfecto",
|
||||
"shieldSpecialWinter2025HealerNotes": "El regalo perfecto te está esperando a que lo abras. ¿Que clase de brujería contendrá? Aumenta la Constitución en <%= con %>. Equipamiento de edición limitada Invierno 2024-2025.",
|
||||
"armorArmoireSnowyFluffTrimmedCoatNotes": "Cuando los primeros copos de nieve caigan a tu alrededor, este abrigo no solo te mantendrá calentito, sino que también te ayudará a mimetizarte perfectamente con el entorno nevado. ¡Deslízate sobre el hielo con estilo! Aumenta la fuerza y la inteligencia en <%= attrs %> cada una. Armario encantado: conjunto de sombrero de trampero nevado (artículo 2 de 2).",
|
||||
"armorArmoireSnowyFluffTrimmedCoatText": "Chaqueta de plumas con capucha",
|
||||
"headMystery202501Text": "Sombrero de Vinculaescarcha Pálido",
|
||||
"headMystery202501Notes": "Este sombrero brillante genera un ambiente festivo y luminoso a tu alrededor en todo momento. No aporta ningún beneficio. Artículo para suscriptores de enero de 2025.",
|
||||
"headArmoireSnowyTrapperHatText": "Sombrero de trampero nevado",
|
||||
"headArmoireSnowyTrapperHatNotes": "Las orejas azules y congeladas serán cosa del pasado. ¡Disfruta de una calidez acogedora con estilo! Aumenta la Constitución y la Percepción en <%= attrs %> cada una. Armario encantado: conjunto de sombrero de trampero nevado (objeto 1 de 2).",
|
||||
"shieldMystery202501Text": "Bastón de Vinculaescarcha Pálido",
|
||||
"shieldMystery202501Notes": "Decora cualquier escenario al aire libre con una capa de diamante de escarcha brillante. No aporta ningún beneficio. Artículo para suscriptores de enero de 2025."
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user