Merge branch 'develop' into party-chat-translations

This commit is contained in:
Mateus Etto
2018-05-19 10:21:54 +09:00
425 changed files with 4415 additions and 4153 deletions

View File

@@ -1,7 +1,7 @@
[//]: # (Note: See http://habitica.wikia.com/wiki/Using_Your_Local_Install_to_Modify_Habitica%27s_Website_and_API for more info) [//]: # (Note: See http://habitica.wikia.com/wiki/Using_Your_Local_Install_to_Modify_Habitica%27s_Website_and_API for more info)
[//]: # (Put Issue # or URL here, if applicable. This will automatically close the issue if your PR is merged in) [//]: # (Put Issue # here, if applicable. This will automatically close the issue if your PR is merged in)
Fixes put_issue_url_here Fixes put_#_and_issue_numer_here
### Changes ### Changes
[//]: # (Describe the changes that were made in detail here. Include pictures if necessary) [//]: # (Describe the changes that were made in detail here. Include pictures if necessary)

View File

@@ -17,7 +17,7 @@ RUN npm install -g gulp-cli mocha
# Clone Habitica repo and install dependencies # Clone Habitica repo and install dependencies
RUN mkdir -p /usr/src/habitrpg RUN mkdir -p /usr/src/habitrpg
WORKDIR /usr/src/habitrpg WORKDIR /usr/src/habitrpg
RUN git clone --branch v4.41.0 https://github.com/HabitRPG/habitica.git /usr/src/habitrpg RUN git clone --branch v4.42.4 https://github.com/HabitRPG/habitica.git /usr/src/habitrpg
RUN npm install RUN npm install
RUN gulp build:prod --force RUN gulp build:prod --force

View File

@@ -167,7 +167,7 @@ gulp.task('test:content:safe', gulp.series('test:prepare:build', (cb) => {
gulp.task('test:api-v3:unit', (done) => { gulp.task('test:api-v3:unit', (done) => {
let runner = exec( let runner = exec(
testBin('node_modules/.bin/istanbul cover --dir coverage/api-v3-unit --report lcovonly node_modules/mocha/bin/_mocha -- test/api/v3/unit --recursive --require ./test/helpers/start-server'), testBin('node_modules/.bin/istanbul cover --dir coverage/api-v3-unit node_modules/mocha/bin/_mocha -- test/api/v3/unit --recursive --require ./test/helpers/start-server'),
(err) => { (err) => {
if (err) { if (err) {
process.exit(1); process.exit(1);

794
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,16 +1,16 @@
{ {
"name": "habitica", "name": "habitica",
"description": "A habit tracker app which treats your goals like a Role Playing Game.", "description": "A habit tracker app which treats your goals like a Role Playing Game.",
"version": "4.41.5", "version": "4.42.6",
"main": "./website/server/index.js", "main": "./website/server/index.js",
"dependencies": { "dependencies": {
"@slack/client": "^3.8.1", "@slack/client": "^3.8.1",
"accepts": "^1.3.5", "accepts": "^1.3.5",
"amazon-payments": "^0.2.6", "amazon-payments": "^0.2.7",
"amplitude": "^3.5.0", "amplitude": "^3.5.0",
"apidoc": "^0.17.5", "apidoc": "^0.17.5",
"autoprefixer": "^8.4.1", "autoprefixer": "^8.5.0",
"aws-sdk": "^2.230.1", "aws-sdk": "^2.239.1",
"axios": "^0.18.0", "axios": "^0.18.0",
"axios-progress-bar": "^1.2.0", "axios-progress-bar": "^1.2.0",
"babel-core": "^6.26.3", "babel-core": "^6.26.3",
@@ -26,20 +26,20 @@
"babel-register": "^6.6.0", "babel-register": "^6.6.0",
"babel-runtime": "^6.11.6", "babel-runtime": "^6.11.6",
"bcrypt": "^2.0.0", "bcrypt": "^2.0.0",
"body-parser": "^1.15.0", "body-parser": "^1.18.3",
"bootstrap": "^4.1.1", "bootstrap": "^4.1.1",
"bootstrap-vue": "^2.0.0-rc.9", "bootstrap-vue": "^2.0.0-rc.9",
"compression": "^1.7.2", "compression": "^1.7.2",
"cookie-session": "^1.2.0", "cookie-session": "^1.2.0",
"coupon-code": "^0.4.5", "coupon-code": "^0.4.5",
"cross-env": "^5.1.4", "cross-env": "^5.1.5",
"css-loader": "^0.28.11", "css-loader": "^0.28.11",
"csv-stringify": "^2.1.0", "csv-stringify": "^2.1.0",
"cwait": "^1.1.1", "cwait": "^1.1.1",
"domain-middleware": "~0.1.0", "domain-middleware": "~0.1.0",
"express": "^4.16.3", "express": "^4.16.3",
"express-basic-auth": "^1.1.5", "express-basic-auth": "^1.1.5",
"express-validator": "^5.1.2", "express-validator": "^5.2.0",
"extract-text-webpack-plugin": "^3.0.2", "extract-text-webpack-plugin": "^3.0.2",
"glob": "^7.1.2", "glob": "^7.1.2",
"got": "^8.3.1", "got": "^8.3.1",
@@ -52,7 +52,7 @@
"hellojs": "^1.15.1", "hellojs": "^1.15.1",
"html-webpack-plugin": "^3.2.0", "html-webpack-plugin": "^3.2.0",
"image-size": "^0.6.2", "image-size": "^0.6.2",
"in-app-purchase": "^1.9.3", "in-app-purchase": "^1.9.4",
"intro.js": "^2.9.3", "intro.js": "^2.9.3",
"jquery": ">=3.0.0", "jquery": ">=3.0.0",
"js2xmlparser": "^3.0.0", "js2xmlparser": "^3.0.0",
@@ -61,7 +61,7 @@
"method-override": "^2.3.5", "method-override": "^2.3.5",
"moment": "^2.22.1", "moment": "^2.22.1",
"moment-recur": "^1.0.7", "moment-recur": "^1.0.7",
"mongoose": "^5.0.17", "mongoose": "^5.1.1",
"morgan": "^1.7.0", "morgan": "^1.7.0",
"nconf": "^0.10.0", "nconf": "^0.10.0",
"node-gcm": "^0.14.4", "node-gcm": "^0.14.4",
@@ -82,8 +82,8 @@
"pusher": "^1.3.0", "pusher": "^1.3.0",
"rimraf": "^2.4.3", "rimraf": "^2.4.3",
"sass-loader": "^7.0.0", "sass-loader": "^7.0.0",
"shelljs": "^0.8.1", "shelljs": "^0.8.2",
"stripe": "^5.8.0", "stripe": "^5.9.0",
"superagent": "^3.8.3", "superagent": "^3.8.3",
"svg-inline-loader": "^0.8.0", "svg-inline-loader": "^0.8.0",
"svg-url-loader": "^2.3.2", "svg-url-loader": "^2.3.2",
@@ -103,7 +103,7 @@
"vue-template-compiler": "^2.5.16", "vue-template-compiler": "^2.5.16",
"vuedraggable": "^2.15.0", "vuedraggable": "^2.15.0",
"vuejs-datepicker": "git://github.com/habitrpg/vuejs-datepicker.git#5d237615463a84a23dd6f3f77c6ab577d68593ec", "vuejs-datepicker": "git://github.com/habitrpg/vuejs-datepicker.git#5d237615463a84a23dd6f3f77c6ab577d68593ec",
"webpack": "^3.11.0", "webpack": "^3.12.0",
"webpack-merge": "^4.0.0", "webpack-merge": "^4.0.0",
"winston": "^2.4.2", "winston": "^2.4.2",
"winston-loggly-bulk": "^2.0.2", "winston-loggly-bulk": "^2.0.2",
@@ -139,15 +139,15 @@
"apidoc": "gulp apidoc" "apidoc": "gulp apidoc"
}, },
"devDependencies": { "devDependencies": {
"@vue/test-utils": "^1.0.0-beta.15", "@vue/test-utils": "^1.0.0-beta.16",
"babel-plugin-istanbul": "^4.1.6", "babel-plugin-istanbul": "^4.1.6",
"babel-plugin-syntax-object-rest-spread": "^6.13.0", "babel-plugin-syntax-object-rest-spread": "^6.13.0",
"chai": "^4.1.2", "chai": "^4.1.2",
"chai-as-promised": "^7.1.1", "chai-as-promised": "^7.1.1",
"chalk": "^2.4.1", "chalk": "^2.4.1",
"chromedriver": "^2.38.2", "chromedriver": "^2.38.3",
"connect-history-api-fallback": "^1.1.0", "connect-history-api-fallback": "^1.1.0",
"coveralls": "^3.0.0", "coveralls": "^3.0.1",
"cross-spawn": "^6.0.5", "cross-spawn": "^6.0.5",
"eslint": "^4.19.1", "eslint": "^4.19.1",
"eslint-config-habitrpg": "^4.0.0", "eslint-config-habitrpg": "^4.0.0",
@@ -163,7 +163,7 @@
"karma-babel-preprocessor": "^7.0.0", "karma-babel-preprocessor": "^7.0.0",
"karma-chai-plugins": "^0.9.0", "karma-chai-plugins": "^0.9.0",
"karma-chrome-launcher": "^2.2.0", "karma-chrome-launcher": "^2.2.0",
"karma-coverage": "^1.1.1", "karma-coverage": "^1.1.2",
"karma-mocha": "^1.3.0", "karma-mocha": "^1.3.0",
"karma-mocha-reporter": "^2.2.5", "karma-mocha-reporter": "^2.2.5",
"karma-sinon-chai": "^1.3.4", "karma-sinon-chai": "^1.3.4",
@@ -173,17 +173,17 @@
"karma-webpack": "^3.0.0", "karma-webpack": "^3.0.0",
"lcov-result-merger": "^2.0.0", "lcov-result-merger": "^2.0.0",
"mocha": "^5.1.1", "mocha": "^5.1.1",
"monk": "^6.0.5", "monk": "^6.0.6",
"nightwatch": "^0.9.21", "nightwatch": "^0.9.21",
"puppeteer": "^1.3.0", "puppeteer": "^1.4.0",
"require-again": "^2.0.0", "require-again": "^2.0.0",
"selenium-server": "^3.11.0", "selenium-server": "^3.12.0",
"sinon": "^4.5.0", "sinon": "^4.5.0",
"sinon-chai": "^3.0.0", "sinon-chai": "^3.0.0",
"sinon-stub-promise": "^4.0.0", "sinon-stub-promise": "^4.0.0",
"webpack-bundle-analyzer": "^2.11.1", "webpack-bundle-analyzer": "^2.12.0",
"webpack-dev-middleware": "^2.0.5", "webpack-dev-middleware": "^2.0.5",
"webpack-hot-middleware": "^2.22.1" "webpack-hot-middleware": "^2.22.2"
}, },
"optionalDependencies": { "optionalDependencies": {
"memwatch-next": "^0.3.0", "memwatch-next": "^0.3.0",

View File

@@ -123,7 +123,8 @@ describe('GET /challenges/:challengeId/members', () => {
}); });
}); });
it('supports using req.query.lastId to get more members', async () => { it('supports using req.query.lastId to get more members', async function () {
this.timeout(30000); // @TODO: times out after 8 seconds
let group = await generateGroup(user, {type: 'party', name: generateUUID()}); let group = await generateGroup(user, {type: 'party', name: generateUUID()});
let challenge = await generateChallenge(user, group); let challenge = await generateChallenge(user, group);

View File

@@ -142,7 +142,8 @@ describe('GET /groups/:groupId/members', () => {
}); });
}); });
it('supports using req.query.lastId to get more members', async () => { it('supports using req.query.lastId to get more members', async function () {
this.timeout(30000); // @TODO: times out after 8 seconds
let leader = await generateUser({balance: 4}); let leader = await generateUser({balance: 4});
let group = await generateGroup(leader, {type: 'guild', privacy: 'public', name: generateUUID()}); let group = await generateGroup(leader, {type: 'guild', privacy: 'public', name: generateUUID()});

View File

@@ -632,6 +632,15 @@ describe('payments/index', () => {
expect(user.sendMessage).to.be.calledWith(recipient, { receiverMsg: msg, senderMsg: msg }); expect(user.sendMessage).to.be.calledWith(recipient, { receiverMsg: msg, senderMsg: msg });
}); });
it('sends a message from purchaser to recipient wtih custom message', async () => {
data.gift.message = 'giftmessage';
await api.buyGems(data);
const msg = `\`Hello recipient, sender has sent you 4 gems!\` ${data.gift.message}`;
expect(user.sendMessage).to.be.calledWith(recipient, { receiverMsg: msg, senderMsg: msg });
});
it('sends a push notification if user did not gift to self', async () => { it('sends a push notification if user did not gift to self', async () => {
await api.buyGems(data); await api.buyGems(data);
expect(notifications.sendNotification).to.be.calledOnce; expect(notifications.sendNotification).to.be.calledOnce;

View File

@@ -0,0 +1,65 @@
import {shallow} from '@vue/test-utils';
import CategoryTags from 'client/components/categories/categoryTags.vue';
describe('Category Tags', () => {
let wrapper;
beforeEach(function () {
wrapper = shallow(CategoryTags, {
propsData: {
categories: [],
},
slots: {
default: '<p>This is a slot.</p>',
},
mocks: {
$t: (string) => string,
},
});
});
it('displays a category', () => {
wrapper.setProps({
categories: [
{
name: 'test',
},
],
});
expect(wrapper.contains('.category-label')).to.eq(true);
expect(wrapper.find('.category-label').text()).to.eq('test');
});
it('displays a habitica official in purple', () => {
wrapper.setProps({
categories: [
{
name: 'habitica_official',
},
],
});
expect(wrapper.contains('.category-label-purple')).to.eq(true);
expect(wrapper.find('.category-label').text()).to.eq('habitica_official');
});
it('displays owner label', () => {
wrapper.setProps({
owner: true,
});
expect(wrapper.contains('.category-label-blue')).to.eq(true);
expect(wrapper.find('.category-label').text()).to.eq('owned');
});
it('displays member label', () => {
wrapper.setProps({
member: true,
});
expect(wrapper.contains('.category-label-green')).to.eq(true);
expect(wrapper.find('.category-label').text()).to.eq('joined');
});
it('displays additional content at the end', () => {
expect(wrapper.find('p').text()).to.eq('This is a slot.');
});
});

View File

@@ -0,0 +1,54 @@
import {shallow} from '@vue/test-utils';
import SidebarSection from 'client/components/sidebarSection.vue';
describe('Sidebar Section', () => {
let wrapper;
beforeEach(function () {
wrapper = shallow(SidebarSection, {
propsData: {
title: 'Hello World',
},
slots: {
default: '<p>This is a test.</p>',
},
});
});
it('displays title', () => {
expect(wrapper.find('h3').text()).to.eq('Hello World');
});
it('displays contents', () => {
expect(wrapper.find('.section-body').find('p').text()).to.eq('This is a test.');
});
it('displays tooltip icon', () => {
expect(wrapper.contains('.section-info')).to.eq(false);
wrapper.setProps({tooltip: 'This is a test'});
expect(wrapper.contains('.section-info')).to.eq(true);
});
it('hides contents', () => {
expect(wrapper.find('.section-body').element.style.display).to.not.eq('none');
wrapper.find('.section-toggle').trigger('click');
expect(wrapper.find('.section-body').element.style.display).to.eq('none');
wrapper.find('.section-toggle').trigger('click');
expect(wrapper.find('.section-body').element.style.display).to.not.eq('none');
});
it('can hide contents by default', () => {
wrapper = shallow(SidebarSection, {
propsData: {
title: 'Hello World',
show: false,
},
slots: {
default: '<p>This is a test.</p>',
},
});
expect(wrapper.find('.section-body').element.style.display).to.eq('none');
});
});

View File

@@ -122,11 +122,10 @@ describe('common.fns.updateStats', () => {
updateStats(user, { updateStats(user, {
exp: 3000, exp: 3000,
}); });
expect(user.addNotification).to.be.calledTwice; // once is for drops enabled expect(user._tmp.leveledUp).to.eql([{
expect(user.addNotification).to.be.calledWith('LEVELED_UP', {
initialLvl, initialLvl,
newLvl: user.stats.lvl, newLvl: user.stats.lvl,
}); }]);
}); });
it('add user notification when rebirth is enabled', () => { it('add user notification when rebirth is enabled', () => {

View File

@@ -1,4 +1,4 @@
import buySpecialSpell from '../../../../website/common/script/ops/buy/buySpecialSpell'; import {BuySpellOperation} from '../../../../website/common/script/ops/buy/buySpell';
import { import {
BadRequest, BadRequest,
NotFound, NotFound,
@@ -15,6 +15,11 @@ describe('shared.ops.buySpecialSpell', () => {
let user; let user;
let analytics = {track () {}}; let analytics = {track () {}};
function buySpecialSpell (_user, _req, _analytics) {
const buyOp = new BuySpellOperation(_user, _req, _analytics);
return buyOp.purchase();
}
beforeEach(() => { beforeEach(() => {
user = generateUser(); user = generateUser();
sinon.stub(analytics, 'track'); sinon.stub(analytics, 'track');

View File

@@ -44,8 +44,6 @@ div
router-view router-view
app-footer app-footer
audio#sound(autoplay, ref="sound") audio#sound(autoplay, ref="sound")
source#oggSource(type="audio/ogg", :src="sound.oggSource")
source#mp3Source(type="audio/mp3", :src="sound.mp3Source")
</template> </template>
<style lang='scss' scoped> <style lang='scss' scoped>
@@ -118,7 +116,7 @@ div
/* Push progress bar above modals */ /* Push progress bar above modals */
#nprogress .bar { #nprogress .bar {
z-index: 1043 !important; /* Must stay above nav bar */ z-index: 1090 !important; /* Must stay above nav bar */
} }
.restingInn { .restingInn {
@@ -127,7 +125,7 @@ div
} }
#app-header { #app-header {
margin-top: 96px !important; margin-top: 40px !important;
} }
} }
@@ -220,10 +218,9 @@ export default {
selectedItemToBuy: null, selectedItemToBuy: null,
selectedSpellToBuy: null, selectedSpellToBuy: null,
sound: { audioSource: null,
oggSource: '', audioSuffix: null,
mp3Source: '',
},
loading: true, loading: true,
currentTipNumber: 0, currentTipNumber: 0,
bannerHidden: false, bannerHidden: false,
@@ -259,11 +256,22 @@ export default {
return; return;
} }
let file = `/static/audio/${theme}/${sound}`; let file = `/static/audio/${theme}/${sound}`;
this.sound = {
oggSource: `${file}.ogg`, if (this.audioSuffix === null) {
mp3Source: `${file}.mp3`, this.audioSource = document.createElement('source');
}; if (this.$refs.sound.canPlayType('audio/ogg')) {
this.audioSuffix = '.ogg';
this.audioSource.type = 'audio/ogg';
} else {
this.audioSuffix = '.mp3';
this.audioSource.type = 'audio/mp3';
}
this.audioSource.src = file + this.audioSuffix;
this.$refs.sound.appendChild(this.audioSource);
} else {
this.audioSource.src = file + this.audioSuffix;
}
this.$refs.sound.load(); this.$refs.sound.load();
}); });
@@ -317,7 +325,7 @@ export default {
title: 'Habitica', title: 'Habitica',
text: errorMessage, text: errorMessage,
type: 'error', type: 'error',
timeout: true, timeout: false,
}); });
} }

View File

@@ -1,72 +1,48 @@
.promo_armoire_backgrounds_201805 { .promo_armoire_backgrounds_201805 {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png'); background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -142px -587px; background-position: -878px 0px;
width: 141px; width: 141px;
height: 441px; height: 441px;
} }
.promo_bundle_cuddleBuddies {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: 0px -534px;
width: 141px;
height: 441px;
}
.promo_fairy_potions {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: 0px 0px;
width: 564px;
height: 196px;
}
.promo_ios { .promo_ios {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png'); background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -532px 0px; background-position: 0px -197px;
width: 325px; width: 325px;
height: 336px; height: 336px;
} }
.promo_mystery_201804 { .promo_mystery_201804 {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png'); background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -340px -383px; background-position: -878px -442px;
width: 114px; width: 114px;
height: 90px; height: 90px;
} }
.promo_rainbow_potions {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -284px -587px;
width: 141px;
height: 441px;
}
.promo_seasonalshop_spring {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -340px -244px;
width: 162px;
height: 138px;
}
.promo_shimmer_pastel {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -426px -735px;
width: 354px;
height: 147px;
}
.promo_shiny_seeds {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -426px -587px;
width: 360px;
height: 147px;
}
.promo_spring_fling_2018 {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: 0px -587px;
width: 141px;
height: 588px;
}
.promo_take_this { .promo_take_this {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png'); background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -340px -474px; background-position: -716px -223px;
width: 114px; width: 114px;
height: 87px; height: 87px;
} }
.scene_positivity { .scene_casting_spells {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png'); background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: 0px 0px; background-position: -565px 0px;
width: 531px; width: 312px;
height: 243px; height: 222px;
} }
.scene_todos { .scene_meditation {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png'); background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -532px -337px; background-position: -565px -223px;
width: 240px; width: 150px;
height: 195px; height: 150px;
}
.scene_video_games {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: 0px -244px;
width: 339px;
height: 342px;
} }

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 142 KiB

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 265 KiB

After

Width:  |  Height:  |  Size: 266 KiB

View File

@@ -15,7 +15,7 @@
background-color: $gray-600; background-color: $gray-600;
padding: .5em; padding: .5em;
display: inline-block; display: inline-block;
margin-right: .5em; margin: .25em;
font-size: 12px; font-size: 12px;
font-weight: 500; font-weight: 500;
line-height: 1.33; line-height: 1.33;
@@ -23,6 +23,21 @@
color: $gray-300; color: $gray-300;
} }
.category-label-purple {
color: white;
background: $purple-300;
}
.category-label-blue {
color: white;
background: $blue-50;
}
.category-label-green {
color: white;
background: $green-50;
}
.category-select { .category-select {
border-radius: 2px; border-radius: 2px;
background-color: $white; background-color: $white;

View File

@@ -0,0 +1,34 @@
<template lang="pug">
.categories
span.category-label.category-label-blue(v-if='owner')
| {{ $t('owned') }}
span.category-label.category-label-green(v-if='member')
| {{ $t('joined') }}
span.category-label(
v-for='category in categories',
:class="{'category-label-purple':isOfficial(category)}"
)
| {{ $t(category.name) }}
slot
</template>
<script>
export default {
props: {
categories: {
required: true,
},
owner: {
default: false,
},
member: {
default: false,
},
},
methods: {
isOfficial (category) {
return category.name === 'habitica_official';
},
},
};
</script>

View File

@@ -6,11 +6,15 @@
challenge-member-progress-modal(:memberId='progressMemberId', :challengeId='challenge._id') challenge-member-progress-modal(:memberId='progressMemberId', :challengeId='challenge._id')
.col-12.col-md-8.standard-page .col-12.col-md-8.standard-page
.row .row
.col-12.col-md-8 .col-12.col-md-6
h1(v-markdown='challenge.name') h1(v-markdown='challenge.name')
div div
strong(v-once) {{$t('createdBy')}}: span.mr-1.ml-0
span(v-if='challenge.leader && challenge.leader.profile') {{challenge.leader.profile.name}} strong(v-once) {{ $t('createdBy') }}:
user-link.mx-1(:user="challenge.leader")
span.mr-1.ml-0(v-if="challenge.group && challenge.group.name !== 'Tavern'")
strong(v-once) {{ $t(challenge.group.type) }}:
group-link.mx-1(:group="challenge.group")
// @TODO: make challenge.author a variable inside the createdBy string (helps with RTL languages) // @TODO: make challenge.author a variable inside the createdBy string (helps with RTL languages)
// @TODO: Implement in V2 strong.margin-left(v-once) // @TODO: Implement in V2 strong.margin-left(v-once)
.svg-icon.calendar-icon(v-html="icons.calendarIcon") .svg-icon.calendar-icon(v-html="icons.calendarIcon")
@@ -19,7 +23,7 @@
// span {{challenge.endDate}} // span {{challenge.endDate}}
.tags .tags
span.tag(v-for='tag in challenge.tags') {{tag}} span.tag(v-for='tag in challenge.tags') {{tag}}
.col-12.col-md-4 .col-12.col-md-6.text-right
.box(@click="showMemberModal()") .box(@click="showMemberModal()")
.svg-icon.member-icon(v-html="icons.memberIcon") .svg-icon.member-icon(v-html="icons.memberIcon")
| {{challenge.memberCount}} | {{challenge.memberCount}}
@@ -29,10 +33,10 @@
| {{challenge.prize}} | {{challenge.prize}}
.details(v-once) {{$t('prize')}} .details(v-once) {{$t('prize')}}
.row.challenge-actions .row.challenge-actions
.col-12.col-md-7.offset-md-5 .col-12.col-md-6
span.view-progress strong.view-progress {{ $t('viewProgressOf') }}
strong {{ $t('viewProgressOf') }}
member-search-dropdown(:text="$t('selectParticipant')", :members='members', :challengeId='challengeId', @member-selected='openMemberProgressModal') member-search-dropdown(:text="$t('selectParticipant')", :members='members', :challengeId='challengeId', @member-selected='openMemberProgressModal')
.col-12.col-md-6.text-right
span(v-if='isLeader || isAdmin') span(v-if='isLeader || isAdmin')
b-dropdown.create-dropdown(:text="$t('addTaskToChallenge')", :variant="'success'") b-dropdown.create-dropdown(:text="$t('addTaskToChallenge')", :variant="'success'")
b-dropdown-item(v-for="type in columns", :key="type", @click="createTask(type)") b-dropdown-item(v-for="type in columns", :key="type", @click="createTask(type)")
@@ -56,24 +60,23 @@
v-on:editTask="editTask", v-on:editTask="editTask",
v-if='tasksByType[column].length > 0') v-if='tasksByType[column].length > 0')
.col-12.col-md-4.sidebar.standard-page .col-12.col-md-4.sidebar.standard-page
.acitons .button-container(v-if='canJoin')
div(v-if='canJoin') button.btn.btn-success(v-once, @click='joinChallenge()') {{$t('joinChallenge')}}
button.btn.btn-success(v-once, @click='joinChallenge()') {{$t('joinChallenge')}} .button-container(v-if='isLeader || isAdmin')
div(v-if='isMember') button.btn.btn-primary(v-once, @click='edit()') {{$t('editChallenge')}}
button.btn.btn-danger(v-once, @click='leaveChallenge()') {{$t('leaveChallenge')}} .button-container(v-if='isLeader || isAdmin')
div(v-if='isLeader || isAdmin') button.btn.btn-primary(v-once, @click='cloneChallenge()') {{$t('clone')}}
button.btn.btn-secondary(v-once, @click='edit()') {{$t('editChallenge')}} .button-container(v-if='isLeader || isAdmin')
div(v-if='isLeader || isAdmin') button.btn.btn-primary(v-once, @click='exportChallengeCsv()') {{$t('exportChallengeCsv')}}
button.btn.btn-danger(v-once, @click='closeChallenge()') {{$t('endChallenge')}} .button-container(v-if='isLeader || isAdmin')
div(v-if='isLeader || isAdmin') button.btn.btn-danger(v-once, @click='closeChallenge()') {{$t('endChallenge')}}
button.btn.btn-secondary(v-once, @click='exportChallengeCsv()') {{$t('exportChallengeCsv')}} div
div(v-if='isLeader || isAdmin') sidebar-section(:title="$t('challengeSummary')")
button.btn.btn-secondary(v-once, @click='cloneChallenge()') {{$t('clone')}} p(v-markdown='challenge.summary')
.description-section sidebar-section(:title="$t('challengeDescription')")
h2 {{$t('challengeSummary')}} p(v-markdown='challenge.description')
p(v-markdown='challenge.summary') .text-center(v-if='isMember')
h2 {{$t('challengeDescription')}} button.btn.btn-danger(v-once, @click='leaveChallenge()') {{$t('leaveChallenge')}}
p(v-markdown='challenge.description')
</template> </template>
<style lang='scss' scoped> <style lang='scss' scoped>
@@ -91,6 +94,14 @@
margin-left: .5em; margin-left: .5em;
} }
.button-container {
margin-bottom: 1em;
button {
width: 100%;
}
}
.calendar-icon { .calendar-icon {
width: 12px; width: 12px;
display: inline-block; display: inline-block;
@@ -138,23 +149,13 @@
} }
} }
.acitons {
width: 100%;
div, button {
width: 60%;
margin: 0 auto;
margin-bottom: .5em;
text-align: center;
}
}
.description-section { .description-section {
margin-top: 2em; margin-top: 2em;
} }
.challenge-actions { .challenge-actions {
margin-top: 1em; margin-top: 1em;
margin-bottom: 2em;
.view-progress { .view-progress {
margin-right: .5em; margin-right: .5em;
@@ -162,14 +163,6 @@
} }
</style> </style>
<style>
.create-dropdown button {
width: 100%;
font-size: 16px !important;
font-weight: bold !important;
}
</style>
<script> <script>
const TASK_KEYS_TO_REMOVE = ['_id', 'completed', 'date', 'dateCompleted', 'history', 'id', 'streak', 'createdAt', 'challenge']; const TASK_KEYS_TO_REMOVE = ['_id', 'completed', 'date', 'dateCompleted', 'history', 'id', 'streak', 'createdAt', 'challenge'];
@@ -189,7 +182,9 @@ import challengeModal from './challengeModal';
import challengeMemberProgressModal from './challengeMemberProgressModal'; import challengeMemberProgressModal from './challengeMemberProgressModal';
import challengeMemberSearchMixin from 'client/mixins/challengeMemberSearch'; import challengeMemberSearchMixin from 'client/mixins/challengeMemberSearch';
import leaveChallengeModal from './leaveChallengeModal'; import leaveChallengeModal from './leaveChallengeModal';
import sidebarSection from '../sidebarSection';
import userLink from '../userLink';
import groupLink from '../groupLink';
import taskDefaults from 'common/script/libs/taskDefaults'; import taskDefaults from 'common/script/libs/taskDefaults';
import gemIcon from 'assets/svg/gem.svg'; import gemIcon from 'assets/svg/gem.svg';
@@ -208,8 +203,11 @@ export default {
challengeModal, challengeModal,
challengeMemberProgressModal, challengeMemberProgressModal,
memberSearchDropdown, memberSearchDropdown,
sidebarSection,
TaskColumn: Column, TaskColumn: Column,
TaskModal, TaskModal,
userLink,
groupLink,
}, },
data () { data () {
return { return {

View File

@@ -1,187 +1,278 @@
<template lang="pug"> <template lang="pug">
.card .challenge
.row .challenge-prize
router-link.col-12(:to="{ name: 'challenge', params: { challengeId: challenge._id } }") .number
h3(v-markdown='challenge.name') span.svg-icon(v-html="icons.gemIcon")
.row span.value {{challenge.prize}}
.col-6 .label {{ $t('challengePrize') }}
div.details .challenge-header
span router-link(
.svg-icon.member-icon(v-html="icons.memberIcon") :to="{ name: 'challenge', params: { challengeId: challenge._id } }"
span {{challenge.memberCount}} )
// @TODO: Add in V2 h3.challenge-title(v-markdown='challenge.name')
span .owner(v-if="fullLayout")
.svg-icon.calendar-icon(v-html="icons.calendarIcon") .owner-item
span strong {{ $t('createdBy') }}:
strong End Date: user-link.mx-1(:user="challenge.leader")
.owner-item(v-if="challenge.group && !isTavern(challenge.group)")
strong {{ $t(challenge.group.type) }}:
group-link.mx-1(:group="challenge.group")
.meta
.meta-item
.svg-icon.user-icon(v-html="icons.memberIcon")
span.mx-1 {{challenge.memberCount}}
// @TODO: add end date
.meta-item
.svg-icon(v-html="icons.calendarIcon")
strong.mx-1 {{ $t('endDate')}}:
span {{challenge.endDate}} span {{challenge.endDate}}
div.tags category-tags.challenge-categories(
span.tag(v-for='tag in challenge.tags') {{tag}} :categories="challenge.categories",
.col-6.prize-section :owner="isOwner",
div :member="isMember",
span.svg-icon.gem(v-html="icons.gemIcon") v-once
span.prize {{challenge.prize}} )
div Challenge Prize .challenge-description(v-markdown='challenge.summary')
.row.description .well-wrapper(v-if="fullLayout")
.col-12 .well
| {{challenge.summary}} div(v-for="task in tasksData", :class="{'muted': task.value === 0}", v-once)
.well.row .number
.col-3 .svg-icon(v-html="task.icon", :class="task.label + '-icon'")
.count-details span.value {{ task.value }}
.svg-icon.habit-icon(v-html="icons.habitIcon") .label {{$t(task.label)}}
span.count {{challenge.tasksOrder.habits.length}}
div {{$t('habit')}}
.col-3
.count-details
.svg-icon.daily-icon(v-html="icons.dailyIcon")
span.count {{challenge.tasksOrder.dailys.length}}
div {{$t('daily')}}
.col-3
.count-details
.svg-icon.todo-icon(v-html="icons.todoIcon")
span.count {{challenge.tasksOrder.todos.length}}
div {{$t('todo')}}
.col-3
.count-details
.svg-icon.reward-icon(v-html="icons.rewardIcon")
span.count {{challenge.tasksOrder.rewards.length}}
div {{$t('reward')}}
</template> </template>
<style lang="scss">
// Have to use this, because v-markdown creates p element in h3. Scoping doesn't work with it.
.challenge-title > p {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
max-height: 3em;
line-height: 1.5em;
overflow: hidden;
text-overflow: ellipsis;
word-break: break-all;
}
</style>
<style lang="scss" scoped> <style lang="scss" scoped>
@import '~client/assets/scss/colors.scss'; @import '~client/assets/scss/colors.scss';
.card { .challenge {
background-color: $white; background-color: $white;
box-shadow: 0 2px 2px 0 $gray-600, 0 1px 4px 0 $gray-600; box-shadow: 0 2px 2px 0 rgba($black, 0.15), 0 1px 4px 0 rgba($black, 0.1);
padding: 2em;
height: 350px;
margin-bottom: 1em; margin-bottom: 1em;
border-radius: 4px;
padding-bottom: .5em;
.gem { .number {
width: 32px; display: flex;
align-items: center;
justify-content: center;
.svg-icon {
margin-top: -.2em;
}
.value {
margin-left: .5em;
font-size: 24px;
}
} }
.member-icon { .label {
font-size: .9em;
}
.challenge-prize {
text-align: center;
color: $gems-color;
display: inline-block;
float: right;
padding: 1em 1.5em;
margin-left: 1em;
background: #eefaf6;
border-bottom-left-radius: 4px;
.svg-icon {
width: 32px;
}
}
.challenge-header,
.well-wrapper {
padding: 1em 1.5em;
}
.challenge-header {
padding-bottom: .5em;
}
.owner {
margin: 1em 0 .5em;
}
.meta, .owner {
display: flex;
align-items: center;
flex-wrap: wrap;
}
.meta-item, .owner-item {
display: inline-flex;
color: $gray-200;
align-items: center;
margin-right: 1em;
white-space: nowrap;
.svg-icon {
color: $gray-300;
width: 14px;
}
}
.challenge-categories {
clear: right;
display: flex;
padding: 0 1.5em 1em;
flex-wrap: wrap;
}
.user-icon {
width: 20px !important;
}
.habit-icon {
width: 30px;
}
.todo-icon {
width: 20px; width: 20px;
} }
.calendar-icon { .daily-icon {
width: 14px; width: 24px;
} }
span { .reward-icon {
display: inline-block; width: 26px;
font-size: 14px; }
.challenge-description {
color: $gray-200; color: $gray-200;
margin-right: 1em; margin: 0 1.5em;
vertical-align: bottom; word-break: break-word;
}
.details {
margin: 1em 0;
}
.tags {
margin-bottom: 1em;
}
.tag {
border-radius: 30px;
background-color: $gray-600;
padding: .5em;
}
.prize {
color: $gray-100;
font-size: 24px;
}
.prize-section {
text-align: right;
padding-right: 2em;
}
.description {
color: $gray-200;
margin-top: 1em;
margin-bottom: 1em;
overflow: hidden;
height: 80px;
}
.well-wrapper {
padding: .8em;
} }
.well { .well {
display: flex;
align-items: center;
justify-content: space-evenly;
background-color: $gray-700; background-color: $gray-700;
text-align: center; text-align: center;
padding: 2em; padding: 1em;
border-radius: 4px; border-radius: .25em;
margin-left: .2em;
margin-right: .2em;
.svg-icon { > div {
display: inline-block; color: $gray-200;
margin-left: .5em;
.svg-icon {
color: $gray-300;
}
} }
.habit-icon { > div.muted {
width: 30px; color: $gray-400;
}
.todo-icon { .svg-icon {
width: 20px; color: $gray-500;
} }
.daily-icon {
width: 24px;
}
.reward-icon {
width: 26px;
}
.count-details span {
margin-right: .5em;
}
.count {
font-size: 20px;
margin-left: .5em;
} }
} }
} }
</style> </style>
<script> <script>
import gemIcon from 'assets/svg/gem.svg'; import { TAVERN_ID } from '../../../common/script/constants';
import memberIcon from 'assets/svg/member-icon.svg'; import userLink from '../userLink';
import calendarIcon from 'assets/svg/calendar.svg'; import groupLink from '../groupLink';
import habitIcon from 'assets/svg/habit.svg'; import categoryTags from '../categories/categoryTags';
import todoIcon from 'assets/svg/todo.svg'; import markdownDirective from 'client/directives/markdown';
import dailyIcon from 'assets/svg/daily.svg'; import {mapState} from 'client/libs/store';
import rewardIcon from 'assets/svg/reward.svg';
import markdownDirective from 'client/directives/markdown';
export default { import gemIcon from 'assets/svg/gem.svg';
props: ['challenge'], import memberIcon from 'assets/svg/member-icon.svg';
data () { import calendarIcon from 'assets/svg/calendar.svg';
return { import habitIcon from 'assets/svg/habit.svg';
icons: Object.freeze({ import todoIcon from 'assets/svg/todo.svg';
gemIcon, import dailyIcon from 'assets/svg/daily.svg';
memberIcon, import rewardIcon from 'assets/svg/reward.svg';
calendarIcon,
habitIcon, export default {
todoIcon, props: {
dailyIcon, challenge: {
rewardIcon, required: true,
}), },
}; fullLayout: {
}, default: true,
directives: { },
markdown: markdownDirective, },
}, components: {
}; userLink,
groupLink,
categoryTags,
},
directives: {
markdown: markdownDirective,
},
data () {
return {
icons: Object.freeze({
gemIcon,
memberIcon,
calendarIcon,
}),
};
},
computed: {
...mapState({user: 'user.data'}),
isOwner () {
return this.challenge.leader && this.challenge.leader._id === this.user._id;
},
isMember () {
return this.user.challenges.indexOf(this.challenge._id) !== -1;
},
tasksData () {
return [
{
icon: habitIcon,
label: 'habit',
value: this.challenge.tasksOrder.habits.length,
},
{
icon: dailyIcon,
label: 'daily',
value: this.challenge.tasksOrder.dailys.length,
},
{
icon: todoIcon,
label: 'todo',
value: this.challenge.tasksOrder.todos.length,
},
{
icon: rewardIcon,
label: 'reward',
value: this.challenge.tasksOrder.rewards.length,
},
];
},
},
methods: {
isTavern (group) {
return group._id === TAVERN_ID;
},
},
};
</script> </script>

View File

@@ -15,7 +15,7 @@
.svg-icon.positive-icon(v-html="icons.positiveIcon") .svg-icon.positive-icon(v-html="icons.positiveIcon")
span(v-once) {{$t('createChallenge')}} span(v-once) {{$t('createChallenge')}}
.row .row
.col-12.col-md-6(v-for='challenge in filteredChallenges', v-if='!memberOf(challenge)') .col-12.col-md-6(v-for='challenge in filteredChallenges')
challenge-item(:challenge='challenge') challenge-item(:challenge='challenge')
.row .row
.col-12.text-center .col-12.text-center
@@ -105,9 +105,6 @@ export default {
}, },
}, },
methods: { methods: {
memberOf (challenge) {
return this.user.challenges.indexOf(challenge._id) !== -1;
},
updateSearch (eventData) { updateSearch (eventData) {
this.search = eventData.searchTerm; this.search = eventData.searchTerm;
this.page = 0; this.page = 0;

View File

@@ -6,131 +6,87 @@ div
.svg-icon.challenge-icon(v-html="icons.challengeIcon") .svg-icon.challenge-icon(v-html="icons.challengeIcon")
h4(v-once) {{ $t('haveNoChallenges') }} h4(v-once) {{ $t('haveNoChallenges') }}
p(v-once) {{ $t('challengeDetails') }} p(v-once) {{ $t('challengeDetails') }}
router-link.title(:to="{ name: 'challenge', params: { challengeId: challenge._id } }", v-for='challenge in challenges',:key='challenge._id') button.btn.btn-secondary(@click='createChallenge()') {{ $t('createChallenge') }}
.col-12.challenge-item template(v-else)
.row challenge-item(v-for='challenge in challenges',:challenge='challenge',:key='challenge._id',:fullLayout='false')
.col-9 .col-12.text-center
router-link.title(:to="{ name: 'challenge', params: { challengeId: challenge._id } }") button.btn.btn-secondary(@click='createChallenge()') {{ $t('createChallenge') }}
strong(v-markdown='challenge.name')
p(v-markdown='challenge.summary || challenge.name')
div
.svg-icon.member-icon(v-html="icons.memberIcon")
.member-count {{challenge.memberCount}}
.col-3
div
span.svg-icon.gem(v-html="icons.gemIcon")
span.prize {{challenge.prize}}
div.prize-title Prize
.col-12.text-center
button.btn.btn-secondary(@click='createChallenge()') {{ $t('createChallenge') }}
</template> </template>
<style scoped> <style lang="scss" scoped>
.title { @import '~client/assets/scss/colors.scss';
color: #4E4A57;
}
.member-icon { .no-quest-section {
display: inline-block;
width: 20px !important;
vertical-align: bottom;
height: 16px !important;
}
.member-count {
width: 21px;
height: 16px;
font-size: 14px;
line-height: 2;
color: #878190;
display: inline-block;
text-align: center;
}
.challenge-icon {
height: 30px;
width: 30px;
margin-bottom: 2em;
margin: 0 auto;
}
.gem {
width: 26px;
vertical-align: bottom;
display: inline-block;
}
.prize {
color: #686274;
font-size: 18px;
margin-left: .5em;
}
.prize-title {
padding-left: .7em;
}
.challenge-item {
border-radius: 2px;
background-color: #ffffff;
box-shadow: 0 2px 2px 0 rgba(26, 24, 29, 0.16), 0 1px 4px 0 rgba(26, 24, 29, 0.12);
margin-bottom: 1em;
padding: 2em; padding: 2em;
color: $gray-300;
h4 {
color: $gray-300;
}
p {
margin-bottom: 2em;
}
.svg-icon {
height: 30px;
width: 30px;
margin: 0 auto;
margin-bottom: 2em;
}
} }
</style> </style>
<script> <script>
import challengeModal from './challengeModal'; import challengeModal from './challengeModal';
import { mapState } from 'client/libs/store'; import {mapState} from 'client/libs/store';
import markdownDirective from 'client/directives/markdown'; import markdownDirective from 'client/directives/markdown';
import challengeIcon from 'assets/svg/challenge.svg'; import challengeItem from './challengeItem';
import gemIcon from 'assets/svg/gem.svg'; import challengeIcon from 'assets/svg/challenge.svg';
import memberIcon from 'assets/svg/member-icon.svg';
export default { export default {
props: ['groupId'], props: ['groupId'],
components: { components: {
challengeModal, challengeModal,
}, challengeItem,
computed: { },
...mapState({user: 'user.data'}), computed: {
}, ...mapState({user: 'user.data'}),
data () { },
return { data () {
challenges: [], return {
icons: Object.freeze({ challenges: [],
challengeIcon, icons: Object.freeze({
memberIcon, challengeIcon,
gemIcon, }),
}), groupIdForChallenges: '',
groupIdForChallenges: '', };
}; },
}, directives: {
directives: { markdown: markdownDirective,
markdown: markdownDirective, },
}, mounted () {
mounted () {
this.loadChallenges();
},
watch: {
async groupId () {
this.loadChallenges(); this.loadChallenges();
}, },
}, watch: {
methods: { async groupId () {
async loadChallenges () { this.loadChallenges();
this.groupIdForChallenges = this.groupId; },
if (this.groupId === 'party' && this.user.party._id) this.groupIdForChallenges = this.user.party._id;
this.challenges = await this.$store.dispatch('challenges:getGroupChallenges', {groupId: this.groupIdForChallenges});
}, },
createChallenge () { methods: {
this.$root.$emit('bv::show::modal', 'challenge-modal'); async loadChallenges () {
this.groupIdForChallenges = this.groupId;
if (this.groupId === 'party' && this.user.party._id) this.groupIdForChallenges = this.user.party._id;
this.challenges = await this.$store.dispatch('challenges:getGroupChallenges', {groupId: this.groupIdForChallenges});
},
createChallenge () {
this.$root.$emit('bv::show::modal', 'challenge-modal');
},
challengeCreated (challenge) {
if (challenge.group._id !== this.groupIdForChallenges) return;
this.challenges.push(challenge);
},
}, },
challengeCreated (challenge) { };
if (challenge.group._id !== this.groupIdForChallenges) return;
this.challenges.push(challenge);
},
},
};
</script> </script>

View File

@@ -63,8 +63,6 @@
</style> </style>
<script> <script>
import { mapState } from 'client/libs/store';
import Sidebar from './sidebar'; import Sidebar from './sidebar';
import ChallengeItem from './challengeItem'; import ChallengeItem from './challengeItem';
import challengeModal from './challengeModal'; import challengeModal from './challengeModal';
@@ -111,24 +109,18 @@ export default {
}, },
], ],
search: '', search: '',
filters: { filters: {},
roles: ['participating'], // This is required for my challenges
},
}; };
}, },
mounted () { mounted () {
this.loadchallanges(); this.loadchallanges();
}, },
computed: { computed: {
...mapState({user: 'user.data'}),
filteredChallenges () { filteredChallenges () {
let search = this.search; let search = this.search;
let filters = this.filters; let filters = this.filters;
let user = this.$store.state.user.data; let user = this.$store.state.user.data;
// Always filter by member on this page:
filters.roles = ['participating'];
// @TODO: Move this to the server // @TODO: Move this to the server
return this.challenges.filter((challenge) => { return this.challenges.filter((challenge) => {
return this.filterChallenge(challenge, filters, search, user); return this.filterChallenge(challenge, filters, search, user);
@@ -136,9 +128,6 @@ export default {
}, },
}, },
methods: { methods: {
memberOf (challenge) {
return this.user.challenges.indexOf(challenge._id) !== -1;
},
updateSearch (eventData) { updateSearch (eventData) {
this.search = eventData.searchTerm; this.search = eventData.searchTerm;
}, },

View File

@@ -5,7 +5,7 @@
form form
h2(v-once) {{ $t('filter') }} h2(v-once) {{ $t('filter') }}
.form-group .form-group
h3 Category h3 {{ $t('category') }}
.form-check( .form-check(
v-for="group in categoryOptions", v-for="group in categoryOptions",
:key="group.key", :key="group.key",
@@ -14,7 +14,7 @@
input.custom-control-input(type="checkbox", :value='group.key' v-model="categoryFilters", :id="group.key") input.custom-control-input(type="checkbox", :value='group.key' v-model="categoryFilters", :id="group.key")
label.custom-control-label(v-once, :for="group.key") {{ $t(group.label) }} label.custom-control-label(v-once, :for="group.key") {{ $t(group.label) }}
.form-group(v-if='$route.name !== "findChallenges"') .form-group(v-if='$route.name !== "findChallenges"')
h3 Membership h3 {{ $t('membership') }}
.form-check( .form-check(
v-for="group in roleOptions", v-for="group in roleOptions",
:key="group.key", :key="group.key",
@@ -23,7 +23,7 @@
input.custom-control-input(type="checkbox", :value='group.key' v-model="roleFilters", :id="group.key") input.custom-control-input(type="checkbox", :value='group.key' v-model="roleFilters", :id="group.key")
label.custom-control-label(v-once, :for="group.key") {{ $t(group.label) }} label.custom-control-label(v-once, :for="group.key") {{ $t(group.label) }}
.form-group .form-group
h3 Ownership h3 {{ $t('ownership') }}
.form-check( .form-check(
v-for="group in ownershipOptions", v-for="group in ownershipOptions",
:key="group.key", :key="group.key",

View File

@@ -163,32 +163,27 @@ b-modal#avatar-modal(title="", :size='editing ? "lg" : "md"', :hide-header='true
:class='{active: user.preferences.hair.bangs === option}') :class='{active: user.preferences.hair.bangs === option}')
.bangs.sprite.customize-option(:class="`hair_bangs_${option}_${user.preferences.hair.color}`", @click='set({"preferences.hair.bangs": option})') .bangs.sprite.customize-option(:class="`hair_bangs_${option}_${user.preferences.hair.color}`", @click='set({"preferences.hair.bangs": option})')
#facialhair.row(v-if='activeSubPage === "facialhair"') #facialhair.row(v-if='activeSubPage === "facialhair"')
.col-12.customize-options(v-if='editing')
.head_0.option(@click='set({"preferences.hair.beard": 0})', :class="[{ active: user.preferences.hair.beard === 0 }, 'hair_base_0_' + user.preferences.hair.color]")
.option(v-for='option in baseHair5',
:class='{active: option.active, locked: option.locked}')
.base.sprite.customize-option(:class="`hair_beard_${option.key}_${user.preferences.hair.color}`", @click='option.click')
.gem-lock(v-if='option.locked')
.svg-icon.gem(v-html='icons.gem')
span 2
.col-12.text-center(v-if='!userOwnsSet("hair", baseHair5Keys, "beard")')
.gem-lock
.svg-icon.gem(v-html='icons.gem')
span 5
button.btn.btn-secondary.purchase-all(@click='unlock(`hair.beard.${baseHair5Keys.join(",hair.beard.")}`)') {{ $t('purchaseAll') }}
.col-12.customize-options(v-if='editing') .col-12.customize-options(v-if='editing')
.head_0.option(@click='set({"preferences.hair.mustache": 0})', :class="[{ active: user.preferences.hair.mustache === 0 }, 'hair_base_0_' + user.preferences.hair.color]") .head_0.option(@click='set({"preferences.hair.mustache": 0})', :class="[{ active: user.preferences.hair.mustache === 0 }, 'hair_base_0_' + user.preferences.hair.color]")
.option(v-for='option in baseHair6', .option(v-for='option in baseHair5',
:class='{active: option.active, locked: option.locked}') :class='{active: option.active, locked: option.locked}')
.base.sprite.customize-option(:class="`hair_mustache_${option.key}_${user.preferences.hair.color}`", @click='option.click') .base.sprite.customize-option(:class="`hair_mustache_${option.key}_${user.preferences.hair.color}`", @click='option.click')
.gem-lock(v-if='option.locked') .gem-lock(v-if='option.locked')
.svg-icon.gem(v-html='icons.gem') .svg-icon.gem(v-html='icons.gem')
span 2 span 2
.col-12.text-center(v-if='!userOwnsSet("hair", baseHair6Keys, "mustache")') .col-12.customize-options(v-if='editing')
.head_0.option(@click='set({"preferences.hair.beard": 0})', :class="[{ active: user.preferences.hair.beard === 0 }, 'hair_base_0_' + user.preferences.hair.color]")
.option(v-for='option in baseHair6',
:class='{active: option.active, locked: option.locked}')
.base.sprite.customize-option(:class="`hair_beard_${option.key}_${user.preferences.hair.color}`", @click='option.click')
.gem-lock(v-if='option.locked')
.svg-icon.gem(v-html='icons.gem')
span 2
.col-12.text-center(v-if="isPurchaseAllNeeded('hair', ['baseHair5', 'baseHair6'], ['mustache', 'beard'])")
.gem-lock .gem-lock
.svg-icon.gem(v-html='icons.gem') .svg-icon.gem(v-html='icons.gem')
span 5 span 5
button.btn.btn-secondary.purchase-all(@click='unlock(`hair.mustache.${baseHair6Keys.join(",hair.mustache.")}`)') {{ $t('purchaseAll') }} button.btn.btn-secondary.purchase-all(@click='unlock(`hair.mustache.${baseHair5Keys.join(",hair.mustache.")},hair.beard.${baseHair6Keys.join(",hair.beard.")}`)') {{ $t('purchaseAll') }}
#extra.section.container.customize-section(v-if='activeTopPage === "extra"') #extra.section.container.customize-section(v-if='activeTopPage === "extra"')
.row.sub-menu .row.sub-menu
.col-3.offset-1.text-center.sub-menu-item(@click='changeSubPage("glasses")', :class='{active: activeSubPage === "glasses"}') .col-3.offset-1.text-center.sub-menu-item(@click='changeSubPage("glasses")', :class='{active: activeSubPage === "glasses"}')
@@ -1010,8 +1005,8 @@ export default {
baseHair2Keys: [2, 4, 5, 6, 7, 8], baseHair2Keys: [2, 4, 5, 6, 7, 8],
baseHair3Keys: [9, 10, 11, 12, 13, 14], baseHair3Keys: [9, 10, 11, 12, 13, 14],
baseHair4Keys: [15, 16, 17, 18, 19, 20], baseHair4Keys: [15, 16, 17, 18, 19, 20],
baseHair5Keys: [1, 2, 3], baseHair5Keys: [1, 2],
baseHair6Keys: [1, 2], baseHair6Keys: [1, 2, 3],
animalEarsKeys: ['bearEars', 'cactusEars', 'foxEars', 'lionEars', 'pandaEars', 'pigEars', 'tigerEars', 'wolfEars'], animalEarsKeys: ['bearEars', 'cactusEars', 'foxEars', 'lionEars', 'pandaEars', 'pigEars', 'tigerEars', 'wolfEars'],
icons: Object.freeze({ icons: Object.freeze({
logoPurple, logoPurple,
@@ -1228,7 +1223,7 @@ export default {
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
let keys = this.baseHair5Keys; let keys = this.baseHair5Keys;
let options = keys.map(key => { let options = keys.map(key => {
return this.mapKeysToOption(key, 'hair', 'beard'); return this.mapKeysToOption(key, 'hair', 'mustache');
}); });
return options; return options;
}, },
@@ -1237,7 +1232,7 @@ export default {
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
let keys = this.baseHair6Keys; let keys = this.baseHair6Keys;
let options = keys.map(key => { let options = keys.map(key => {
return this.mapKeysToOption(key, 'hair', 'mustache'); return this.mapKeysToOption(key, 'hair', 'beard');
}); });
return options; return options;
}, },
@@ -1335,6 +1330,68 @@ export default {
return owns; return owns;
}, },
/**
* Allows you to find out whether you need the "Purchase All" button or not. If there are more than 2 unpurchased items, returns true, otherwise returns false.
* @param {string} category - The selected category.
* @param {string[]} keySets - The items keySets.
* @param {string[]} [types] - The items types (subcategories). Optional.
* @returns {boolean} - Determines whether the "Purchase All" button is needed (true) or not (false).
*/
isPurchaseAllNeeded (category, keySets, types) {
const purchasedItemsLengths = [];
// If item types are specified, count them
if (types && types.length > 0) {
// Types can be undefined, so we must check them.
types.forEach((type) => {
if (this.user.purchased[category][type]) {
purchasedItemsLengths
.push(Object.keys(this.user.purchased[category][type]).length);
}
});
} else {
let purchasedItemsCounter = 0;
// If types are not specified, recursively
// search for purchased items in the category
const findPurchasedItems = (item) => {
if (typeof item === 'object') {
Object.values(item)
.forEach((innerItem) => {
if (typeof innerItem === 'boolean' && innerItem === true) {
purchasedItemsCounter += 1;
}
return findPurchasedItems(innerItem);
});
}
return purchasedItemsCounter;
};
findPurchasedItems(this.user.purchased[category]);
if (purchasedItemsCounter > 0) {
purchasedItemsLengths.push(purchasedItemsCounter);
}
}
// We don't need to count the key sets (below)
// if there are no purchased items at all.
if (purchasedItemsLengths.length === 0) {
return true;
}
const allItemsLengths = [];
// Key sets must be specify correctly.
keySets.forEach((keySet) => {
allItemsLengths.push(Object.keys(this[keySet]).length);
});
// Simply sum all the length values and
// write them into variables for the convenience.
const allItems = allItemsLengths.reduce((acc, val) => acc + val);
const purchasedItems = purchasedItemsLengths.reduce((acc, val) => acc + val);
const unpurchasedItems = allItems - purchasedItems;
return unpurchasedItems > 2;
},
prev () { prev () {
this.modalPage -= 1; this.modalPage -= 1;
}, },

View File

@@ -0,0 +1,25 @@
<template lang="pug">
b-link(
v-if='group',
@click.prevent='goToGroup'
) {{group.name}}
</template>
<script>
import { TAVERN_ID } from '../../common/script/constants';
export default {
props: ['group'],
methods: {
goToGroup () {
if (this.group.type === 'party') {
this.$router.push({name: 'party'});
} else if (this.group._id === TAVERN_ID) {
this.$router.push({name: 'tavern'});
} else {
this.$router.push({name: 'guild', params: {groupId: this.group._id}});
}
},
},
};
</script>

View File

@@ -0,0 +1,222 @@
<template lang="pug">
.row.chat-row
.col-12
h3(v-once) {{ label }}
.row
textarea(:placeholder='placeholder',
v-model='newMessage',
:class='{"user-entry": newMessage}',
@keydown='updateCarretPosition',
@keyup.ctrl.enter='sendMessageShortcut()',
@paste='disableMessageSendShortcut()'
)
autocomplete(
:text='newMessage',
v-on:select="selectedAutocomplete",
:coords='coords',
:chat='group.chat')
.row.chat-actions
.col-6.chat-receive-actions
button.btn.btn-secondary.float-left.fetch(v-once, @click='fetchRecentMessages()') {{ $t('fetchRecentMessages') }}
button.btn.btn-secondary.float-left(v-once, @click='reverseChat()') {{ $t('reverseChat') }}
.col-6.chat-send-actions
button.btn.btn-secondary.send-chat.float-right(v-once, @click='sendMessage()') {{ $t('send') }}
community-guidelines
slot(
name="additionRow",
)
.row
.hr.col-12
chat-message(:chat.sync='group.chat', :group-id='group._id', :group-name='group.name')
</template>
<script>
import debounce from 'lodash/debounce';
import autocomplete from '../chat/autoComplete';
import communityGuidelines from './communityGuidelines';
import chatMessage from '../chat/chatMessages';
export default {
props: ['label', 'group', 'placeholder'],
components: {
autocomplete,
communityGuidelines,
chatMessage,
},
data () {
return {
newMessage: '',
chat: {
submitDisable: false,
submitTimeout: null,
},
coords: {
TOP: 0,
LEFT: 0,
},
};
},
methods: {
// https://medium.com/@_jh3y/how-to-where-s-the-caret-getting-the-xy-position-of-the-caret-a24ba372990a
getCoord (e, text) {
let carPos = text.selectionEnd;
let div = document.createElement('div');
let span = document.createElement('span');
let 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, carPos);
span.textContent = text.value.substr(carPos) || '.';
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) {
let 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) {
this.sendMessage();
}
},
async sendMessage () {
let response = await this.$store.dispatch('chat:postChat', {
group: this.group,
message: this.newMessage,
});
this.group.chat.unshift(response.message);
this.newMessage = '';
// @TODO: I would like to not reload everytime we send. Realtime/Firebase?
let chat = await this.$store.dispatch('chat:getChat', {groupId: this.group._id});
this.group.chat = chat;
},
disableMessageSendShortcut () {
// Some users were experiencing accidental sending of messages after pasting
// So, after pasting, disable the shortcut for a second.
this.chat.submitDisable = true;
if (this.chat.submitTimeout) {
// If someone pastes during the disabled period, prevent early re-enable
clearTimeout(this.chat.submitTimeout);
this.chat.submitTimeout = null;
}
this.chat.submitTimeout = window.setTimeout(() => {
this.chat.submitTimeout = null;
this.chat.submitDisable = false;
}, 500);
},
selectedAutocomplete (newText) {
this.newMessage = newText;
},
fetchRecentMessages () {
this.$emit('fetchRecentMessages');
},
reverseChat () {
this.group.chat.reverse();
},
},
beforeRouteUpdate (to, from, next) {
// Reset chat
this.newMessage = '';
this.coords = {
TOP: 0,
LEFT: 0,
};
next();
},
};
</script>
<style scoped lang="scss">
@import '~client/assets/scss/colors.scss';
@import '~client/assets/scss/variables.scss';
.chat-actions {
margin-top: 1em;
.chat-receive-actions {
padding-left: 0;
button {
margin-bottom: 1em;
&:not(:last-child) {
margin-right: 1em;
}
}
}
.chat-send-actions {
padding-right: 0;
}
}
.chat-row {
position: relative;
textarea {
height: 150px;
width: 100%;
background-color: $white;
border: solid 1px $gray-400;
font-size: 16px;
font-style: italic;
line-height: 1.43;
color: $gray-300;
padding: .5em;
}
.user-entry {
font-style: normal;
color: $black;
}
.hr {
width: 100%;
height: 20px;
border-bottom: 1px solid $gray-500;
text-align: center;
margin: 2em 0;
}
.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;
}
}
</style>

View File

@@ -9,8 +9,10 @@
.row .row
.col-12.col-md-6.title-details .col-12.col-md-6.title-details
h1 {{group.name}} h1 {{group.name}}
strong.float-left(v-once) {{$t('groupLeader')}} div
span.leader.float-left(v-if='group.leader.profile', @click='showMemberProfile(group.leader)') : {{group.leader.profile.name}} span.mr-1.ml-0
strong(v-once) {{$t('groupLeader')}}:
user-link.mx-1(:user="group.leader")
.col-12.col-md-6 .col-12.col-md-6
.row.icon-row .row.icon-row
.col-4.offset-4(v-bind:class="{ 'offset-8': isParty }") .col-4.offset-4(v-bind:class="{ 'offset-8': isParty }")
@@ -25,25 +27,16 @@
.svg-icon.gem(v-html="icons.gem") .svg-icon.gem(v-html="icons.gem")
span.number {{group.balance * 4}} span.number {{group.balance * 4}}
div(v-once) {{ $t('guildBank') }} div(v-once) {{ $t('guildBank') }}
.row.chat-row chat(
.col-12 :label="$t('chat')",
h3(v-once) {{ $t('chat') }} :group="group",
.row.new-message-row :placeholder="!isParty ? $t('chatPlaceholder') : $t('partyChatPlaceholder')",
textarea(:placeholder="!isParty ? $t('chatPlaceholder') : $t('partyChatPlaceholder')", v-model='newMessage', @keydown='updateCarretPosition', @keyup.ctrl.enter='sendMessage()') @fetchRecentMessages="fetchRecentMessages()"
autocomplete(:text='newMessage', v-on:select="selectedAutocomplete", :coords='coords', :chat='group.chat') )
.row.chat-actions template(slot="additionRow")
.col-6.chat-receive-actions
button.btn.btn-secondary.float-left.fetch(v-once, @click='fetchRecentMessages()') {{ $t('fetchRecentMessages') }}
button.btn.btn-secondary.float-left(v-once, @click='reverseChat()') {{ $t('reverseChat') }}
.col-6.chat-send-actions
button.btn.btn-secondary.send-chat.float-right(v-once, @click='sendMessage()') {{ $t('send') }}
community-guidelines
.row(v-if='showNoNotificationsMessage') .row(v-if='showNoNotificationsMessage')
.col-12.no-notifications .col-12.no-notifications
| {{$t('groupNoNotifications')}} | {{$t('groupNoNotifications')}}
.row
.col-12.hr
chat-message(:chat.sync='group.chat', :group-id='group._id', :group-name='group.name')
.col-12.col-sm-4.sidebar .col-12.col-sm-4.sidebar
.row(:class='{"guild-background": !isParty}') .row(:class='{"guild-background": !isParty}')
.col-12 .col-12
@@ -61,47 +54,16 @@
// @TODO: V2 button.btn.btn-primary(v-once, v-if='!isLeader') {{$t('messageGuildLeader')}} // Suggest making the button visible to the leader too - useful for them to test how the feature works or to send a note to themself. -- Alys // @TODO: V2 button.btn.btn-primary(v-once, v-if='!isLeader') {{$t('messageGuildLeader')}} // Suggest making the button visible to the leader too - useful for them to test how the feature works or to send a note to themself. -- Alys
.button-container .button-container
// @TODO: V2 button.btn.btn-primary(v-once, v-if='isMember && !isParty') {{$t('donateGems')}} // Suggest removing the isMember restriction - it's okay if non-members donate to a public guild. Also probably allow it for parties if parties can buy imagery. -- Alys // @TODO: V2 button.btn.btn-primary(v-once, v-if='isMember && !isParty') {{$t('donateGems')}} // Suggest removing the isMember restriction - it's okay if non-members donate to a public guild. Also probably allow it for parties if parties can buy imagery. -- Alys
.section-header(v-if='isParty') div
quest-sidebar-section(@toggle='toggleQuestSection', :show='sections.quest', :group='group') quest-sidebar-section(:group='group', v-if='isParty')
.section-header(v-if='!isParty') sidebar-section(:title="$t('guildSummary')", v-if='!isParty')
.row
.col-10
h3(v-once) {{ $t('guildSummary') }}
.col-2
.toggle-up(@click="sections.summary = !sections.summary", v-if="sections.summary")
.svg-icon(v-html="icons.upIcon")
.toggle-down(@click="sections.summary = !sections.summary", v-if="!sections.summary")
.svg-icon(v-html="icons.downIcon")
.section(v-if="sections.summary")
p(v-markdown='group.summary') p(v-markdown='group.summary')
.section-header sidebar-section(:title="$t('groupDescription')")
.row
.col-10
h3 {{ $t('groupDescription') }}
.col-2
.toggle-up(@click="sections.description = !sections.description", v-if="sections.description")
.svg-icon(v-html="icons.upIcon")
.toggle-down(@click="sections.description = !sections.description", v-if="!sections.description")
.svg-icon(v-html="icons.downIcon")
.section(v-if="sections.description")
p(v-markdown='group.description') p(v-markdown='group.description')
.section-header.challenge sidebar-section(
.row :title="$t('challenges')",
.col-10.information-header :tooltip="isParty ? $t('challengeDetails') : $t('privateDescription')"
h3(v-once) )
| {{ $t('challenges') }}
#groupPrivateDescOrChallengeInfo.icon.tooltip-wrapper(:title="isParty ? $t('challengeDetails') : $t('privateDescription')")
.svg-icon(v-html='icons.information')
b-tooltip(
:title="isParty ? $t('challengeDetails') : $t('privateDescription')",
target="groupPrivateDescOrChallengeInfo",
)
.col-2
.toggle-up(@click="sections.challenges = !sections.challenges", v-if="sections.challenges")
.svg-icon(v-html="icons.upIcon")
.toggle-down(@click="sections.challenges = !sections.challenges", v-if="!sections.challenges")
.svg-icon(v-html="icons.downIcon")
.section(v-if="sections.challenges")
group-challenges(:groupId='searchId') group-challenges(:groupId='searchId')
div.text-center div.text-center
button.btn.btn-danger(v-if='isMember', @click='clickLeave()') {{ isParty ? $t('leaveParty') : $t('leaveGroup') }} button.btn.btn-danger(v-if='isMember', @click='clickLeave()') {{ isParty ? $t('leaveParty') : $t('leaveGroup') }}
@@ -124,10 +86,6 @@
color: $purple-200; color: $purple-200;
} }
.leader:hover {
cursor: pointer;
}
.button-container { .button-container {
margin-bottom: 1em; margin-bottom: 1em;
@@ -270,29 +228,6 @@
margin-right: .3em; margin-right: .3em;
} }
.information-header {
h3, .tooltip-wrapper {
display: inline-block;
}
.tooltip-wrapper {
width: 15px;
margin-left: 1.2em;
}
}
.section-header {
border-top: 1px solid #e1e0e3;
margin-top: 1em;
padding-top: 1em;
}
.section-header.challenge {
border-bottom: 1px solid #e1e0e3;
margin-bottom: 1em;
padding-bottom: 1em;
}
.hr { .hr {
width: 100%; width: 100%;
height: 20px; height: 20px;
@@ -316,7 +251,6 @@
<script> <script>
// @TODO: Break this down into components // @TODO: Break this down into components
import debounce from 'lodash/debounce';
import extend from 'lodash/extend'; import extend from 'lodash/extend';
import groupUtilities from 'client/mixins/groupsUtilities'; import groupUtilities from 'client/mixins/groupsUtilities';
import styleHelper from 'client/mixins/styleHelper'; import styleHelper from 'client/mixins/styleHelper';
@@ -327,13 +261,13 @@ import startQuestModal from './startQuestModal';
import questDetailsModal from './questDetailsModal'; import questDetailsModal from './questDetailsModal';
import groupFormModal from './groupFormModal'; import groupFormModal from './groupFormModal';
import inviteModal from './inviteModal'; import inviteModal from './inviteModal';
import chatMessage from '../chat/chatMessages';
import autocomplete from '../chat/autoComplete';
import groupChallenges from '../challenges/groupChallenges'; import groupChallenges from '../challenges/groupChallenges';
import groupGemsModal from 'client/components/groups/groupGemsModal'; import groupGemsModal from 'client/components/groups/groupGemsModal';
import questSidebarSection from 'client/components/groups/questSidebarSection'; import questSidebarSection from 'client/components/groups/questSidebarSection';
import markdownDirective from 'client/directives/markdown'; import markdownDirective from 'client/directives/markdown';
import communityGuidelines from './communityGuidelines'; import chat from './chat';
import sidebarSection from '../sidebarSection';
import userLink from '../userLink';
import deleteIcon from 'assets/svg/delete.svg'; import deleteIcon from 'assets/svg/delete.svg';
import copyIcon from 'assets/svg/copy.svg'; import copyIcon from 'assets/svg/copy.svg';
@@ -342,10 +276,7 @@ import likedIcon from 'assets/svg/liked.svg';
import reportIcon from 'assets/svg/report.svg'; import reportIcon from 'assets/svg/report.svg';
import gemIcon from 'assets/svg/gem.svg'; import gemIcon from 'assets/svg/gem.svg';
import questIcon from 'assets/svg/quest.svg'; import questIcon from 'assets/svg/quest.svg';
import informationIcon from 'assets/svg/information.svg';
import questBackground from 'assets/svg/quest-background-border.svg'; import questBackground from 'assets/svg/quest-background-border.svg';
import upIcon from 'assets/svg/up.svg';
import downIcon from 'assets/svg/down.svg';
import goldGuildBadgeIcon from 'assets/svg/gold-guild-badge-small.svg'; import goldGuildBadgeIcon from 'assets/svg/gold-guild-badge-small.svg';
import silverGuildBadgeIcon from 'assets/svg/silver-guild-badge-small.svg'; import silverGuildBadgeIcon from 'assets/svg/silver-guild-badge-small.svg';
import bronzeGuildBadgeIcon from 'assets/svg/bronze-guild-badge-small.svg'; import bronzeGuildBadgeIcon from 'assets/svg/bronze-guild-badge-small.svg';
@@ -357,14 +288,14 @@ export default {
membersModal, membersModal,
startQuestModal, startQuestModal,
groupFormModal, groupFormModal,
chatMessage,
inviteModal, inviteModal,
groupChallenges, groupChallenges,
autocomplete,
questDetailsModal, questDetailsModal,
groupGemsModal, groupGemsModal,
questSidebarSection, questSidebarSection,
communityGuidelines, sidebarSection,
userLink,
chat,
}, },
directives: { directives: {
markdown: markdownDirective, markdown: markdownDirective,
@@ -381,26 +312,16 @@ export default {
gem: gemIcon, gem: gemIcon,
liked: likedIcon, liked: likedIcon,
questIcon, questIcon,
information: informationIcon,
questBackground, questBackground,
upIcon,
downIcon,
goldGuildBadgeIcon, goldGuildBadgeIcon,
silverGuildBadgeIcon, silverGuildBadgeIcon,
bronzeGuildBadgeIcon, bronzeGuildBadgeIcon,
}), }),
members: [], members: [],
selectedQuest: {}, selectedQuest: {},
sections: { chat: {
quest: true, submitDisable: false,
summary: true, submitTimeout: null,
description: true,
challenges: true,
},
newMessage: '',
coords: {
TOP: 0,
LEFT: 0,
}, },
}; };
}, },
@@ -452,13 +373,6 @@ export default {
beforeRouteUpdate (to, from, next) { beforeRouteUpdate (to, from, next) {
this.$set(this, 'searchId', to.params.groupId); this.$set(this, 'searchId', to.params.groupId);
// Reset chat
this.newMessage = '';
this.coords = {
TOP: 0,
LEFT: 0,
};
next(); next();
}, },
watch: { watch: {
@@ -510,40 +424,6 @@ export default {
return this.$store.dispatch('members:getGroupMembers', payload); return this.$store.dispatch('members:getGroupMembers', payload);
}, },
// @TODO: abstract autocomplete
// https://medium.com/@_jh3y/how-to-where-s-the-caret-getting-the-xy-position-of-the-caret-a24ba372990a
getCoord (e, text) {
let carPos = text.selectionEnd;
let div = document.createElement('div');
let span = document.createElement('span');
let 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, carPos);
span.textContent = text.value.substr(carPos) || '.';
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) {
let text = eventUpdate.target;
this.getCoord(eventUpdate, text);
},
selectedAutocomplete (newText) {
this.newMessage = newText;
},
showMemberModal () { showMemberModal () {
this.$store.state.memberModalOptions.groupId = this.group._id; this.$store.state.memberModalOptions.groupId = this.group._id;
this.$store.state.memberModalOptions.group = this.group; this.$store.state.memberModalOptions.group = this.group;
@@ -552,22 +432,9 @@ export default {
this.$store.state.memberModalOptions.fetchMoreMembers = this.loadMembers; this.$store.state.memberModalOptions.fetchMoreMembers = this.loadMembers;
this.$root.$emit('bv::show::modal', 'members-modal'); this.$root.$emit('bv::show::modal', 'members-modal');
}, },
async sendMessage () {
if (!this.newMessage) return;
let response = await this.$store.dispatch('chat:postChat', {
group: this.group,
message: this.newMessage,
});
this.group.chat.unshift(response.message);
this.newMessage = '';
},
fetchRecentMessages () { fetchRecentMessages () {
this.fetchGuild(); this.fetchGuild();
}, },
reverseChat () {
this.group.chat.reverse();
},
updateGuild () { updateGuild () {
this.$store.state.editingGroup = this.group; this.$store.state.editingGroup = this.group;
this.$root.$emit('bv::show::modal', 'guild-form'); this.$root.$emit('bv::show::modal', 'guild-form');
@@ -688,19 +555,9 @@ export default {
} }
// $rootScope.$state.go('options.inventory.quests'); // $rootScope.$state.go('options.inventory.quests');
}, },
async showMemberProfile (leader) {
let heroDetails = await this.$store.dispatch('members:fetchMember', { memberId: leader._id });
this.$root.$emit('habitica:show-profile', {
user: heroDetails.data.data,
startingPage: 'profile',
});
},
showGroupGems () { showGroupGems () {
this.$root.$emit('bv::show::modal', 'group-gems-modal'); this.$root.$emit('bv::show::modal', 'group-gems-modal');
}, },
toggleQuestSection () {
this.sections.quest = !this.sections.quest;
},
}, },
}; };
</script> </script>

View File

@@ -10,13 +10,18 @@ div
.col-6 .col-6
button(type="button" aria-label="Close" class="close", @click='close()') button(type="button" aria-label="Close" class="close", @click='close()')
span(aria-hidden="true") × span(aria-hidden="true") ×
.row .row.d-flex.align-items-center
.form-group.col-6 .col-4
input.form-control.search(type="text", :placeholder="$t('search')", v-model='searchTerm') input.form-control.input-search(type="text", :placeholder="$t('search')", v-model='searchTerm')
.col-5.offset-1 .col
span.dropdown-label {{ $t('sortBy') }} select.form-control(@change='changeSortOption($event)')
b-dropdown(:text="$t('sort')", right=true) option(v-for='sortOption in sortOptions', :value='sortOption.value') {{sortOption.text}}
b-dropdown-item(v-for='sortOption in sortOptions', @click='sort(sortOption)', :key='sortOption.value') {{sortOption.text}} .col-3
select.form-control(@change='changeSortDirection($event)')
option(v-for='sortDirection in sortDirections', :value='sortDirection.value') {{sortDirection.text}}
.row.apply-options.d-flex.justify-content-center(v-if='sortDirty')
a(@click='applySortOptions()') {{ $t('applySortToHeader') }}
.row(v-if='invites.length > 0') .row(v-if='invites.length > 0')
.col-6.offset-3.nav .col-6.offset-3.nav
.nav-item(@click='viewMembers()', :class="{active: selectedPage === 'members'}") {{ $t('members') }} .nav-item(@click='viewMembers()', :class="{active: selectedPage === 'members'}") {{ $t('members') }}
@@ -69,14 +74,30 @@ div
<style lang='scss'> <style lang='scss'>
#members-modal { #members-modal {
.modal-header {
background-color: #edecee;
border-radius: 8px 8px 0 0;
box-shadow: 0 1px 2px 0 rgba(26, 24, 29, 0.24);
}
.modal-footer {
background-color: #edecee;
border-radius: 0 0 8px 8px;
}
.small-text, .character-name { .small-text, .character-name {
color: #878190; color: #878190;
} }
.no-padding-left, .modal-body { .no-padding-left {
padding-left: 0; padding-left: 0;
} }
.modal-body {
padding-left: 0;
padding-right: 0;
}
.member-details { .member-details {
margin: 0; margin: 0;
} }
@@ -88,15 +109,21 @@ div
</style> </style>
<style lang='scss' scoped> <style lang='scss' scoped>
header { .apply-options {
background-color: #edecee; padding: 1em;
border-radius: 4px 4px 0 0; margin: 0;
background-color: #f9f9f9;
color: #2995cd;
} }
.header-wrap { .header-wrap {
width: 100%; width: 100%;
} }
.form-control {
font-size: 0.9rem;
}
h1 { h1 {
color: #4f2a93; color: #4f2a93;
} }
@@ -172,7 +199,6 @@ div
</style> </style>
<script> <script>
// import sortBy from "lodash/sortBy";
import orderBy from 'lodash/orderBy'; import orderBy from 'lodash/orderBy';
import isEmpty from 'lodash/isEmpty'; import isEmpty from 'lodash/isEmpty';
import { mapState } from 'client/libs/store'; import { mapState } from 'client/libs/store';
@@ -193,82 +219,49 @@ export default {
data () { data () {
return { return {
sortOption: {}, sortOption: {},
sortDirty: false,
selectedPage: 'members', selectedPage: 'members',
members: [], members: [],
invites: [], invites: [],
memberToRemove: {}, memberToRemove: {},
sortOptions: [ sortOptions: [
{ {
value: 'class', value: 'stats.class',
text: this.$t('class'), text: this.$t('sortClass'),
order: 'asc',
param: 'stats.class',
}, },
{ {
value: 'background', value: 'preferences.background',
text: this.$t('background'), text: this.$t('sortBackground'),
order: 'asc',
param: 'preferences.background',
}, },
{ {
value: 'date-joined-asc', value: 'auth.timestamps.created',
text: this.$t('sortDateJoinedAsc'), text: this.$t('sortDateJoined'),
order: 'asc',
param: 'auth.timestamps.created',
}, },
{ {
value: 'date-joined-desc', value: 'auth.timestamps.loggedin',
text: this.$t('sortDateJoinedDesc'), text: this.$t('sortLogin'),
order: 'desc',
param: 'auth.timestamps.created',
}, },
{ {
value: 'login-asc', value: 'stats.lvl',
text: this.$t('sortLoginAsc'), text: this.$t('sortLevel'),
order: 'asc',
param: 'auth.timestamps.loggedin',
}, },
{ {
value: 'login-desc', value: 'profile.name',
text: this.$t('sortLoginDesc'), text: this.$t('sortName'),
order: 'desc',
param: 'auth.timestamps.loggedin',
}, },
{ {
value: 'level-asc', value: 'contributor.level',
text: this.$t('sortLevelAsc'), text: this.$t('sortTier'),
order: 'asc', },
param: 'stats.lvl', ],
sortDirections: [
{
value: 'asc',
text: this.$t('ascendingAbbrev'),
}, },
{ {
value: 'level-desc', value: 'desc',
text: this.$t('sortLevelDesc'), text: this.$t('descendingAbbrev'),
order: 'desc',
param: 'stats.lvl',
},
{
value: 'name-asc',
text: this.$t('sortNameAsc'),
order: 'asc',
param: 'profile.name',
},
{
value: 'name-desc',
text: this.$t('sortNameDesc'),
order: 'desc',
param: 'profile.name',
},
{
value: 'tier-asc',
text: this.$t('sortTierAsc'),
order: 'asc',
param: 'contributor.level',
},
{
value: 'tier-desc',
text: this.$t('sortTierDesc'),
order: 'desc',
param: 'contributor.level',
}, },
], ],
searchTerm: '', searchTerm: '',
@@ -318,7 +311,7 @@ export default {
if (!isEmpty(this.sortOption)) { if (!isEmpty(this.sortOption)) {
// Use the memberlist filtered by searchTerm // Use the memberlist filtered by searchTerm
sortedMembers = orderBy(sortedMembers, [this.sortOption.param], [this.sortOption.order]); sortedMembers = orderBy(sortedMembers, [this.sortOption.value], [this.sortOption.direction]);
} }
return sortedMembers; return sortedMembers;
@@ -424,8 +417,25 @@ export default {
close () { close () {
this.$root.$emit('bv::hide::modal', 'members-modal'); this.$root.$emit('bv::hide::modal', 'members-modal');
}, },
sort (option) { changeSortOption (e) {
this.sortOption = option; this.sortOption.value = e.target.value;
this.sort();
},
changeSortDirection (e) {
this.sortOption.direction = e.target.value;
this.sort();
},
sort () {
this.sortDirty = true;
this.members = orderBy(this.members, [this.sortOption.value], [this.sortOption.direction]);
},
async applySortOptions () {
const settings = {
'party.order': this.sortOption.value,
'party.orderAscending': this.sortOption.direction,
};
await this.$store.dispatch('user:set', settings);
this.sortDirty = false;
}, },
async loadMoreMembers () { async loadMoreMembers () {
const lastMember = this.members[this.members.length - 1]; const lastMember = this.members[this.members.length - 1];

View File

@@ -24,9 +24,7 @@ router-link.card-link(:to="{ name: 'guild', params: { groupId: guild._id } }")
span.count {{ guild.balance * 4 }} span.count {{ guild.balance * 4 }}
div.guild-bank(v-if='displayGemBank', v-once) {{$t('guildBank')}} div.guild-bank(v-if='displayGemBank', v-once) {{$t('guildBank')}}
.row .row
.col-md-12 category-tags.col-md-12(:categories="guild.categories", :owner="isOwner", v-once)
.category-label(v-for="category in guild.categorySlugs")
| {{$t(category)}}
span.recommend-text(v-if='showSuggested(guild._id)') Suggested because youre new to Habitica. span.recommend-text(v-if='showSuggested(guild._id)') Suggested because youre new to Habitica.
</template> </template>
@@ -128,6 +126,7 @@ router-link.card-link(:to="{ name: 'guild', params: { groupId: guild._id } }")
<script> <script>
import moment from 'moment'; import moment from 'moment';
import { mapState } from 'client/libs/store'; import { mapState } from 'client/libs/store';
import categoryTags from '../categories/categoryTags';
import groupUtilities from 'client/mixins/groupsUtilities'; import groupUtilities from 'client/mixins/groupsUtilities';
import markdown from 'client/directives/markdown'; import markdown from 'client/directives/markdown';
import gemIcon from 'assets/svg/gem.svg'; import gemIcon from 'assets/svg/gem.svg';
@@ -142,8 +141,14 @@ export default {
markdown, markdown,
}, },
props: ['guild', 'displayLeave', 'displayGemBank'], props: ['guild', 'displayLeave', 'displayGemBank'],
components: {
categoryTags,
},
computed: { computed: {
...mapState({user: 'user.data'}), ...mapState({user: 'user.data'}),
isOwner () {
return this.guild.leader && this.guild.leader === this.user._id;
},
isMember () { isMember () {
return this.isMemberOfGroup(this.user, this.guild); return this.isMemberOfGroup(this.user, this.guild);
}, },

View File

@@ -1,74 +1,65 @@
<template lang="pug"> <template lang="pug">
div sidebar-section(:title="$t('questDetailsTitle')")
.row .row.no-quest-section(v-if='!onPendingQuest && !onActiveQuest')
.col-10 .col-12.text-center
h3(v-once) {{ $t('questDetailsTitle') }} .svg-icon(v-html="icons.questIcon")
h4(v-once) {{ $t('youAreNotOnQuest') }}
p(v-once) {{ $t('questDescription') }}
button.btn.btn-secondary(v-once, @click="openStartQuestModal()") {{ $t('startAQuest') }}
.row.quest-active-section(v-if='onPendingQuest && !onActiveQuest')
.col-2 .col-2
.toggle-up(@click="toggle()", v-if="show") .quest(:class='`inventory_quest_scroll_${questData.key}`')
.svg-icon(v-html="icons.upIcon") .col-6.titles
.toggle-down(@click="toggle()", v-if="!show") strong {{ questData.text() }}
.svg-icon(v-html="icons.downIcon") p {{acceptedCount}} / {{group.memberCount}}
.section(v-if="show") .col-4
.row.no-quest-section(v-if='!onPendingQuest && !onActiveQuest') button.btn.btn-secondary(@click="openQuestDetails()") {{ $t('details') }}
.col-12.text-center .row.quest-active-section.quest-invite(v-if='user.party.quest && user.party.quest.RSVPNeeded')
.svg-icon(v-html="icons.questIcon") span {{ $t('wouldYouParticipate') }}
h4(v-once) {{ $t('youAreNotOnQuest') }} button.btn.btn-primary.accept(@click='questAccept(group._id)') {{$t('accept')}}
p(v-once) {{ $t('questDescription') }} button.btn.btn-primary.reject(@click='questReject(group._id)') {{$t('reject')}}
button.btn.btn-secondary(v-once, @click="openStartQuestModal()") {{ $t('startAQuest') }} .row.quest-active-section(v-if='!onPendingQuest && onActiveQuest')
.row.quest-active-section(v-if='onPendingQuest && !onActiveQuest') .col-12.text-center
.col-2 .quest-boss(:class="'quest_' + questData.key")
.quest(:class='`inventory_quest_scroll_${questData.key}`') h3(v-once) {{ questData.text() }}
.col-6.titles .quest-box
strong {{ questData.text() }} .collect-info(v-if='questData.collect')
p {{acceptedCount}} / {{group.memberCount}} .row(v-for='(value, key) in questData.collect')
.col-4 .col-2
button.btn.btn-secondary(@click="openQuestDetails()") {{ $t('details') }} div(:class="'quest_' + questData.key + '_' + key")
.row.quest-active-section.quest-invite(v-if='user.party.quest && user.party.quest.RSVPNeeded') .col-10
span {{ $t('wouldYouParticipate') }} strong {{value.text()}}
button.btn.btn-primary.accept(@click='questAccept(group._id)') {{$t('accept')}} .grey-progress-bar
button.btn.btn-primary.reject(@click='questReject(group._id)') {{$t('reject')}} .collect-progress-bar(:style="{width: (group.quest.progress.collect[key] / value.count) * 100 + '%'}")
.row.quest-active-section(v-if='!onPendingQuest && onActiveQuest') strong {{group.quest.progress.collect[key]}} / {{value.count}}
.col-12.text-center div.text-right {{parseFloat(user.party.quest.progress.collectedItems) || 0}} items found
.quest-boss(:class="'quest_' + questData.key") .boss-info(v-if='questData.boss')
h3(v-once) {{ questData.text() }} .row
.quest-box .col-6
.collect-info(v-if='questData.collect') h4.float-left(v-once) {{ questData.boss.name() }}
.row(v-for='(value, key) in questData.collect') .col-6
.col-2 span.float-right(v-once) {{ $t('participantsTitle') }}
div(:class="'quest_' + questData.key + '_' + key") .row
.col-10 .col-12
strong {{value.text()}} .grey-progress-bar
.grey-progress-bar .boss-health-bar(:style="{width: bossHpPercent + '%'}")
.collect-progress-bar(:style="{width: (group.quest.progress.collect[key] / value.count) * 100 + '%'}") .row.boss-details
strong {{group.quest.progress.collect[key]}} / {{value.count}} .col-6
div.text-right {{parseFloat(user.party.quest.progress.collectedItems) || 0}} items found span.float-left
.boss-info(v-if='questData.boss') | {{ Math.ceil(parseFloat(group.quest.progress.hp) * 100) / 100 }} / {{ parseFloat(questData.boss.hp).toFixed(2) }}
.row // current boss hp uses ceil so you don't underestimate damage needed to end quest
.col-6(v-if='userIsOnQuest')
// @TODO: Why do we not sync quest progress on the group doc? Each user could have different progress.
span.float-right {{ user.party.quest.progress.up | floor(10) }} {{ $t('pendingDamageLabel') }}
// player's pending damage uses floor so you don't overestimate damage you've already done
.row.rage-bar-row(v-if='questData.boss.rage')
.col-12
.grey-progress-bar
.boss-health-bar.rage-bar(:style="{width: (group.quest.progress.rage / questData.boss.rage.value) * 100 + '%'}")
.row.boss-details.rage-details(v-if='questData.boss.rage')
.col-6 .col-6
h4.float-left(v-once) {{ questData.boss.name() }} span.float-left {{ $t('rage') }} {{ parseFloat(group.quest.progress.rage).toFixed(2) }} / {{ questData.boss.rage.value }}
.col-6 button.btn.btn-secondary(v-once, @click="questAbort()", v-if='canEditQuest') {{ $t('abort') }}
span.float-right(v-once) {{ $t('participantsTitle') }}
.row
.col-12
.grey-progress-bar
.boss-health-bar(:style="{width: (group.quest.progress.hp / questData.boss.hp) * 100 + '%'}")
.row.boss-details
.col-6
span.float-left
| {{ Math.ceil(parseFloat(group.quest.progress.hp) * 100) / 100 }} / {{ parseFloat(questData.boss.hp).toFixed(2) }}
// current boss hp uses ceil so you don't underestimate damage needed to end quest
.col-6(v-if='userIsOnQuest')
// @TODO: Why do we not sync quest progress on the group doc? Each user could have different progress.
span.float-right {{ user.party.quest.progress.up | floor(10) }} {{ $t('pendingDamageLabel') }}
// player's pending damage uses floor so you don't overestimate damage you've already done
.row.rage-bar-row(v-if='questData.boss.rage')
.col-12
.grey-progress-bar
.boss-health-bar.rage-bar(:style="{width: (group.quest.progress.rage / questData.boss.rage.value) * 100 + '%'}")
.row.boss-details.rage-details(v-if='questData.boss.rage')
.col-6
span.float-left {{ $t('rage') }} {{ parseFloat(group.quest.progress.rage).toFixed(2) }} / {{ questData.boss.rage.value }}
button.btn.btn-secondary(v-once, @click="questAbort()", v-if='canEditQuest') {{ $t('abort') }}
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
@@ -193,18 +184,18 @@ import { mapState } from 'client/libs/store';
import quests from 'common/script/content/quests'; import quests from 'common/script/content/quests';
import percent from 'common/script/libs/percent'; import percent from 'common/script/libs/percent';
import sidebarSection from '../sidebarSection';
import upIcon from 'assets/svg/up.svg';
import downIcon from 'assets/svg/down.svg';
import questIcon from 'assets/svg/quest.svg'; import questIcon from 'assets/svg/quest.svg';
export default { export default {
props: ['show', 'group'], props: ['group'],
components: {
sidebarSection,
},
data () { data () {
return { return {
icons: Object.freeze({ icons: Object.freeze({
upIcon,
downIcon,
questIcon, questIcon,
}), }),
}; };
@@ -261,9 +252,6 @@ export default {
}, },
}, },
methods: { methods: {
toggle () {
this.$emit('toggle');
},
openStartQuestModal () { openStartQuestModal () {
this.$root.$emit('bv::show::modal', 'start-quest-modal'); this.$root.$emit('bv::show::modal', 'start-quest-modal');
}, },

View File

@@ -6,7 +6,7 @@
form form
h2(v-once) {{ $t('filter') }} h2(v-once) {{ $t('filter') }}
.form-group .form-group
h3 Category h3 {{ $t('category') }}
.form-check( .form-check(
v-for="group in categoryOptions", v-for="group in categoryOptions",
:key="group.key", :key="group.key",
@@ -15,7 +15,7 @@
input.custom-control-input(type="checkbox", :value='group.key' v-model="categoryFilters", :id="group.key") input.custom-control-input(type="checkbox", :value='group.key' v-model="categoryFilters", :id="group.key")
label.custom-control-label(v-once, :for="group.key") {{ $t(group.label) }} label.custom-control-label(v-once, :for="group.key") {{ $t(group.label) }}
.form-group .form-group
h3 Role h3 {{ $t('role') }}
.form-check( .form-check(
v-for="group in roleOptions", v-for="group in roleOptions",
:key="group.key", :key="group.key",
@@ -24,7 +24,7 @@
input.custom-control-input(type="checkbox", :value='group.key' v-model="roleFilters", :id="group.key") input.custom-control-input(type="checkbox", :value='group.key' v-model="roleFilters", :id="group.key")
label.custom-control-label(v-once, :for="group.key") {{ $t(group.label) }} label.custom-control-label(v-once, :for="group.key") {{ $t(group.label) }}
.form-group .form-group
h3 Guild Size h3 {{ $t('guildSize') }}
.form-check( .form-check(
v-for="group in guildSizeOptions", v-for="group in guildSizeOptions",
:key="group.key", :key="group.key",

View File

@@ -7,26 +7,12 @@
.col-6.title-details .col-6.title-details
h1(v-once) {{ $t('welcomeToTavern') }} h1(v-once) {{ $t('welcomeToTavern') }}
.row.chat-row chat(
.col-12 :label="$t('tavernChat')",
h3(v-once) {{ $t('tavernChat') }} :group="group",
:placeholder="$t('tavernCommunityGuidelinesPlaceholder')",
.row @fetchRecentMessages="fetchRecentMessages()"
textarea(:placeholder="$t('tavernCommunityGuidelinesPlaceholder')", v-model='newMessage', :class='{"user-entry": newMessage}', @keydown='updateCarretPosition', @keyup.ctrl.enter='sendMessage()') )
autocomplete(:text='newMessage', v-on:select="selectedAutocomplete", :coords='coords', :chat='group.chat')
.row
.col-6
button.btn.btn-secondary.float-left.fetch(v-once, @click='fetchRecentMessages()') {{ $t('fetchRecentMessages') }}
button.btn.btn-secondary.float-left(v-once, @click='reverseChat()') {{ $t('reverseChat') }}
.col-6
button.btn.btn-secondary.send-chat.float-right(v-once, @click='sendMessage()') {{ $t('send') }}
community-guidelines
.row
.hr.col-12
chat-message(:chat.sync='group.chat', :group-id='group._id', :group-name='group.name')
.col-12.col-sm-4.sidebar .col-12.col-sm-4.sidebar
.section .section
.grassy-meadow-backdrop .grassy-meadow-backdrop
@@ -102,18 +88,9 @@
li(v-once) {{ $t('sleepBullet4') }} li(v-once) {{ $t('sleepBullet4') }}
button.btn.btn-secondary.pause-button(v-if='!user.preferences.sleep', @click='toggleSleep()', v-once) {{ $t('pauseDailies') }} button.btn.btn-secondary.pause-button(v-if='!user.preferences.sleep', @click='toggleSleep()', v-once) {{ $t('pauseDailies') }}
button.btn.btn-secondary.pause-button(v-if='user.preferences.sleep', @click='toggleSleep()', v-once) {{ $t('unpauseDailies') }} button.btn.btn-secondary.pause-button(v-if='user.preferences.sleep', @click='toggleSleep()', v-once) {{ $t('unpauseDailies') }}
.px-3
.below-header-sections sidebar-section(:title="$t('staffAndModerators')")
.section-header
.row .row
.col-10
h3(v-once) {{ $t('staffAndModerators') }}
.col-2
.toggle-up(@click="sections.staff = !sections.staff", v-if="sections.staff")
.svg-icon(v-html="icons.upIcon")
.toggle-down(@click="sections.staff = !sections.staff", v-if="!sections.staff")
.svg-icon(v-html="icons.downIcon")
.section.row(v-if="sections.staff")
.col-4.staff(v-for='user in staff', :class='{staff: user.type === "Staff", moderator: user.type === "Moderator", bailey: user.name === "It\'s Bailey"}') .col-4.staff(v-for='user in staff', :class='{staff: user.type === "Staff", moderator: user.type === "Moderator", bailey: user.name === "It\'s Bailey"}')
div div
a.title(@click="viewStaffProfile(user.uuid)") {{user.name}} a.title(@click="viewStaffProfile(user.uuid)") {{user.name}}
@@ -122,50 +99,33 @@
.svg-icon.npc-icon(v-html="icons.tierNPC", v-if='user.name === "It\'s Bailey"') .svg-icon.npc-icon(v-html="icons.tierNPC", v-if='user.name === "It\'s Bailey"')
.type {{user.type}} .type {{user.type}}
.section-header sidebar-section(:title="$t('helpfulLinks')")
.row ul
.col-10 li
h3(v-once) {{ $t('helpfulLinks') }} a(href='', @click.prevent='modForm()') {{ $t('contactForm') }}
.col-2 li
.toggle-up(@click="sections.helpfulLinks = !sections.helpfulLinks", v-if="sections.helpfulLinks") router-link(to='/static/community-guidelines', v-once) {{ $t('communityGuidelinesLink') }}
.svg-icon(v-html="icons.upIcon") li
.toggle-down(@click="sections.helpfulLinks = !sections.helpfulLinks", v-if="!sections.helpfulLinks") router-link(to="/groups/guild/f2db2a7f-13c5-454d-b3ee-ea1f5089e601") {{ $t('lookingForGroup') }}
.svg-icon(v-html="icons.downIcon") li
.section.row(v-if="sections.helpfulLinks") router-link(to='/static/faq', v-once) {{ $t('faq') }}
ul li
li a(href='', v-html="$t('glossary')")
a(href='', @click.prevent='modForm()') {{ $t('contactForm') }} li
li a(href='http://habitica.wikia.com/wiki/Habitica_Wiki', v-once) {{ $t('wiki') }}
router-link(to='/static/community-guidelines', v-once) {{ $t('communityGuidelinesLink') }} li
li a(href='https://oldgods.net/habitrpg/habitrpg_user_data_display.html', v-once) {{ $t('dataDisplayTool') }}
router-link(to="/groups/guild/f2db2a7f-13c5-454d-b3ee-ea1f5089e601") {{ $t('lookingForGroup') }} li
li router-link(to="/groups/guild/a29da26b-37de-4a71-b0c6-48e72a900dac") {{ $t('reportProblem') }}
router-link(to='/static/faq', v-once) {{ $t('faq') }} li
li a(href='https://trello.com/c/odmhIqyW/440-read-first-table-of-contents', v-once) {{ $t('requestFeature') }}
a(href='', v-html="$t('glossary')") li
li a(href='', v-html="$t('communityForum')")
a(href='http://habitica.wikia.com/wiki/Habitica_Wiki', v-once) {{ $t('wiki') }} li
li router-link(to="/groups/guild/5481ccf3-5d2d-48a9-a871-70a7380cee5a") {{ $t('askQuestionGuild') }}
a(href='https://oldgods.net/habitrpg/habitrpg_user_data_display.html', v-once) {{ $t('dataDisplayTool') }}
li
router-link(to="/groups/guild/a29da26b-37de-4a71-b0c6-48e72a900dac") {{ $t('reportProblem') }}
li
a(href='https://trello.com/c/odmhIqyW/440-read-first-table-of-contents', v-once) {{ $t('requestFeature') }}
li
a(href='', v-html="$t('communityForum')")
li
router-link(to="/groups/guild/5481ccf3-5d2d-48a9-a871-70a7380cee5a") {{ $t('askQuestionGuild') }}
.section-header sidebar-section(:title="$t('playerTiers')")
.row .row
.col-10
h3(v-once) {{ $t('playerTiers') }}
.col-2
.toggle-up(@click="sections.playerTiers = !sections.playerTiers", v-if="sections.playerTiers")
.svg-icon(v-html="icons.upIcon")
.toggle-down(@click="sections.playerTiers = !sections.playerTiers", v-if="!sections.playerTiers")
.svg-icon(v-html="icons.downIcon")
.section.row(v-if="sections.playerTiers")
.col-12 .col-12
p(v-once) {{ $t('playerTiersDesc') }} p(v-once) {{ $t('playerTiersDesc') }}
ul.tier-list ul.tier-list
@@ -205,49 +165,6 @@
@import '~client/assets/scss/colors.scss'; @import '~client/assets/scss/colors.scss';
@import '~client/assets/scss/variables.scss'; @import '~client/assets/scss/variables.scss';
.chat-row {
position: relative;
textarea {
height: 150px;
width: 100%;
background-color: $white;
border: solid 1px $gray-400;
font-size: 16px;
font-style: italic;
line-height: 1.43;
color: $gray-300;
padding: .5em;
}
.user-entry {
font-style: normal;
color: $black;
}
.hr {
width: 100%;
height: 20px;
border-bottom: 1px solid $gray-500;
text-align: center;
margin: 2em 0;
}
.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;
}
}
h1 { h1 {
color: $purple-200; color: $purple-200;
} }
@@ -267,10 +184,6 @@
width: 100%; width: 100%;
} }
.section-header {
margin-top: 2em;
}
.grassy-meadow-backdrop { .grassy-meadow-backdrop {
background-image: url('~assets/images/npc/#{$npc_tavern_flavor}/tavern_background.png'); background-image: url('~assets/images/npc/#{$npc_tavern_flavor}/tavern_background.png');
background-repeat: repeat-x; background-repeat: repeat-x;
@@ -515,27 +428,24 @@
</style> </style>
<script> <script>
import debounce from 'lodash/debounce';
import { mapState } from 'client/libs/store'; import { mapState } from 'client/libs/store';
import { goToModForm } from 'client/libs/modform'; import { goToModForm } from 'client/libs/modform';
import { TAVERN_ID } from '../../../common/script/constants'; import { TAVERN_ID } from '../../../common/script/constants';
import chatMessage from '../chat/chatMessages';
import autocomplete from '../chat/autoComplete';
import communityGuidelines from './communityGuidelines';
import worldBossInfoModal from '../world-boss/worldBossInfoModal'; import worldBossInfoModal from '../world-boss/worldBossInfoModal';
import worldBossRageModal from '../world-boss/worldBossRageModal'; import worldBossRageModal from '../world-boss/worldBossRageModal';
import sidebarSection from '../sidebarSection';
import chat from './chat';
import challengeIcon from 'assets/svg/challenge.svg'; import challengeIcon from 'assets/svg/challenge.svg';
import chevronIcon from 'assets/svg/chevron-red.svg'; import chevronIcon from 'assets/svg/chevron-red.svg';
import downIcon from 'assets/svg/down.svg';
import gemIcon from 'assets/svg/gem.svg'; import gemIcon from 'assets/svg/gem.svg';
import healthIcon from 'assets/svg/health.svg'; import healthIcon from 'assets/svg/health.svg';
import informationIconRed from 'assets/svg/information-red.svg'; import informationIconRed from 'assets/svg/information-red.svg';
import questBackground from 'assets/svg/quest-background-border.svg'; import questBackground from 'assets/svg/quest-background-border.svg';
import rageIcon from 'assets/svg/rage.svg'; import rageIcon from 'assets/svg/rage.svg';
import swordIcon from 'assets/svg/sword.svg'; import swordIcon from 'assets/svg/sword.svg';
import upIcon from 'assets/svg/up.svg';
import tier1 from 'assets/svg/tier-1.svg'; import tier1 from 'assets/svg/tier-1.svg';
import tier2 from 'assets/svg/tier-2.svg'; import tier2 from 'assets/svg/tier-2.svg';
@@ -549,14 +459,14 @@ import tierNPC from 'assets/svg/tier-npc.svg';
import tierStaff from 'assets/svg/tier-staff.svg'; import tierStaff from 'assets/svg/tier-staff.svg';
import quests from 'common/script/content/quests'; import quests from 'common/script/content/quests';
import staffList from '../../libs/staffList';
export default { export default {
components: { components: {
chatMessage,
autocomplete,
communityGuidelines,
worldBossInfoModal, worldBossInfoModal,
worldBossRageModal, worldBossRageModal,
sidebarSection,
chat,
}, },
data () { data () {
return { return {
@@ -564,7 +474,6 @@ export default {
icons: Object.freeze({ icons: Object.freeze({
challengeIcon, challengeIcon,
chevronIcon, chevronIcon,
downIcon,
gem: gemIcon, gem: gemIcon,
healthIcon, healthIcon,
informationIcon: informationIconRed, informationIcon: informationIconRed,
@@ -581,119 +490,14 @@ export default {
tierMod, tierMod,
tierNPC, tierNPC,
tierStaff, tierStaff,
upIcon,
}), }),
group: { group: {
chat: [], chat: [],
}, },
sections: { sections: {
staff: true,
helpfulLinks: true,
playerTiers: true,
worldBoss: true, worldBoss: true,
}, },
staff: [ staff: staffList,
{
name: 'beffymaroo',
type: 'Staff',
uuid: '9fe7183a-4b79-4c15-9629-a1aee3873390',
},
// {
// name: 'lefnire',
// type: 'Staff',
// uuid: '00000000-0000-4000-9000-000000000000',
// },
{
name: 'Lemoness',
type: 'Staff',
uuid: '7bde7864-ebc5-4ee2-a4b7-1070d464cdb0',
},
{
name: 'paglias',
type: 'Staff',
uuid: 'ed4c688c-6652-4a92-9d03-a5a79844174a',
},
{
name: 'redphoenix',
type: 'Staff',
uuid: 'cb46ad54-8c78-4dbc-a8ed-4e3185b2b3ff',
},
{
name: 'SabreCat',
type: 'Staff',
uuid: '7f14ed62-5408-4e1b-be83-ada62d504931',
},
{
name: 'TheHollidayInn',
type: 'Staff',
uuid: '206039c6-24e4-4b9f-8a31-61cbb9aa3f66',
},
{
name: 'viirus',
type: 'Staff',
uuid: 'a327d7e0-1c2e-41be-9193-7b30b484413f',
},
{
name: 'It\'s Bailey',
type: 'Moderator',
uuid: '9da65443-ed43-4c21-804f-d260c1361596',
},
{
name: 'Alys',
type: 'Moderator',
uuid: 'd904bd62-da08-416b-a816-ba797c9ee265',
},
{
name: 'Blade',
type: 'Moderator',
uuid: '75f270e8-c5db-4722-a5e6-a83f1b23f76b',
},
{
name: 'Breadstrings',
type: 'Moderator',
uuid: '3b675c0e-d7a6-440c-8687-bc67cd0bf4e9',
},
{
name: 'Cantras',
type: 'Moderator',
uuid: '28771972-ca6d-4c03-8261-e1734aa7d21d',
},
// {
// name: 'Daniel the Bard',
// type: 'Moderator',
// uuid: '1f7c4a74-03a3-4b2c-b015-112d0acbd593',
// },
{
name: 'deilann 5.0.5b',
type: 'Moderator',
uuid: 'e7b5d1e2-3b6e-4192-b867-8bafdb03eeec',
},
{
name: 'Dewines',
type: 'Moderator',
uuid: '262a7afb-6b57-4d81-88e0-80d2e9f6cbdc',
},
{
name: 'Fox_town',
type: 'Moderator',
uuid: 'a05f0152-d66b-4ef1-93ac-4adb195d0031',
},
{
name: 'Megan',
type: 'Moderator',
uuid: '73e5125c-2c87-4004-8ccd-972aeac4f17a',
},
{
name: 'shanaqui',
type: 'Moderator',
uuid: 'bb089388-28ae-4e42-a8fa-f0c2bfb6f779',
},
],
newMessage: '',
coords: {
TOP: 0,
LEFT: 0,
},
}; };
}, },
computed: { computed: {
@@ -710,59 +514,10 @@ export default {
modForm () { modForm () {
goToModForm(this.user); goToModForm(this.user);
}, },
// https://medium.com/@_jh3y/how-to-where-s-the-caret-getting-the-xy-position-of-the-caret-a24ba372990a
getCoord (e, text) {
let carPos = text.selectionEnd;
let div = document.createElement('div');
let span = document.createElement('span');
let 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, carPos);
span.textContent = text.value.substr(carPos) || '.';
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) {
let text = eventUpdate.target;
this.getCoord(eventUpdate, text);
},
selectedAutocomplete (newText) {
this.newMessage = newText;
},
toggleSleep () { toggleSleep () {
this.$store.dispatch('user:sleep'); this.$store.dispatch('user:sleep');
}, },
async sendMessage () {
let response = await this.$store.dispatch('chat:postChat', {
group: this.group,
message: this.newMessage,
});
this.group.chat.unshift(response.message);
this.newMessage = '';
// @TODO: I would like to not reload everytime we send. Realtime/Firebase?
let chat = await this.$store.dispatch('chat:getChat', {groupId: this.group._id});
this.group.chat = chat;
},
async fetchRecentMessages () {
this.group = await this.$store.dispatch('guilds:getGroup', {groupId: TAVERN_ID});
},
reverseChat () {
this.group.chat.reverse();
},
pendingDamage () { pendingDamage () {
if (!this.user.party.quest.progress.up) return 0; if (!this.user.party.quest.progress.up) return 0;
return this.$options.filters.floor(this.user.party.quest.progress.up, 10); return this.$options.filters.floor(this.user.party.quest.progress.up, 10);
@@ -795,6 +550,10 @@ export default {
startingPage: 'profile', startingPage: 'profile',
}); });
}, },
async fetchRecentMessages () {
this.group = await this.$store.dispatch('guilds:getGroup', {groupId: TAVERN_ID});
},
}, },
}; };
</script> </script>

View File

@@ -18,7 +18,7 @@ div
@resized="setPartyMembersWidth($event)" @resized="setPartyMembersWidth($event)"
) )
member-details( member-details(
v-for="(member, $index) in partyMembers", v-for="(member, $index) in sortedPartyMembers",
:key="member._id", :key="member._id",
v-if="member._id !== user._id && $index < membersToShow", v-if="member._id !== user._id && $index < membersToShow",
:member="member", :member="member",
@@ -55,7 +55,6 @@ div
} }
#app-header { #app-header {
margin-top: 56px;
padding-left: 24px; padding-left: 24px;
padding-top: 9px; padding-top: 9px;
padding-bottom: 8px; padding-bottom: 8px;
@@ -107,6 +106,7 @@ div
</style> </style>
<script> <script>
import orderBy from 'lodash/orderBy';
import { mapGetters, mapActions } from 'client/libs/store'; import { mapGetters, mapActions } from 'client/libs/store';
import MemberDetails from '../memberDetails'; import MemberDetails from '../memberDetails';
import createPartyModal from '../groups/createPartyModal'; import createPartyModal from '../groups/createPartyModal';
@@ -140,6 +140,9 @@ export default {
membersToShow () { membersToShow () {
return Math.floor(this.currentWidth / 140) + 1; return Math.floor(this.currentWidth / 140) + 1;
}, },
sortedPartyMembers () {
return orderBy(this.partyMembers, [this.user.party.order], [this.user.party.orderAscending]);
},
}, },
methods: { methods: {
...mapActions({ ...mapActions({

View File

@@ -3,60 +3,60 @@ div
inbox-modal inbox-modal
creator-intro creator-intro
profile profile
b-navbar.navbar.navbar-inverse.fixed-top.navbar-expand-lg(type="dark") b-navbar.topbar.navbar-inverse.static-top.navbar-expand-lg(type="dark", :class="navbarZIndexClass")
.navbar-header b-navbar-brand.brand
.logo.svg-icon.d-none.d-xl-block(v-html="icons.logo") .logo.svg-icon.d-none.d-xl-block(v-html="icons.logo")
.svg-icon.gryphon.d-md-block.d-none.d-xl-none .svg-icon.gryphon.d-xs-block.d-xl-none
.svg-icon.gryphon.d-sm-block.d-lg-none.d-md-none b-nav-toggle(target='menu_collapse').menu-toggle
b-nav-toggle(target='nav_collapse') .quick-menu.mobile-only.form-inline
b-collapse#nav_collapse.collapse.navbar-collapse.justify-content-between.flex-wrap(is-nav) a.item-with-icon(@click="sync", v-b-tooltip.hover.bottom="$t('sync')")
.ul.navbar-nav .top-menu-icon.svg-icon(v-html="icons.sync")
router-link.nav-item(tag="li", :to="{name: 'tasks'}", exact) notification-menu.item-with-icon
a.nav-link(v-once) {{ $t('tasks') }} user-dropdown.item-with-icon
router-link.nav-item.dropdown(tag="li", :to="{name: 'items'}", :class="{'active': $route.path.startsWith('/inventory')}") b-collapse#menu_collapse.collapse.navbar-collapse
a.nav-link(v-once) {{ $t('inventory') }} b-navbar-nav.menu-list
.dropdown-menu b-nav-item.topbar-item(tag="li", :to="{name: 'tasks'}", exact) {{ $t('tasks') }}
router-link.dropdown-item(:to="{name: 'items'}", exact) {{ $t('items') }} li.topbar-item(:class="{'active': $route.path.startsWith('/inventory')}")
router-link.dropdown-item(:to="{name: 'equipment'}") {{ $t('equipment') }} router-link.nav-link(:to="{name: 'items'}") {{ $t('inventory') }}
router-link.dropdown-item(:to="{name: 'stable'}") {{ $t('stable') }} .topbar-dropdown
router-link.nav-item.dropdown(tag="li", :to="{name: 'market'}", :class="{'active': $route.path.startsWith('/shop')}") router-link.topbar-dropdown-item.dropdown-item(:to="{name: 'items'}", exact) {{ $t('items') }}
a.nav-link(v-once) {{ $t('shops') }} router-link.topbar-dropdown-item.dropdown-item(:to="{name: 'equipment'}") {{ $t('equipment') }}
.dropdown-menu router-link.topbar-dropdown-item.dropdown-item(:to="{name: 'stable'}") {{ $t('stable') }}
router-link.dropdown-item(:to="{name: 'market'}", exact) {{ $t('market') }} li.topbar-item(:class="{'active': $route.path.startsWith('/shop')}")
router-link.dropdown-item(:to="{name: 'quests'}") {{ $t('quests') }} router-link.nav-link(:to="{name: 'market'}") {{ $t('shops') }}
router-link.dropdown-item(:to="{name: 'seasonal'}") {{ $t('titleSeasonalShop') }} .topbar-dropdown
router-link.dropdown-item(:to="{name: 'time'}") {{ $t('titleTimeTravelers') }} router-link.topbar-dropdown-item.dropdown-item(:to="{name: 'market'}", exact) {{ $t('market') }}
router-link.nav-item(tag="li", :to="{name: 'party'}", v-if='this.user.party._id') router-link.topbar-dropdown-item.dropdown-item(:to="{name: 'quests'}") {{ $t('quests') }}
a.nav-link(v-once) {{ $t('party') }} router-link.topbar-dropdown-item.dropdown-item(:to="{name: 'seasonal'}") {{ $t('titleSeasonalShop') }}
.nav-item(@click='openPartyModal()', v-if='!this.user.party._id') router-link.topbar-dropdown-item.dropdown-item(:to="{name: 'time'}") {{ $t('titleTimeTravelers') }}
a.nav-link(v-once) {{ $t('party') }} b-nav-item.topbar-item(tag="li", :to="{name: 'party'}", v-if='this.user.party._id') {{ $t('party') }}
router-link.nav-item.dropdown(tag="li", :to="{name: 'tavern'}", :class="{'active': $route.path.startsWith('/guilds')}") b-nav-item.topbar-item(@click='openPartyModal()', v-if='!this.user.party._id') {{ $t('party') }}
a.nav-link(v-once) {{ $t('guilds') }} li.topbar-item(:class="{'active': $route.path.startsWith('/guilds')}")
.dropdown-menu router-link.nav-link(:to="{name: 'tavern'}") {{ $t('guilds') }}
router-link.dropdown-item(:to="{name: 'tavern'}") {{ $t('tavern') }} .topbar-dropdown
router-link.dropdown-item(:to="{name: 'myGuilds'}") {{ $t('myGuilds') }} router-link.topbar-dropdown-item.dropdown-item(:to="{name: 'tavern'}") {{ $t('tavern') }}
router-link.dropdown-item(:to="{name: 'guildsDiscovery'}") {{ $t('guildsDiscovery') }} router-link.topbar-dropdown-item.dropdown-item(:to="{name: 'myGuilds'}") {{ $t('myGuilds') }}
router-link.nav-item.dropdown(tag="li", :to="{name: 'groupPlan'}", :class="{'active': $route.path.startsWith('/group-plans')}") router-link.topbar-dropdown-item.dropdown-item(:to="{name: 'guildsDiscovery'}") {{ $t('guildsDiscovery') }}
a.nav-link(v-once) {{ $t('group') }} li.topbar-item(:class="{'active': $route.path.startsWith('/group-plans')}")
.dropdown-menu router-link.nav-link(:to="{name: 'groupPlan'}") {{ $t('group') }}
router-link.dropdown-item(v-for='group in groupPlans', :key='group._id', :to="{name: 'groupPlanDetailTaskInformation', params: {groupId: group._id}}") {{ group.name }} .topbar-dropdown
router-link.nav-item.dropdown(tag="li", :to="{name: 'myChallenges'}", :class="{'active': $route.path.startsWith('/challenges')}") router-link.topbar-dropdown-item.dropdown-item(v-for='group in groupPlans', :key='group._id', :to="{name: 'groupPlanDetailTaskInformation', params: {groupId: group._id}}") {{ group.name }}
a.nav-link(v-once) {{ $t('challenges') }} li.topbar-item(:class="{'active': $route.path.startsWith('/challenges')}")
.dropdown-menu router-link.nav-link(:to="{name: 'myChallenges'}") {{ $t('challenges') }}
router-link.dropdown-item(:to="{name: 'myChallenges'}") {{ $t('myChallenges') }} .topbar-dropdown
router-link.dropdown-item(:to="{name: 'findChallenges'}") {{ $t('findChallenges') }} router-link.topbar-dropdown-item.dropdown-item(:to="{name: 'myChallenges'}") {{ $t('myChallenges') }}
router-link.nav-item.dropdown(tag="li", :class="{'active': $route.path.startsWith('/help')}", :to="{name: 'faq'}") router-link.topbar-dropdown-item.dropdown-item(:to="{name: 'findChallenges'}") {{ $t('findChallenges') }}
a.nav-link(v-once) {{ $t('help') }} li.topbar-item(:class="{'active': $route.path.startsWith('/help')}")
.dropdown-menu router-link.nav-link(:to="{name: 'faq'}") {{ $t('help') }}
router-link.dropdown-item(:to="{name: 'faq'}") {{ $t('faq') }} .topbar-dropdown
router-link.dropdown-item(:to="{name: 'overview'}") {{ $t('overview') }} router-link.topbar-dropdown-item.dropdown-item(:to="{name: 'faq'}") {{ $t('faq') }}
router-link.dropdown-item(to="/groups/guild/a29da26b-37de-4a71-b0c6-48e72a900dac") {{ $t('reportBug') }} router-link.topbar-dropdown-item.dropdown-item(:to="{name: 'overview'}") {{ $t('overview') }}
router-link.dropdown-item(to="/groups/guild/5481ccf3-5d2d-48a9-a871-70a7380cee5a") {{ $t('askAQuestion') }} router-link.topbar-dropdown-item.dropdown-item(to="/groups/guild/a29da26b-37de-4a71-b0c6-48e72a900dac") {{ $t('reportBug') }}
router-link.topbar-dropdown-item.dropdown-item(to="/groups/guild/5481ccf3-5d2d-48a9-a871-70a7380cee5a") {{ $t('askAQuestion') }}
a.dropdown-item(href="https://trello.com/c/odmhIqyW/440-read-first-table-of-contents", target='_blank') {{ $t('requestAF') }} a.dropdown-item(href="https://trello.com/c/odmhIqyW/440-read-first-table-of-contents", target='_blank') {{ $t('requestAF') }}
a.dropdown-item(href="http://habitica.wikia.com/wiki/Contributing_to_Habitica", target='_blank') {{ $t('contributing') }} a.dropdown-item(href="http://habitica.wikia.com/wiki/Contributing_to_Habitica", target='_blank') {{ $t('contributing') }}
a.dropdown-item(href="http://habitica.wikia.com/wiki/Habitica_Wiki", target='_blank') {{ $t('wiki') }} a.dropdown-item(href="http://habitica.wikia.com/wiki/Habitica_Wiki", target='_blank') {{ $t('wiki') }}
a.dropdown-item(@click='modForm()') {{ $t('contactForm') }} .currency-tray.form-inline
.user-menu.d-flex.align-items-center
.item-with-icon(v-if="userHourglasses > 0") .item-with-icon(v-if="userHourglasses > 0")
.top-menu-icon.svg-icon(v-html="icons.hourglasses", v-b-tooltip.hover.bottom="$t('mysticHourglassesTooltip')") .top-menu-icon.svg-icon(v-html="icons.hourglasses", v-b-tooltip.hover.bottom="$t('mysticHourglassesTooltip')")
span {{ userHourglasses }} span {{ userHourglasses }}
@@ -66,6 +66,7 @@ div
.item-with-icon.gold .item-with-icon.gold
.top-menu-icon.svg-icon(v-html="icons.gold", v-b-tooltip.hover.bottom="$t('gold')") .top-menu-icon.svg-icon(v-html="icons.gold", v-b-tooltip.hover.bottom="$t('gold')")
span {{Math.floor(user.stats.gp * 100) / 100}} span {{Math.floor(user.stats.gp * 100) / 100}}
.form-inline.desktop-only
a.item-with-icon(@click="sync", v-b-tooltip.hover.bottom="$t('sync')") a.item-with-icon(@click="sync", v-b-tooltip.hover.bottom="$t('sync')")
.top-menu-icon.svg-icon(v-html="icons.sync") .top-menu-icon.svg-icon(v-html="icons.sync")
notification-menu.item-with-icon notification-menu.item-with-icon
@@ -76,16 +77,6 @@ div
@import '~client/assets/scss/colors.scss'; @import '~client/assets/scss/colors.scss';
@import '~client/assets/scss/utils.scss'; @import '~client/assets/scss/utils.scss';
@media only screen and (max-width: 1305px) {
.nav-link {
padding: .8em 1em !important;
}
.navbar-header {
margin-right: 5px !important;
}
}
@media only screen and (max-width: 1200px) { @media only screen and (max-width: 1200px) {
.gryphon { .gryphon {
background-image: url('~assets/images/melior@3x.png'); background-image: url('~assets/images/melior@3x.png');
@@ -94,127 +85,185 @@ div
background-size: cover; background-size: cover;
color: $white; color: $white;
margin: 0 auto; margin: 0 auto;
} }
.svg-icon.gryphon.d-sm-block { .topbar-item {
position: absolute;
left: calc(50% - 30px);
top: 1em;
}
.nav-item .nav-link {
font-size: 14px !important; font-size: 14px !important;
padding: 16px 12px !important;
} }
} }
@media only screen and (max-width: 990px) { @media only screen and (min-width: 992px) {
#nav_collapse { .mobile-only {
margin-top: 0.6em; display: none !important;
flex-direction: row !important;
max-height: 650px;
overflow: auto;
} }
.navbar-nav { .topbar {
width: 100%; max-height: 56px;
background: $purple-100;
}
.user-menu { .currency-tray {
flex-direction: column !important; margin-left: auto;
align-items: left !important; }
background: $purple-100;
width: 100%;
.item-with-icon { .topbar-item {
width: 100%; padding-top: 5px;
padding-bottom: 1em; height: 56px;
&.active:not(:hover) {
box-shadow: 0px -4px 0px $purple-300 inset;
}
}
.topbar-dropdown {
position: absolute;
} }
} }
} }
#nav_collapse { @media only screen and (max-width: 992px) {
.brand {
margin: 0;
}
.gryphon {
position: absolute;
left: calc(50% - 30px);
top: 10px;
}
#menu_collapse {
margin: 0.6em -16px -8px;
overflow: auto;
flex-direction: column;
background-color: $purple-100;
.menu-list {
width: 100%;
order: 1;
text-align: center;
.topbar-dropdown-item {
background: #432874;
border-bottom: #6133b4 solid 1px;
}
.topbar-item {
&.active {
background: #6133b4;
}
background: #4f2a93;
border-bottom: #6133b4 solid 1px;
}
}
}
.currency-tray {
justify-content: center;
min-height: 40px;
background: #271b3d;
width: 100%;
}
.desktop-only {
display: none !important;
}
}
.menu-toggle {
border: none;
}
#menu_collapse {
display: flex;
justify-content: space-between;
}
.topbar {
background: $purple-100 url(~assets/svg/for-css/bits.svg) right top no-repeat;
min-height: 56px;
box-shadow: 0 1px 2px 0 rgba($black, 0.24);
a {
color: white !important;
}
}
.navbar-z-index {
&-normal {
z-index: 1080;
}
&-modal {
z-index: 1035;
z-index: 1042; // To stay above snakbar notifications and modals
}
}
.logo {
padding-left: 10px;
width: 128px;
height: 28px;
}
.quick-menu {
display: flex;
margin-left: auto;
}
.currency-tray {
display: flex; display: flex;
} }
nav.navbar { .topbar-item {
background: $purple-100 url(~assets/svg/for-css/bits.svg) right no-repeat; font-size: 16px;
padding-left: 25px; color: $white !important;
padding-right: 12.5px; font-weight: bold;
height: 56px; transition: none;
box-shadow: 0 1px 2px 0 rgba($black, 0.24);
z-index: 1042; // To stay above snakbar notifications and modals
}
.navbar-header { .topbar-dropdown {
margin-right: 48px; display: none; // Display is set to block on hover.
.logo {
width: 128px;
height: 28px;
} }
}
>a {
.nav-item { padding: .8em 1em !important;
.nav-link {
font-size: 16px;
color: $white !important;
font-weight: bold;
line-height: 1.5;
padding: 16px 20px;
transition: none;
} }
&:hover { &:hover {
.nav-link { color: $white !important;
color: $white !important; background: $purple-200;
.topbar-dropdown {
display: block; // Open drop-down on hover.
margin-top: 0; // Remove gap between navbar and drop-down.
background: $purple-200; background: $purple-200;
} border-radius: 0px;
} border: none;
box-shadow: none;
padding: 0px;
&.active:not(:hover) { border-bottom-right-radius: 5px;
.nav-link { border-bottom-left-radius: 5px;
box-shadow: 0px -4px 0px $purple-300 inset;
}
}
}
// Make the dropdown menu open on hover .topbar-dropdown-item {
.dropdown:hover .dropdown-menu { font-size: 16px;
display: block; box-shadow: none;
margin-top: 0; // remove the gap so it doesn't close color: $white;
} border: none;
line-height: 1.5;
display: list-item;
.dropdown-menu { &.active {
background: $purple-200; background: $purple-300;
border-radius: 0px; }
border: none;
box-shadow: none;
padding: 0px;
border-bottom-right-radius: 5px; &:hover {
border-bottom-left-radius: 5px; background: $purple-300;
.dropdown-item { &:last-child {
font-size: 16px; border-bottom-right-radius: 5px;
box-shadow: none; border-bottom-left-radius: 5px;
color: $white; }
border: none; }
line-height: 1.5;
&.active {
background: $purple-300;
}
&:hover {
background: $purple-300;
color: $white;
&:last-child {
border-bottom-right-radius: 5px;
border-bottom-left-radius: 5px;
} }
} }
} }
@@ -327,7 +376,14 @@ export default {
user: 'user.data', user: 'user.data',
userHourglasses: 'user.data.purchased.plan.consecutive.trinkets', userHourglasses: 'user.data.purchased.plan.consecutive.trinkets',
groupPlans: 'groupPlans', groupPlans: 'groupPlans',
modalStack: 'modalStack',
}), }),
navbarZIndexClass () {
if (this.modalStack.length > 0) {
return 'navbar-z-index-modal';
}
return 'navbar-z-index-normal';
},
}, },
mounted () { mounted () {
this.getUserGroupPlans(); this.getUserGroupPlans();
@@ -364,6 +420,7 @@ export default {
this.$root.$emit('bv::show::modal', 'buy-gems', {alreadyTracked: true}); this.$root.$emit('bv::show::modal', 'buy-gems', {alreadyTracked: true});
}, },
}, },
}; };
</script> </script>

View File

@@ -47,7 +47,7 @@
label.custom-control-label(v-once, :for="mountGroup.key") {{ mountGroup.label }} label.custom-control-label(v-once, :for="mountGroup.key") {{ mountGroup.label }}
div.form-group.clearfix div.form-group.clearfix
h3.float-left Hide Missing h3.float-left {{ $t('hideMissing') }}
toggle-switch.float-right( toggle-switch.float-right(
:checked="hideMissing", :checked="hideMissing",
@change="updateHideMissing" @change="updateHideMissing"
@@ -935,10 +935,22 @@
} }
}, },
async feedAction (petKey, foodKey) { async feedAction (petKey, foodKey) {
const result = await this.$store.dispatch('common:feed', {pet: petKey, food: foodKey}); try {
if (result.message) this.text(result.message); const result = await this.$store.dispatch('common:feed', {pet: petKey, food: foodKey});
if (this.user.preferences.suppressModals.raisePet) return;
if (this.user.items.pets[petKey] === -1) this.$root.$emit('habitica::mount-raised', petKey); if (result.message) this.text(result.message);
if (this.user.preferences.suppressModals.raisePet) return;
if (this.user.items.pets[petKey] === -1) this.$root.$emit('habitica::mount-raised', petKey);
} catch (e) {
const errorMessage = e.message || e;
this.$store.dispatch('snackbars:add', {
title: 'Habitica',
text: errorMessage,
type: 'error',
timeout: true,
});
}
}, },
closeHatchPetDialog () { closeHatchPetDialog () {
this.$root.$emit('bv::hide::modal', 'hatching-modal'); this.$root.$emit('bv::hide::modal', 'hatching-modal');

View File

@@ -26,7 +26,7 @@
b.how-many-to-sell {{ $t('howManyToSell') }} b.how-many-to-sell {{ $t('howManyToSell') }}
div div
b-input.itemsToSell(type="number", v-model="selectedAmountToSell", :max="itemCount", min="1", @keyup.native="preventNegative($event)") b-input.itemsToSell(type="number", v-model="selectedAmountToSell", :max="itemCount", min="1", @keyup.native="preventNegative($event)", step="1")
span.svg-icon.inline.icon-32(aria-hidden="true", v-html="icons.gold") span.svg-icon.inline.icon-32(aria-hidden="true", v-html="icons.gold")
span.value {{ item.value }} span.value {{ item.value }}
@@ -144,11 +144,16 @@
preventNegative ($event) { preventNegative ($event) {
let value = $event.target.value; let value = $event.target.value;
if (isNaN($event.target.valueAsNumber) || Number(value) < 0) { if (Number(value) < 0) {
this.selectedAmountToSell = 0; this.selectedAmountToSell = 0;
} }
}, },
sellItems () { sellItems () {
if (!Number.isInteger(Number(this.selectedAmountToSell))) {
this.selectedAmountToSell = 0;
return;
}
this.$store.dispatch('shops:sellItems', { this.$store.dispatch('shops:sellItems', {
type: this.itemType, type: this.itemType,
key: this.item.key, key: this.item.key,

View File

@@ -139,7 +139,7 @@
h4.popover-content-title(v-else) {{ item.text }} h4.popover-content-title(v-else) {{ item.text }}
.popover-content-text(v-if='item.locked && item.key === "lostMasterclasser1"') {{ `${$t('questUnlockLostMasterclasser')}` }} .popover-content-text(v-if='item.locked && item.key === "lostMasterclasser1"') {{ `${$t('questUnlockLostMasterclasser')}` }}
.popover-content-text(v-if='item.locked && item.unlockCondition && item.unlockCondition.incentiveThreshold') {{ `${$t('loginIncentiveQuest', {count: item.unlockCondition.incentiveThreshold})}` }} .popover-content-text(v-if='item.locked && item.unlockCondition && item.unlockCondition.incentiveThreshold') {{ `${$t('loginIncentiveQuest', {count: item.unlockCondition.incentiveThreshold})}` }}
.popover-content-text(v-if='item.locked && item.previous') {{ `${$t('unlockByQuesting', {title: item.previous})}` }} .popover-content-text(v-if='item.locked && item.previous && isBuyingDependentOnPrevious(item)') {{ `${$t('unlockByQuesting', {title: item.previous})}` }}
.popover-content-text(v-if='item.lvl > user.stats.lvl') {{ `${$t('mustLvlQuest', {level: item.lvl})}` }} .popover-content-text(v-if='item.lvl > user.stats.lvl') {{ `${$t('mustLvlQuest', {level: item.lvl})}` }}
questInfo(v-if='!item.locked', :quest="item") questInfo(v-if='!item.locked', :quest="item")
@@ -486,6 +486,11 @@ export default {
this.$root.$emit('bv::show::modal', 'buy-quest-modal'); this.$root.$emit('bv::show::modal', 'buy-quest-modal');
}, },
isBuyingDependentOnPrevious (item) {
let questsNotDependentToPrevious = ['moon2', 'moon3'];
if (item.key in questsNotDependentToPrevious) return false;
return true;
},
}, },
}; };
</script> </script>

View File

@@ -0,0 +1,91 @@
<template lang="pug">
.section
.section-header.d-flex.align-items-center
h3.mb-0(v-once)
| {{ title }}
.section-info.mx-1(
v-if="tooltip !== null"
)
.svg-icon(
v-html='icons.information',
:id="tooltipId",
:title="tooltip"
)
b-tooltip(
:title="tooltip",
:target="tooltipId",
)
.section-toggle.ml-auto(@click="toggle")
.svg-icon(v-html="icons.upIcon", v-if="visible")
.svg-icon(v-html="icons.downIcon", v-else)
.section-body(v-show="visible")
slot
</template>
<style lang="scss" scoped>
.section {
border-top: 1px solid #e1e0e3;
margin-top: 1em;
padding-top: 1em;
}
.section:last-of-type {
border-bottom: 1px solid #e1e0e3;
margin-bottom: 1em;
padding-bottom: 1em;
}
.section-body {
margin-top: 1em;
}
.section-toggle {
cursor: pointer;
}
.section-info {
cursor: help;
}
.section-info .svg-icon,
.section-toggle .svg-icon {
width: 16px;
}
</style>
<script>
import uuid from 'uuid/v4';
import upIcon from 'assets/svg/up.svg';
import downIcon from 'assets/svg/down.svg';
import informationIcon from 'assets/svg/information.svg';
export default {
props: {
title: {
required: true,
},
tooltip: {
default: null,
},
show: {
default: true,
},
},
data () {
return {
tooltipId: uuid(),
visible: this.show,
icons: {
upIcon,
downIcon,
information: informationIcon,
},
};
},
methods: {
toggle () {
this.visible = !this.visible;
},
},
};
</script>

View File

@@ -130,7 +130,6 @@ export default {
}; };
}, },
created () { created () {
// @TODO the notifications always close even if timeout is false
let timeout = this.notification.hasOwnProperty('timeout') ? this.notification.timeout : true; let timeout = this.notification.hasOwnProperty('timeout') ? this.notification.timeout : true;
if (timeout) { if (timeout) {
let delay = this.notification.delay || 1500; let delay = this.notification.delay || 1500;

View File

@@ -1,6 +1,6 @@
<template lang="pug"> <template lang="pug">
.notifications .notifications(:class="notificationsTopPos")
div(v-for='notification in notifications', :key='notification.uuid') div(v-for='notification in notificationStore', :key='notification.uuid')
notification(:notification='notification') notification(:notification='notification')
</template> </template>
@@ -8,13 +8,23 @@
.notifications { .notifications {
position: fixed; position: fixed;
right: 10px; right: 10px;
top: 65px;
width: 350px; width: 350px;
z-index: 1041; // 1041 is above modal backgrounds z-index: 1070; // 1070 is above modal backgrounds
&-top-pos {
&-normal {
top: 65px;
}
&-sleeping {
top: 105px;
}
}
} }
</style> </style>
<script> <script>
import { mapState } from 'client/libs/store';
import notification from './notification'; import notification from './notification';
export default { export default {
@@ -22,8 +32,19 @@ export default {
notification, notification,
}, },
computed: { computed: {
notifications () { ...mapState({
return this.$store.state.notificationStore; notificationStore: 'notificationStore',
userSleeping: 'user.data.preferences.sleep',
}),
notificationsTopPos () {
const base = 'notifications-top-pos-';
let modifier = '';
if (this.userSleeping) {
modifier = 'sleeping';
} else {
modifier = 'normal';
}
return `${base}${modifier}`;
}, },
}, },
}; };

View File

@@ -24,7 +24,7 @@
@focus="quickAddFocused = true", @blur="quickAddFocused = false", @focus="quickAddFocused = true", @blur="quickAddFocused = false",
) )
transition(name="quick-add-tip-slide") transition(name="quick-add-tip-slide")
.quick-add-tip.small-text(v-show="quickAddFocused", v-html="$t('addMultipleTip')") .quick-add-tip.small-text(v-show="quickAddFocused", v-html="$t('addMultipleTip', {taskType: $t(typeLabel)})")
clear-completed-todos(v-if="activeFilter.label === 'complete2' && isUser === true") clear-completed-todos(v-if="activeFilter.label === 'complete2' && isUser === true")
.column-background( .column-background(
v-if="isUser === true", v-if="isUser === true",
@@ -370,7 +370,7 @@ export default {
let rewards = inAppRewards(this.user); let rewards = inAppRewards(this.user);
// Add season rewards if user is affected // Add season rewards if user is affected
// @TODO: Add buff coniditional // @TODO: Add buff conditional
const seasonalSkills = { const seasonalSkills = {
snowball: 'salt', snowball: 'salt',
spookySparkles: 'opaquePotion', spookySparkles: 'opaquePotion',

View File

@@ -55,10 +55,6 @@
.custom-control-label { .custom-control-label {
color: $gray-50 !important; color: $gray-50 !important;
font-weight: normal; font-weight: normal;
overflow: hidden;
text-overflow: ellipsis;
white-space: pre;
width: 8em;
} }
} }

View File

@@ -64,7 +64,7 @@
type="checkbox", type="checkbox",
:checked="item.completed", :checked="item.completed",
@change="toggleChecklistItem(item)", @change="toggleChecklistItem(item)",
:disabled="castingSpell", :disabled="castingSpell || !isUser",
:id="`checklist-${item.id}`" :id="`checklist-${item.id}`"
) )
label.custom-control-label(v-markdown="item.text", :for="`checklist-${item.id}`") label.custom-control-label(v-markdown="item.text", :for="`checklist-${item.id}`")

View File

@@ -1,44 +1,57 @@
<template lang="pug"> <template lang="pug">
div.header-tabs .header-tabs
.drawer-tab-container ul.drawer-tab-container
.drawer-tab(v-for="(tab, index) in tabs") li.drawer-tab(v-for="(tab, index) in tabs")
a.drawer-tab-text( a.drawer-tab-text(
@click="changeTab(index)", @click="changeTab(index)",
:class="{'drawer-tab-text-active': selectedTabPosition === index}", :class="{'drawer-tab-text-active': selectedTabPosition === index}",
:title="tab.label" :title="tab.label"
) {{ tab.label }} ) {{ tab.label }}
span.right-item aside.help-item
slot(name="right-item") slot(name="right-item")
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
.drawer-tab-text { .drawer-tab-text {
overflow-x: hidden;
display: block; display: block;
overflow-x: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.drawer-tab { .drawer-tab {
white-space: nowrap;
overflow-x: hidden;
flex: inherit; flex: inherit;
overflow-x: hidden;
white-space: nowrap;
} }
.drawer-tab-container { .drawer-tab-container {
max-width: 50%; grid-column-start: 2;
margin: 0 auto; grid-column-end: 3;
justify-self: center;
margin: 0;
padding: 0;
} }
.right-item { .help-item {
position: absolute; grid-column-start: 3;
position: relative;
right: -11px; right: -11px;
text-align: right;
top: -2px; top: -2px;
} }
.header-tabs { .header-tabs {
position: relative; display: grid;
display: flex; grid-template-columns: 1fr auto 1fr;
}
// MS Edge
@supports (-ms-ime-align: auto) {
.help-item {
align-self: center;
top: 1px;
}
} }
</style> </style>

View File

@@ -0,0 +1,21 @@
<template lang="pug">
b-link(
v-if='user && user.profile',
@click.prevent='showProfile(user)'
) {{user.profile.name}}
</template>
<script>
export default {
props: ['user'],
methods: {
async showProfile (user) {
let heroDetails = await this.$store.dispatch('members:fetchMember', { memberId: user._id });
this.$root.$emit('habitica:show-profile', {
user: heroDetails.data.data,
startingPage: 'profile',
});
},
},
};
</script>

View File

@@ -55,7 +55,6 @@
h3(v-if="label !== 'skip'") {{ label }} h3(v-if="label !== 'skip'") {{ label }}
h3(v-else) {{ $t('background') }} h3(v-else) {{ $t('background') }}
.row.pet-mount-row .row.pet-mount-row
.col-12.col-md-6 .col-12.col-md-6
h2.text-center(v-once) {{ $t('pets') }} h2.text-center(v-once) {{ $t('pets') }}
@@ -134,15 +133,15 @@
.row .row
.col-12.col-md-3(v-for='(statInfo, stat) in allocateStatsList') .col-12.col-md-3(v-for='(statInfo, stat) in allocateStatsList')
.box.white.row.col-12 .box.white.row.col-12
.col-12.col-md-8 .col-12.col-md-9
div(:class='stat') {{ $t(stats[stat].title) }} div(:class='stat') {{ $t(stats[stat].title) }}
.number {{ user.stats[stat] }} .number {{ user.stats[stat] }}
.points {{$t('pts')}} .points {{$t('pts')}}
.col-12.col-md-4 .col-12.col-md-3
div div
.up(v-if='user.stats.points', @click='allocate(stat)') .up(v-if='user.stats.points', @click='allocate(stat)')
div div
.down(@click='deallocate(stat)') .down(@click='deallocate(stat)', v-if='user.stats.points')
.row.save-row .row.save-row
.col-12.col-md-6.offset-md-3.text-center .col-12.col-md-6.offset-md-3.text-center
button.btn.btn-primary(@click='saveAttributes()', :disabled='loading') {{ this.loading ? $t('loading') : $t('save') }} button.btn.btn-primary(@click='saveAttributes()', :disabled='loading') {{ this.loading ? $t('loading') : $t('save') }}
@@ -212,7 +211,7 @@
popover: 'perText', popover: 'perText',
}, },
}, },
statsAtStart: { statUpdates: {
str: 0, str: 0,
int: 0, int: 0,
con: 0, con: 0,
@@ -221,9 +220,6 @@
content: Content, content: Content,
}; };
}, },
mounted () {
this.statsAtStart = Object.assign({}, this.user.stats);
},
computed: { computed: {
...mapState({ ...mapState({
flatGear: 'content.gear.flat', flatGear: 'content.gear.flat',
@@ -291,25 +287,33 @@
}, },
allocate (stat) { allocate (stat) {
allocate(this.user, {query: { stat }}); allocate(this.user, {query: { stat }});
this.statUpdates[stat] += 1;
}, },
deallocate (stat) { deallocate (stat) {
if (this.user.stats[stat] === 0) return; if (this.user.stats[stat] === 0) return;
this.user.stats[stat] -= 1; this.user.stats[stat] -= 1;
this.user.stats.points += 1; this.user.stats.points += 1;
this.statUpdates[stat] -= 1;
}, },
async saveAttributes () { async saveAttributes () {
this.loading = true; this.loading = true;
const statUpdates = {}; const statUpdates = {};
['str', 'int', 'per', 'con'].forEach(stat => { ['str', 'int', 'per', 'con'].forEach(stat => {
const diff = this.user.stats[stat] - this.statsAtStart[stat]; if (this.statUpdates[stat] > 0) statUpdates[stat] = this.statUpdates[stat];
statUpdates[stat] = diff;
}); });
await axios.post('/api/v3/user/allocate-bulk', { await axios.post('/api/v3/user/allocate-bulk', {
stats: statUpdates, stats: statUpdates,
}); });
this.statUpdates = {
str: 0,
int: 0,
con: 0,
per: 0,
};
this.loading = false; this.loading = false;
}, },
allocateNow () { allocateNow () {

View File

@@ -1,40 +0,0 @@
let store = {};
let currentCount = 1;
let currentSpell = {
key: '',
};
let timer = null;
// @TODO: We are using this lib in actions, so we have to inject store
function setStore (storeInc) {
store = storeInc;
}
function castSpell () {
clearTimeout(timer);
currentSpell.quantity = currentCount;
store.dispatch('user:castSpell', currentSpell);
currentCount = 0;
}
function queue (spell, storeInc) {
setStore(storeInc);
currentCount += 1;
if (currentSpell.key && spell.key !== currentSpell.key) {
castSpell();
}
currentSpell = spell;
clearTimeout(timer);
timer = setTimeout(() => {
castSpell();
}, 1500);
}
export default { queue };

View File

@@ -0,0 +1,97 @@
export default [
{
name: 'beffymaroo',
type: 'Staff',
uuid: '9fe7183a-4b79-4c15-9629-a1aee3873390',
},
// {
// name: 'lefnire',
// type: 'Staff',
// uuid: '00000000-0000-4000-9000-000000000000',
// },
{
name: 'Lemoness',
type: 'Staff',
uuid: '7bde7864-ebc5-4ee2-a4b7-1070d464cdb0',
},
{
name: 'paglias',
type: 'Staff',
uuid: 'ed4c688c-6652-4a92-9d03-a5a79844174a',
},
{
name: 'redphoenix',
type: 'Staff',
uuid: 'cb46ad54-8c78-4dbc-a8ed-4e3185b2b3ff',
},
{
name: 'SabreCat',
type: 'Staff',
uuid: '7f14ed62-5408-4e1b-be83-ada62d504931',
},
{
name: 'TheHollidayInn',
type: 'Staff',
uuid: '206039c6-24e4-4b9f-8a31-61cbb9aa3f66',
},
{
name: 'viirus',
type: 'Staff',
uuid: 'a327d7e0-1c2e-41be-9193-7b30b484413f',
},
{
name: 'It\'s Bailey',
type: 'Moderator',
uuid: '9da65443-ed43-4c21-804f-d260c1361596',
},
{
name: 'Alys',
type: 'Moderator',
uuid: 'd904bd62-da08-416b-a816-ba797c9ee265',
},
{
name: 'Blade',
type: 'Moderator',
uuid: '75f270e8-c5db-4722-a5e6-a83f1b23f76b',
},
{
name: 'Breadstrings',
type: 'Moderator',
uuid: '3b675c0e-d7a6-440c-8687-bc67cd0bf4e9',
},
{
name: 'Cantras',
type: 'Moderator',
uuid: '28771972-ca6d-4c03-8261-e1734aa7d21d',
},
// {
// name: 'Daniel the Bard',
// type: 'Moderator',
// uuid: '1f7c4a74-03a3-4b2c-b015-112d0acbd593',
// },
{
name: 'deilann 5.0.5b',
type: 'Moderator',
uuid: 'e7b5d1e2-3b6e-4192-b867-8bafdb03eeec',
},
{
name: 'Dewines',
type: 'Moderator',
uuid: '262a7afb-6b57-4d81-88e0-80d2e9f6cbdc',
},
{
name: 'Fox_town',
type: 'Moderator',
uuid: 'a05f0152-d66b-4ef1-93ac-4adb195d0031',
},
{
name: 'Megan',
type: 'Moderator',
uuid: '73e5125c-2c87-4004-8ccd-972aeac4f17a',
},
{
name: 'shanaqui',
type: 'Moderator',
uuid: 'bb089388-28ae-4e42-a8fa-f0c2bfb6f779',
},
];

View File

@@ -133,23 +133,6 @@ export default {
this.markdown(msg); // @TODO: mardown directive? this.markdown(msg); // @TODO: mardown directive?
// If using mpheal and there are other mages in the party, show extra notification
if (type === 'party' && spell.key === 'mpheal') {
// Counting mages
let magesCount = 0;
for (let i = 0; i < target.length; i++) {
if (target[i].stats.class === 'wizard') {
magesCount++;
}
}
// If there are mages, show message telling that the mpheal don't work on other mages
// The count must be bigger than 1 because the user casting the spell is a mage
if (magesCount > 1) {
this.markdown(this.$t('spellWizardNoEthOnMage'));
}
}
if (!beforeQuestProgress) return; if (!beforeQuestProgress) return;
let questProgress = this.questProgress() - beforeQuestProgress; let questProgress = this.questProgress() - beforeQuestProgress;
if (questProgress > 0) { if (questProgress > 0) {

View File

@@ -1,7 +1,6 @@
import axios from 'axios'; import axios from 'axios';
import buyOp from 'common/script/ops/buy/buy'; import buyOp from 'common/script/ops/buy/buy';
import content from 'common/script/content/index'; import content from 'common/script/content/index';
import purchaseOp from 'common/script/ops/buy/purchaseWithSpell';
import hourglassPurchaseOp from 'common/script/ops/buy/hourglassPurchase'; import hourglassPurchaseOp from 'common/script/ops/buy/hourglassPurchase';
import sellOp from 'common/script/ops/sell'; import sellOp from 'common/script/ops/sell';
import unlockOp from 'common/script/ops/unlock'; import unlockOp from 'common/script/ops/unlock';
@@ -91,7 +90,7 @@ async function buyArmoire (store, params) {
export function purchase (store, params) { export function purchase (store, params) {
const quantity = params.quantity || 1; const quantity = params.quantity || 1;
const user = store.state.user.data; const user = store.state.user.data;
let opResult = purchaseOp(user, {params, quantity}); let opResult = buyOp(user, {params, quantity});
return { return {
result: opResult, result: opResult,

View File

@@ -1,5 +1,4 @@
import { loadAsyncResource } from 'client/libs/asyncResource'; import { loadAsyncResource } from 'client/libs/asyncResource';
import spellQueue from 'client/libs/spellQueue';
import setProps from 'lodash/set'; import setProps from 'lodash/set';
import axios from 'axios'; import axios from 'axios';
@@ -118,11 +117,6 @@ export async function movePinnedItem (store, params) {
} }
export function castSpell (store, params) { export function castSpell (store, params) {
if (params.pinType !== 'card' && !params.quantity) {
spellQueue.queue({key: params.key, targetId: params.targetId}, store);
return;
}
let spellUrl = `/api/v3/user/class/cast/${params.key}`; let spellUrl = `/api/v3/user/class/cast/${params.key}`;
const data = {}; const data = {};

View File

@@ -13,6 +13,8 @@
"challengeWinner": "Беше победител в следните предизвикателства", "challengeWinner": "Беше победител в следните предизвикателства",
"challenges": "Предизвикателства", "challenges": "Предизвикателства",
"challengesLink": "<a href='http://habitica.wikia.com/wiki/Challenges' target='_blank'>Предизвикателства</a>", "challengesLink": "<a href='http://habitica.wikia.com/wiki/Challenges' target='_blank'>Предизвикателства</a>",
"challengePrize": "Challenge Prize",
"endDate": "Ends",
"noChallenges": "Все още няма предизвикателства. Посетете", "noChallenges": "Все още няма предизвикателства. Посетете",
"toCreate": "за да създадете.", "toCreate": "за да създадете.",
"selectWinner": "Изберете победител и завършете предизвикателството:", "selectWinner": "Изберете победител и завършете предизвикателството:",
@@ -23,7 +25,9 @@
"filter": "Филтриране", "filter": "Филтриране",
"groups": "Групи", "groups": "Групи",
"noNone": "Нищо", "noNone": "Нищо",
"category": "Category",
"membership": "Участие", "membership": "Участие",
"ownership": "Ownership",
"participating": "Участвам", "participating": "Участвам",
"notParticipating": "Не участвам", "notParticipating": "Не участвам",
"either": "Без значение", "either": "Без значение",

View File

@@ -201,7 +201,6 @@
"showQuickAllocation": "Показване на разпределението на показателните точки", "showQuickAllocation": "Показване на разпределението на показателните точки",
"hideQuickAllocation": "Скриване на разпределението на показателните точки", "hideQuickAllocation": "Скриване на разпределението на показателните точки",
"quickAllocationLevelPopover": "Всяко ниво Ви дава една точка, която можете да разпределите на показател по свой избор. Можете да го направите ръчно или да оставите играта да реши вместо Вас, използвайки една възможностите за автоматично разпределяне, които можете да намерите в Потребителската иконка > Показатели.", "quickAllocationLevelPopover": "Всяко ниво Ви дава една точка, която можете да разпределите на показател по свой избор. Можете да го направите ръчно или да оставите играта да реши вместо Вас, използвайки една възможностите за автоматично разпределяне, които можете да намерите в Потребителската иконка > Показатели.",
"invalidAttribute": "„<%= attr %>“ не е правилен показател.",
"notEnoughAttrPoints": "Нямате достатъчно показателни точки.", "notEnoughAttrPoints": "Нямате достатъчно показателни точки.",
"style": "Стил", "style": "Стил",
"facialhair": "Лице", "facialhair": "Лице",
@@ -219,6 +218,5 @@
"mainHand": "Основна ръка", "mainHand": "Основна ръка",
"offHand": "Страничен", "offHand": "Страничен",
"pointsAvailable": "Налични точки", "pointsAvailable": "Налични точки",
"pts": "точки", "pts": "точки"
"statsObjectRequired": "Промяната на показателите е задължителна"
} }

View File

@@ -49,7 +49,6 @@
"UUID": "Потребителски идентификатор", "UUID": "Потребителски идентификатор",
"loadUser": "Зареждане на потребителя", "loadUser": "Зареждане на потребителя",
"noAdminAccess": "Нямате администраторски достъп.", "noAdminAccess": "Нямате администраторски достъп.",
"pageMustBeNumber": "req.query.page трябва да бъде число",
"userNotFound": "Потребителят не е намерен.", "userNotFound": "Потребителят не е намерен.",
"invalidUUID": "Идентификаторът UUID трябва да бъде правилен", "invalidUUID": "Идентификаторът UUID трябва да бъде правилен",
"title": "Звание", "title": "Звание",

View File

@@ -304,7 +304,7 @@
"alreadyHaveAccountLogin": "Вече имате регистрация? <strong>Влезте.</strong>", "alreadyHaveAccountLogin": "Вече имате регистрация? <strong>Влезте.</strong>",
"dontHaveAccountSignup": "Нямате регистрация? <strong>Регистрирайте се.</strong>", "dontHaveAccountSignup": "Нямате регистрация? <strong>Регистрирайте се.</strong>",
"motivateYourself": "Мотивирайте се, за да изпълните целите си.", "motivateYourself": "Мотивирайте се, за да изпълните целите си.",
"timeToGetThingsDone": "It's time to have fun when you get things done! Join over <%= userCountInMillions %> million Habiticans and improve your life one task at a time.", "timeToGetThingsDone": "Време е да започнете да се забавлявате, докато вършите нещата си! Присъединете се към над <%= userCountInMillions %> милиона хабитиканци и подобрете живота си, задача по задача.",
"singUpForFree": "Регистрирайте се безплатно", "singUpForFree": "Регистрирайте се безплатно",
"or": "ИЛИ", "or": "ИЛИ",
"gamifyYourLife": "Превърнете живота си в игра", "gamifyYourLife": "Превърнете живота си в игра",

View File

@@ -106,16 +106,16 @@
"optionalMessage": "Незадължително съобщение", "optionalMessage": "Незадължително съобщение",
"yesRemove": "Да, нека бъдат премахнати", "yesRemove": "Да, нека бъдат премахнати",
"foreverAlone": "Не можете да харесате собственото си съобщение. Не бъдете такъв човек.", "foreverAlone": "Не можете да харесате собственото си съобщение. Не бъдете такъв човек.",
"sortDateJoinedAsc": "Най-ранна дата на присъединяване", "sortBackground": "Подреждане по фоново изображение",
"sortDateJoinedDesc": "Най-скорошна дата на присъединяване", "sortClass": "Подреждане по клас",
"sortLoginAsc": "Най-ранно вписване", "sortDateJoined": "Подреждане по дата на присъединяване",
"sortLoginDesc": "Най-скорошно вписване", "sortLogin": "Подреждане по дата на вписване",
"sortLevelAsc": "Най-ниско ниво", "sortLevel": "Подреждане по ниво",
"sortLevelDesc": "Най-високо ниво", "sortName": "Подреждане по име",
"sortNameAsc": "Име (А-Я)", "sortTier": "Подреждане по ниво на сътрудник",
"sortNameDesc": "Име (Я-А)", "ascendingAbbrev": "Възходящ ред",
"sortTierAsc": "Най-ниско ниво в системата", "descendingAbbrev": "Низходящ ред",
"sortTierDesc": "Най-високо ниво в системата", "applySortToHeader": "Прилагане на настройките за подреждане към заглавната част на групата",
"confirmGuild": "Създавате ли гилдията за 4 диаманта?", "confirmGuild": "Създавате ли гилдията за 4 диаманта?",
"leaveGroupCha": "Напускане на предизвикателствата на гилдията и…", "leaveGroupCha": "Напускане на предизвикателствата на гилдията и…",
"confirm": "Потвърждаване", "confirm": "Потвърждаване",
@@ -131,6 +131,10 @@
"clearAll": "Изтриване на всички съобщения", "clearAll": "Изтриване на всички съобщения",
"confirmDeleteAllMessages": "Наистина ли искате да изтриете всички съобщения от входящата поща? Другите потребители ще виждат изпратените от Вас съобщения.", "confirmDeleteAllMessages": "Наистина ли искате да изтриете всички съобщения от входящата поща? Другите потребители ще виждат изпратените от Вас съобщения.",
"optOutPopover": "Личните съобщения не Ви допадат? Щракнете тук, за да се откажете напълно от тях.", "optOutPopover": "Личните съобщения не Ви допадат? Щракнете тук, за да се откажете напълно от тях.",
"PMPlaceholderTitle": "Тук все още няма нищо",
"PMPlaceholderDescription": "Изберете разговор отляво",
"PMPlaceholderTitleRevoked": "Привилегиите Ви в чата Ви бяха отнети",
"PMPlaceholderDescriptionRevoked": "Не можете да изпращате лични съобщения, тъй като привилегиите Ви в чата Ви бяха отнети. Ако имате въпроси или притеснения относно това, моля, пишете на <a href=\"mailto:admin@habitica.com\">admin@habitica.com</a>, за да ги обсъдите с екипа.",
"block": "Блокиране", "block": "Блокиране",
"unblock": "Отблокиране", "unblock": "Отблокиране",
"pm-reply": "Изпращане на отговор", "pm-reply": "Изпращане на отговор",
@@ -207,7 +211,6 @@
"partyOnName": "Купонът продължава", "partyOnName": "Купонът продължава",
"partyUpText": "Присъединил(а) се към група с още един човек! Забавлявайте се, докато заедно се биете с чудовища и се подкрепяте взаимно.", "partyUpText": "Присъединил(а) се към група с още един човек! Забавлявайте се, докато заедно се биете с чудовища и се подкрепяте взаимно.",
"partyOnText": "Присъединил(а) се към група с поне четири човека! Радвайте се на допълнителната отговорност, докато се съюзявате с приятелите си, за да побеждавате враговете си!", "partyOnText": "Присъединил(а) се към група с поне четири човека! Радвайте се на допълнителната отговорност, докато се съюзявате с приятелите си, за да побеждавате враговете си!",
"groupIdRequired": "„groupId“ трябва да бъде правилно форматиран идентификатор UUID",
"groupNotFound": "Групата не е намерена или нямате достъп.", "groupNotFound": "Групата не е намерена или нямате достъп.",
"groupTypesRequired": "Трябва да подадете правилен низ за заявка в „type“.", "groupTypesRequired": "Трябва да подадете правилен низ за заявка в „type“.",
"questLeaderCannotLeaveGroup": "Не можете да напуснете групата си, след като сте започнали мисия. Първо прекратете мисията.", "questLeaderCannotLeaveGroup": "Не можете да напуснете групата си, след като сте започнали мисия. Първо прекратете мисията.",
@@ -217,8 +220,6 @@
"memberCannotRemoveYourself": "Не можете да премахнете себе си!", "memberCannotRemoveYourself": "Не можете да премахнете себе си!",
"groupMemberNotFound": "Потребителят не е намерен сред членовете на групата", "groupMemberNotFound": "Потребителят не е намерен сред членовете на групата",
"mustBeGroupMember": "Трябва да бъде член на групата.", "mustBeGroupMember": "Трябва да бъде член на групата.",
"keepOrRemoveAll": "req.query.keep трябва да бъде или „keep-all“, или „remove-all“",
"keepOrRemove": "req.query.keep трябва да бъде или „keep“, или „remove“",
"canOnlyInviteEmailUuid": "Покани могат да бъдат изпращани само чрез UUID идентификатор или е-поща.", "canOnlyInviteEmailUuid": "Покани могат да бъдат изпращани само чрез UUID идентификатор или е-поща.",
"inviteMissingEmail": "В поканата липсва адрес на е-поща.", "inviteMissingEmail": "В поканата липсва адрес на е-поща.",
"inviteMissingUuid": "В поканата липсва потребителски идентификатор", "inviteMissingUuid": "В поканата липсва потребителски идентификатор",
@@ -252,7 +253,7 @@
"userRequestsApproval": "<%= userName %> иска одобрение", "userRequestsApproval": "<%= userName %> иска одобрение",
"userCountRequestsApproval": "<%= userCount %> потребители искат одобрение", "userCountRequestsApproval": "<%= userCount %> потребители искат одобрение",
"youAreRequestingApproval": "Вие искате одобрение", "youAreRequestingApproval": "Вие искате одобрение",
"chatPrivilegesRevoked": "You cannot do that because your chat privileges have been revoked.", "chatPrivilegesRevoked": "Не можете да направите това, защото привилегиите Ви в чата са Ви били отнети.",
"cannotCreatePublicGuildWhenMuted": "Не можете да създадете обществена гилдия, защото привилегиите Ви в чата са Ви били отнети.", "cannotCreatePublicGuildWhenMuted": "Не можете да създадете обществена гилдия, защото привилегиите Ви в чата са Ви били отнети.",
"cannotInviteWhenMuted": "Не можете да изпратите покана за гилдия или група, защото привилегиите Ви в чата са Ви били отнети.", "cannotInviteWhenMuted": "Не можете да изпратите покана за гилдия или група, защото привилегиите Ви в чата са Ви били отнети.",
"newChatMessagePlainNotification": "Има ново съобщение в <%= groupName %> от <%= authorName %>. Щракнете тук, за да отворите страницата!", "newChatMessagePlainNotification": "Има ново съобщение в <%= groupName %> от <%= authorName %>. Щракнете тук, за да отворите страницата!",
@@ -315,7 +316,7 @@
"approvalsTitle": "Задачи, чакащи одобрение", "approvalsTitle": "Задачи, чакащи одобрение",
"upgradeTitle": "Надграждане", "upgradeTitle": "Надграждане",
"blankApprovalsDescription": "Когато групата Ви завърши задача, която се нуждае от одобрение, тя ще се появи тук! Можете да зададете дали дадена задача се нуждае от одобрение в настройките ѝ при редактиране.", "blankApprovalsDescription": "Когато групата Ви завърши задача, която се нуждае от одобрение, тя ще се появи тук! Можете да зададете дали дадена задача се нуждае от одобрение в настройките ѝ при редактиране.",
"userIsClamingTask": "`<%= username %> пое „<%= task %>“`", "userIsClamingTask": "`<%= username %> has claimed:` <%= task %>",
"approvalRequested": "Заявено е одобрение", "approvalRequested": "Заявено е одобрение",
"refreshApprovals": "Опресняване на одобренията", "refreshApprovals": "Опресняване на одобренията",
"refreshGroupTasks": "Опресняване на груповите задачи", "refreshGroupTasks": "Опресняване на груповите задачи",
@@ -323,7 +324,6 @@
"cantDeleteAssignedGroupTasks": "Не можете да изтриете груповите задачи, които са Ви разпределени.", "cantDeleteAssignedGroupTasks": "Не можете да изтриете груповите задачи, които са Ви разпределени.",
"confirmGuildPlanCreation": "Създаване на тази група?", "confirmGuildPlanCreation": "Създаване на тази група?",
"onlyGroupLeaderCanInviteToGroupPlan": "Само водачът на групата може да кани хора в група с абонамент.", "onlyGroupLeaderCanInviteToGroupPlan": "Само водачът на групата може да кани хора в група с абонамент.",
"remainOrLeaveChallenges": "req.query.keep трябва да бъде или „remain-in-challenges“ или „leave-challenges“",
"paymentDetails": "Подробности за разплащането", "paymentDetails": "Подробности за разплащането",
"aboutToJoinCancelledGroupPlan": "На път сте да се присъедините към група, чийто план е прекратен. НЯМА да получите безплатен абонамент.", "aboutToJoinCancelledGroupPlan": "На път сте да се присъедините към група, чийто план е прекратен. НЯМА да получите безплатен абонамент.",
"cannotChangeLeaderWithActiveGroupPlan": "Не можете да промените водача, докато групата има план.", "cannotChangeLeaderWithActiveGroupPlan": "Не можете да промените водача, докато групата има план.",
@@ -366,9 +366,11 @@
"recentActivity": "Последна дейност", "recentActivity": "Последна дейност",
"myGuilds": "Моите гилдии", "myGuilds": "Моите гилдии",
"guildsDiscovery": "Разглеждане на гилдиите", "guildsDiscovery": "Разглеждане на гилдиите",
"role": "Role",
"guildOrPartyLeader": "Водач", "guildOrPartyLeader": "Водач",
"guildLeader": "Водач на гилдията", "guildLeader": "Водач на гилдията",
"member": "Член", "member": "Член",
"guildSize": "Guild Size",
"goldTier": "Златно ниво", "goldTier": "Златно ниво",
"silverTier": "Сребърно ниво", "silverTier": "Сребърно ниво",
"bronzeTier": "Бронзово ниво", "bronzeTier": "Бронзово ниво",

View File

@@ -25,7 +25,7 @@
"tip23": "Достигнете ниво 100, за да отключите Кълбото за прераждане безплатно и да започнете ново приключение!", "tip23": "Достигнете ниво 100, за да отключите Кълбото за прераждане безплатно и да започнете ново приключение!",
"tip24": "Имате въпрос? Задайте го в помощната гилдия на Хабитика)", "tip24": "Имате въпрос? Задайте го в помощната гилдия на Хабитика)",
"tip25": "Четирите сезонни големи празненства започват около слънцестоенията и равноденствията.", "tip25": "Четирите сезонни големи празненства започват около слънцестоенията и равноденствията.",
"tip26": "You can look for a Party or find Party members in the Party Wanted Guild!", "tip26": "Можете да си потърсите група, или да откриете хора, желаещи да влязат в група, в гилдията „Търсене на група“ (Party Wanted Guild)!",
"tip27": "Изпълнихте ежедневна задача вчера, но забравихте да го отбележите? Не се притеснявайте! С възможността за запис на вчерашната дейност можете да записвате това, което сте свършили, преди да започнете новия си ден.", "tip27": "Изпълнихте ежедневна задача вчера, но забравихте да го отбележите? Не се притеснявайте! С възможността за запис на вчерашната дейност можете да записвате това, което сте свършили, преди да започнете новия си ден.",
"tip28": "Задайте свое персонализирано начало на деня от Потребителската иконка > Настройки, за да определите кога започва Вашият ден.", "tip28": "Задайте свое персонализирано начало на деня от Потребителската иконка > Настройки, за да определите кога започва Вашият ден.",
"tip29": "Завършете всичките си ежедневни задачи, за да получите подсилването „Перфектен ден“, което увеличава показателите Ви!", "tip29": "Завършете всичките си ежедневни задачи, за да получите подсилването „Перфектен ден“, което увеличава показателите Ви!",

View File

@@ -48,6 +48,7 @@
"featuredItems": "Препоръчани предмети!", "featuredItems": "Препоръчани предмети!",
"hideLocked": "Скриване на заключените", "hideLocked": "Скриване на заключените",
"hidePinned": "Скриване на закачените", "hidePinned": "Скриване на закачените",
"hideMissing": "Hide Missing",
"amountExperience": "<%= amount %> точки опит", "amountExperience": "<%= amount %> точки опит",
"amountGold": "<%= amount %> злато", "amountGold": "<%= amount %> злато",
"namedHatchingPotion": "Излюпваща отвара с(ъс) <%= type %>", "namedHatchingPotion": "Излюпваща отвара с(ъс) <%= type %>",
@@ -74,20 +75,13 @@
"ianTextMobile": "Мога ли да Ви заинтересовам с няколко свитъка за мисии? Активирайте ги, за да се биете срещу чудовища заедно с групата си!", "ianTextMobile": "Мога ли да Ви заинтересовам с няколко свитъка за мисии? Активирайте ги, за да се биете срещу чудовища заедно с групата си!",
"ianBrokenText": "Добре дошли в магазина за мисии… Тук може да използвате свитъците си с мисии, за да се биете срещу чудовища заедно с приятелите си… Вижте чудесните ни свитъци с мисии, налични за купуване, вдясно…", "ianBrokenText": "Добре дошли в магазина за мисии… Тук може да използвате свитъците си с мисии, за да се биете срещу чудовища заедно с приятелите си… Вижте чудесните ни свитъци с мисии, налични за купуване, вдясно…",
"featuredQuests": "Препоръчани мисии!", "featuredQuests": "Препоръчани мисии!",
"missingKeyParam": "„req.params.key“ е задължително.",
"itemNotFound": "Предметът „<%= key %>“ не е намерен.",
"cannotBuyItem": "Не може да купите този предмет.", "cannotBuyItem": "Не може да купите този предмет.",
"missingTypeKeyEquip": "„key“ и „type“ са задължителни параметри.",
"missingPetFoodFeed": "„pet“ и „food“ са задължителни параметри.",
"invalidPetName": "Подадено е неправилно име на любимец.",
"missingEggHatchingPotionHatch": "„egg“ и „hatchingPotion“ са задължителни параметри.",
"invalidTypeEquip": "„type“ трябва да бъде едно от следните: „equipped“, „pet“, „mount“ или „costume“.",
"mustPurchaseToSet": "Трябва да закупите <%= val %>, за да го/я зададете на <%= key %>.", "mustPurchaseToSet": "Трябва да закупите <%= val %>, за да го/я зададете на <%= key %>.",
"typeRequired": "Типът е задължителен", "typeRequired": "Типът е задължителен",
"positiveAmountRequired": "Изисква се положително количество", "positiveAmountRequired": "Изисква се положително количество",
"notAccteptedType": "Типът трябва да бъде един от следните: eggs, hatchingPotions, premiumHatchingPotions, food, quests, gear", "notAccteptedType": "Типът трябва да бъде един от следните: eggs, hatchingPotions, premiumHatchingPotions, food, quests, gear",
"contentKeyNotFound": "Ключът не е открит за съдържанието <%= type %>", "contentKeyNotFound": "Ключът не е открит за съдържанието <%= type %>",
"plusGem": "+<%= count %> Gem", "plusGem": "+<%= count %> диамант",
"typeNotSellable": "Този тип не може да се продава. Трябва да бъде един от следните: <%= acceptedTypes %>", "typeNotSellable": "Този тип не може да се продава. Трябва да бъде един от следните: <%= acceptedTypes %>",
"userItemsKeyNotFound": "Ключът не е намерен за user.items <%= type %>", "userItemsKeyNotFound": "Ключът не е намерен за user.items <%= type %>",
"userItemsNotEnough": "Нямате достатъчно <%= type %>", "userItemsNotEnough": "Нямате достатъчно <%= type %>",

View File

@@ -96,7 +96,6 @@
"questInvitationDoesNotExist": "Няма изпратени покани за мисията.", "questInvitationDoesNotExist": "Няма изпратени покани за мисията.",
"questInviteNotFound": "Няма намерени покани за мисията.", "questInviteNotFound": "Няма намерени покани за мисията.",
"guildQuestsNotSupported": "Гилдиите не могат да бъдат канени в мисии.", "guildQuestsNotSupported": "Гилдиите не могат да бъдат канени в мисии.",
"questNotFound": "Мисията „<%= key %>“ не беше намерена.",
"questNotOwned": "Не притежавате този свитък с мисия.", "questNotOwned": "Не притежавате този свитък с мисия.",
"questNotGoldPurchasable": "Мисията „<%= key %>“ не може да бъде купена със злато.", "questNotGoldPurchasable": "Мисията „<%= key %>“ не може да бъде купена със злато.",
"questLevelTooHigh": "Трябва да бъдете ниво <%= level %>, за да започнете тази мисия.", "questLevelTooHigh": "Трябва да бъдете ниво <%= level %>, за да започнете тази мисия.",

View File

@@ -102,7 +102,7 @@
"questGoldenknight2Text": "Златният рицар, част 2: Златен рицар", "questGoldenknight2Text": "Златният рицар, част 2: Златен рицар",
"questGoldenknight2Notes": "Въоръжен(а) със стотици показания на хабитиканци, ти най-после се изправяш срещу Златния рицар. Започваш да четеш оплакванията на хабитиканците срещу нея, едно по едно: „А @Pfeffernusse казва, че постоянното ти натякване…“ — рицарят вдига ръка, за да те спре, и казва надменно: „Моля те, тези хора просто завиждат на успеха ми. Вместо да се оплакват, може просто да работят усърдно като мен! Може би трябва да ти демонстрирам силата, която може да получиш, ако се стараеш като мен!“ — тя вдига боздугана си и се приготвя да те нападне!", "questGoldenknight2Notes": "Въоръжен(а) със стотици показания на хабитиканци, ти най-после се изправяш срещу Златния рицар. Започваш да четеш оплакванията на хабитиканците срещу нея, едно по едно: „А @Pfeffernusse казва, че постоянното ти натякване…“ — рицарят вдига ръка, за да те спре, и казва надменно: „Моля те, тези хора просто завиждат на успеха ми. Вместо да се оплакват, може просто да работят усърдно като мен! Може би трябва да ти демонстрирам силата, която може да получиш, ако се стараеш като мен!“ — тя вдига боздугана си и се приготвя да те нападне!",
"questGoldenknight2Boss": "Златен рицар", "questGoldenknight2Boss": "Златен рицар",
"questGoldenknight2Completion": "The Golden Knight lowers her Morningstar in consternation. “I apologize for my rash outburst,” she says. “The truth is, its painful to think that Ive been inadvertently hurting others, and it made me lash out in defense… but perhaps I can still apologize?”", "questGoldenknight2Completion": "Златният рицар със смайване сваля боздугана си. — „Извинявам се за прибързаното си избухване“ — казва тя. — „Истината е, че ме боли, когато си помисля, че може да наранявам останалите, и това ме накара да се защитавам твърде упорито… Надявам се, че не е късно да се извиня?“",
"questGoldenknight2DropGoldenknight3Quest": "Златният рицар, част 3: Железният рицар (свитък)", "questGoldenknight2DropGoldenknight3Quest": "Златният рицар, част 3: Железният рицар (свитък)",
"questGoldenknight3Text": "Златният рицар, част 3: Железният рицар", "questGoldenknight3Text": "Златният рицар, част 3: Железният рицар",
"questGoldenknight3Notes": "@Jon Arinbjorn изкрещява, за да привлече вниманието ти. След края на битката ти се е появила някаква нова фигура. Рицар, облечен в желязо на черни петна, бавно се приближава към теб с меч в ръка. Златният рицар извиква към фигурата: „Татко, не!“ — но рицарят изглежда не смята да спира. Тя се обръща към теб и казва: „Съжалявам. Бях глупачка, не осъзнавах колко съм жестока. Но баща ми е по-жесток, отколкото аз бих могла да бъда някога. Ако не бъде спрян, ще унищожи всички ни. Ето, използвай боздугана ми и спри Железния рицар!“", "questGoldenknight3Notes": "@Jon Arinbjorn изкрещява, за да привлече вниманието ти. След края на битката ти се е появила някаква нова фигура. Рицар, облечен в желязо на черни петна, бавно се приближава към теб с меч в ръка. Златният рицар извиква към фигурата: „Татко, не!“ — но рицарят изглежда не смята да спира. Тя се обръща към теб и казва: „Съжалявам. Бях глупачка, не осъзнавах колко съм жестока. Но баща ми е по-жесток, отколкото аз бих могла да бъда някога. Ако не бъде спрян, ще унищожи всички ни. Ето, използвай боздугана ми и спри Железния рицар!“",
@@ -600,5 +600,7 @@
"questSquirrelCompletion": "С внимателен подход, подкупи и няколко успокояващи заклинания, успявате да придумате катерицата да се отмести от плячката си и да се насочи към конюшнята, където @Shtut вече е успял да премахне всички жълъди. Няколко от жълъдите са подредени на една работна маса. „Това са яйца на катерица! Може би ще успееш да отгледаш някоя катерица, която няма да си играе толкова много с храната си.“", "questSquirrelCompletion": "С внимателен подход, подкупи и няколко успокояващи заклинания, успявате да придумате катерицата да се отмести от плячката си и да се насочи към конюшнята, където @Shtut вече е успял да премахне всички жълъди. Няколко от жълъдите са подредени на една работна маса. „Това са яйца на катерица! Може би ще успееш да отгледаш някоя катерица, която няма да си играе толкова много с храната си.“",
"questSquirrelBoss": "Хитра катерица", "questSquirrelBoss": "Хитра катерица",
"questSquirrelDropSquirrelEgg": "Катерица (яйце)", "questSquirrelDropSquirrelEgg": "Катерица (яйце)",
"questSquirrelUnlockText": "Отключва възможността за купуване на яйца на катерица от пазара." "questSquirrelUnlockText": "Отключва възможността за купуване на яйца на катерица от пазара.",
"cuddleBuddiesText": "Пакет мисии „Пухкави приятелчета“",
"cuddleBuddiesNotes": "Съдържа: „Зайчето-убиец“, „Нечестивият пор“ и „Бандата на морските свинчета“. Наличен до 31 май."
} }

View File

@@ -32,7 +32,7 @@
"resetAccPop": "Започнете отначало, премахвайки всички нива, злато, екипировка, история и задачи.", "resetAccPop": "Започнете отначало, премахвайки всички нива, злато, екипировка, история и задачи.",
"deleteAccount": "Изтриване на профила", "deleteAccount": "Изтриване на профила",
"deleteAccPop": "Изтрива и премахва Вашия профил в Хабитика.", "deleteAccPop": "Изтрива и премахва Вашия профил в Хабитика.",
"feedback": "If you'd like to give us feedback, please enter it below - we'd love to know what you liked or didn't like about Habitica! Don't speak English well? No problem! Use the language you prefer.", "feedback": "Ако искате да ни изпратите отзивите си, моля, въведете ги по-долу. Ще се радваме да научим какво Ви е харесало, или пък не, в Хабитика! Не говорите английски добре? Няма проблем! Пишете на който искате език.",
"qrCode": "QR-код", "qrCode": "QR-код",
"dataExport": "Изнасяне на данни", "dataExport": "Изнасяне на данни",
"saveData": "Ето няколко възможности за запазване на данните Ви.", "saveData": "Ето няколко възможности за запазване на данните Ви.",

View File

@@ -51,7 +51,6 @@
"spellSpecialSeafoamNotes": "Превърнете приятел в морско създание!", "spellSpecialSeafoamNotes": "Превърнете приятел в морско създание!",
"spellSpecialSandText": "Пясък", "spellSpecialSandText": "Пясък",
"spellSpecialSandNotes": "Развалете заклинанието, което Ви е превърнало в морска звезда.", "spellSpecialSandNotes": "Развалете заклинанието, което Ви е превърнало в морска звезда.",
"spellNotFound": "Умението „<%= spellId %>“ не е намерено.",
"partyNotFound": "Групата не е намерена", "partyNotFound": "Групата не е намерена",
"targetIdUUID": "„targetId“ трябва да бъде правилен потребителски идентификатор.", "targetIdUUID": "„targetId“ трябва да бъде правилен потребителски идентификатор.",
"challengeTasksNoCast": "Използването на умения върху задачи от предизвикателства не е позволено.", "challengeTasksNoCast": "Използването на умения върху задачи от предизвикателства не е позволено.",

View File

@@ -7,7 +7,7 @@
"buyGemsGoldText": "Александър Търговеца ще Ви продава диаманти на цената от 20 злато за диамант. Месечните му доставки първоначално са ограничени до 25 диаманта на месец, но това ограничение се увеличава с 5 диаманта за всеки 3 месеца на непрекъснат абонамент, докато достигне 50 диаманта на месец!", "buyGemsGoldText": "Александър Търговеца ще Ви продава диаманти на цената от 20 злато за диамант. Месечните му доставки първоначално са ограничени до 25 диаманта на месец, но това ограничение се увеличава с 5 диаманта за всеки 3 месеца на непрекъснат абонамент, докато достигне 50 диаманта на месец!",
"mustSubscribeToPurchaseGems": "Купуването на диаманти със злато изисква абонамент", "mustSubscribeToPurchaseGems": "Купуването на диаманти със злато изисква абонамент",
"reachedGoldToGemCap": "Достигнахте месечното ограничение на златото, което може да бъде превърнато в диаманти: <%= convCap %>. Целта на това е да предотвратим злоупотребите. Ограничението се нулира през първите три дни на всеки месец.", "reachedGoldToGemCap": "Достигнахте месечното ограничение на златото, което може да бъде превърнато в диаманти: <%= convCap %>. Целта на това е да предотвратим злоупотребите. Ограничението се нулира през първите три дни на всеки месец.",
"reachedGoldToGemCapQuantity": "Your requested amount <%= quantity %> exceeds the Gold=>Gem conversion cap <%= convCap %> for this month. We have this to prevent abuse / farming. The cap resets within the first three days of each month.", "reachedGoldToGemCapQuantity": "Заявеното от Вас количество <%= quantity %>, превишава месечното ограничение на златото, което може да бъде превърнато в диаманти <%= convCap %>. Целта на това е да предотвратим злоупотребите. Ограничението се нулира през първите три дни на всеки месец.",
"retainHistory": "Запазвате по-голяма история", "retainHistory": "Запазвате по-голяма история",
"retainHistoryText": "Завършените задачи за изпълнение остават по-дълго в историята.", "retainHistoryText": "Завършените задачи за изпълнение остават по-дълго в историята.",
"doubleDrops": "Ежедневното ограничение на паданията е два пъти по-голямо", "doubleDrops": "Ежедневното ограничение на паданията е два пъти по-голямо",
@@ -175,12 +175,6 @@
"invalidCoupon": "Грешен код от купон.", "invalidCoupon": "Грешен код от купон.",
"couponUsed": "Този код от купон вече е използван.", "couponUsed": "Този код от купон вече е използван.",
"couponCodeRequired": "Кодът от купона е задължителен.", "couponCodeRequired": "Кодът от купона е задължителен.",
"eventRequired": "„req.params.event“ е задължително.",
"countRequired": "„req.query.count“ е задължително.",
"missingPaymentId": "Липсва „req.query.paymentId“",
"missingCustomerId": "Липсва „req.query.customerId“",
"missingPaypalBlock": "Липсва „req.session.paypalBlock“",
"missingSubKey": "Липсва „req.query.sub“",
"paypalCanceled": "Абонаментът Ви е прекратен", "paypalCanceled": "Абонаментът Ви е прекратен",
"earnGemsMonthly": "Получавайте до **<%= cap %> диаманта** на месец", "earnGemsMonthly": "Получавайте до **<%= cap %> диаманта** на месец",
"receiveMysticHourglass": "Получете Тайнствен пясъчен часовник!", "receiveMysticHourglass": "Получете Тайнствен пясъчен часовник!",

View File

@@ -145,7 +145,6 @@
"rewardHelp3": "По време на световни събития, тук ще се появява специалната екипировка.", "rewardHelp3": "По време на световни събития, тук ще се появява специалната екипировка.",
"rewardHelp4": "Не се притеснявайте да си създадете свои собствени награди! Вижте <a href='http://habitica.wikia.com/wiki/Sample_Custom_Rewards' target='_blank'>примерите тук</a>.", "rewardHelp4": "Не се притеснявайте да си създадете свои собствени награди! Вижте <a href='http://habitica.wikia.com/wiki/Sample_Custom_Rewards' target='_blank'>примерите тук</a>.",
"clickForHelp": "Щракнете за помощ", "clickForHelp": "Щракнете за помощ",
"taskIdRequired": "„taskId“ трябва да бъде правилно форматиран идентификатор UUID.",
"taskAliasAlreadyUsed": "Псевдонимът на задачата вече се използва за друга задача.", "taskAliasAlreadyUsed": "Псевдонимът на задачата вече се използва за друга задача.",
"taskNotFound": "Задачата не е намерена.", "taskNotFound": "Задачата не е намерена.",
"invalidTaskType": "Типът на задачата трябва да бъде един от следните: „habit“, „daily“, „todo“, „reward“.", "invalidTaskType": "Типът на задачата трябва да бъде един от следните: „habit“, „daily“, „todo“, „reward“.",

View File

@@ -13,6 +13,8 @@
"challengeWinner": "Stal se výhercem následujících výzev", "challengeWinner": "Stal se výhercem následujících výzev",
"challenges": "Výzvy", "challenges": "Výzvy",
"challengesLink": "<a href='http://habitica.wikia.com/wiki/Challenges' target='_blank'>Challenges</a>", "challengesLink": "<a href='http://habitica.wikia.com/wiki/Challenges' target='_blank'>Challenges</a>",
"challengePrize": "Challenge Prize",
"endDate": "Ends",
"noChallenges": "Zatím nemáš žádné výzvy. Navštiv", "noChallenges": "Zatím nemáš žádné výzvy. Navštiv",
"toCreate": "abys nějakou vytvořil.", "toCreate": "abys nějakou vytvořil.",
"selectWinner": "Zvolit vítěze a zavřít výzvu:", "selectWinner": "Zvolit vítěze a zavřít výzvu:",
@@ -23,7 +25,9 @@
"filter": "Filtr", "filter": "Filtr",
"groups": "Skupiny", "groups": "Skupiny",
"noNone": "Žádné", "noNone": "Žádné",
"category": "Category",
"membership": "Členství", "membership": "Členství",
"ownership": "Ownership",
"participating": "Účastní se", "participating": "Účastní se",
"notParticipating": "Neúčastní se", "notParticipating": "Neúčastní se",
"either": "Obojí", "either": "Obojí",

View File

@@ -201,7 +201,6 @@
"showQuickAllocation": "Zobrazit přidělení vlastnostních bodů", "showQuickAllocation": "Zobrazit přidělení vlastnostních bodů",
"hideQuickAllocation": "Skrýt přidělení vlastnostních bodů", "hideQuickAllocation": "Skrýt přidělení vlastnostních bodů",
"quickAllocationLevelPopover": "S každou další úrovní získáš jeden bod, který můžeš přiřadit k libovolné vlastnosti. Přiřadit body můžeš buď manuálně anebo můžeš nechat hru rozhodnout za tebe na základě některé z možností Automatického Přiřazení, které nalezneš v Uživatel -> Statistiky.", "quickAllocationLevelPopover": "S každou další úrovní získáš jeden bod, který můžeš přiřadit k libovolné vlastnosti. Přiřadit body můžeš buď manuálně anebo můžeš nechat hru rozhodnout za tebe na základě některé z možností Automatického Přiřazení, které nalezneš v Uživatel -> Statistiky.",
"invalidAttribute": "\"<%= attr %>\" není platný atribut.",
"notEnoughAttrPoints": "Nemáš dostatek vlastnostních bodů", "notEnoughAttrPoints": "Nemáš dostatek vlastnostních bodů",
"style": "Styl", "style": "Styl",
"facialhair": "Vousy", "facialhair": "Vousy",
@@ -219,6 +218,5 @@
"mainHand": "Hlavní ruka", "mainHand": "Hlavní ruka",
"offHand": "Druhá ruka", "offHand": "Druhá ruka",
"pointsAvailable": "Dostupné body", "pointsAvailable": "Dostupné body",
"pts": "Body", "pts": "Body"
"statsObjectRequired": "Je požadována aktualizace atributů"
} }

View File

@@ -49,7 +49,6 @@
"UUID": "ID uživatele", "UUID": "ID uživatele",
"loadUser": "Načíst uživatele", "loadUser": "Načíst uživatele",
"noAdminAccess": "Nemáte adminský přístup.", "noAdminAccess": "Nemáte adminský přístup.",
"pageMustBeNumber": "req.query.page musí být číslo",
"userNotFound": "Uživatel nenalezen.", "userNotFound": "Uživatel nenalezen.",
"invalidUUID": "UUID musí být platné.", "invalidUUID": "UUID musí být platné.",
"title": "Název", "title": "Název",

View File

@@ -106,16 +106,16 @@
"optionalMessage": "Nepovinná zpráva", "optionalMessage": "Nepovinná zpráva",
"yesRemove": "Ano, odstraň je", "yesRemove": "Ano, odstraň je",
"foreverAlone": "Nemůže se ti líbit tvoje vlastní zpráva. Nebuď takový.", "foreverAlone": "Nemůže se ti líbit tvoje vlastní zpráva. Nebuď takový.",
"sortDateJoinedAsc": "Earliest Date Joined", "sortBackground": "Sort by Background",
"sortDateJoinedDesc": "Latest Date Joined", "sortClass": "Sort by Class",
"sortLoginAsc": "Earliest Login", "sortDateJoined": "Sort by Join Date",
"sortLoginDesc": "Latest Login", "sortLogin": "Sort by Login Date",
"sortLevelAsc": "Lowest Level", "sortLevel": "Sort by Level",
"sortLevelDesc": "Highest Level", "sortName": "Sort by Name",
"sortNameAsc": "Name (A - Z)", "sortTier": "Sort by Tier",
"sortNameDesc": "Name (Z - A)", "ascendingAbbrev": "Asc",
"sortTierAsc": "Lowest Tier", "descendingAbbrev": "Desc",
"sortTierDesc": "Highest Tier", "applySortToHeader": "Apply Sort Options to Party Header",
"confirmGuild": "Vytvořit cech za 4 drahokamy?", "confirmGuild": "Vytvořit cech za 4 drahokamy?",
"leaveGroupCha": "Opustit výzvy cechu a...", "leaveGroupCha": "Opustit výzvy cechu a...",
"confirm": "Potvrdit", "confirm": "Potvrdit",
@@ -131,6 +131,10 @@
"clearAll": "Vymazat všechny zprávy", "clearAll": "Vymazat všechny zprávy",
"confirmDeleteAllMessages": "Jsi si jistý, že chceš vymazat všechny zprávy ve schránce? Ostatní uživatelé stále uvidí všechny zprávy, které jsi jim poslal.", "confirmDeleteAllMessages": "Jsi si jistý, že chceš vymazat všechny zprávy ve schránce? Ostatní uživatelé stále uvidí všechny zprávy, které jsi jim poslal.",
"optOutPopover": "Nemáš rád soukromé zprávy? Klikni pro úplné odhlášení", "optOutPopover": "Nemáš rád soukromé zprávy? Klikni pro úplné odhlášení",
"PMPlaceholderTitle": "Nothing Here Yet",
"PMPlaceholderDescription": "Select a conversation on the left",
"PMPlaceholderTitleRevoked": "Your chat privileges have been revoked",
"PMPlaceholderDescriptionRevoked": "You are not able to send private messages because your chat privileges have been revoked. If you have questions or concerns about this, please email <a href=\"mailto:admin@habitica.com\">admin@habitica.com</a> to discuss it with the staff.",
"block": "Blokovat", "block": "Blokovat",
"unblock": "Odblokovat", "unblock": "Odblokovat",
"pm-reply": "Poslat odpověď", "pm-reply": "Poslat odpověď",
@@ -207,7 +211,6 @@
"partyOnName": "Velká družina", "partyOnName": "Velká družina",
"partyUpText": "Joined a Party with another person! Have fun battling monsters and supporting each other.", "partyUpText": "Joined a Party with another person! Have fun battling monsters and supporting each other.",
"partyOnText": "Joined a Party with at least four people! Enjoy your increased accountability as you unite with your friends to vanquish your foes!", "partyOnText": "Joined a Party with at least four people! Enjoy your increased accountability as you unite with your friends to vanquish your foes!",
"groupIdRequired": "„groupId\" musí být platné UUID",
"groupNotFound": "Group not found or you don't have access.", "groupNotFound": "Group not found or you don't have access.",
"groupTypesRequired": "You must supply a valid \"type\" query string.", "groupTypesRequired": "You must supply a valid \"type\" query string.",
"questLeaderCannotLeaveGroup": "You cannot leave your Party when you have started a quest. Abort the quest first.", "questLeaderCannotLeaveGroup": "You cannot leave your Party when you have started a quest. Abort the quest first.",
@@ -217,8 +220,6 @@
"memberCannotRemoveYourself": "Nemůžete se sám odebrat!", "memberCannotRemoveYourself": "Nemůžete se sám odebrat!",
"groupMemberNotFound": "Uživatel nenalezen mezi členy skupiny.", "groupMemberNotFound": "Uživatel nenalezen mezi členy skupiny.",
"mustBeGroupMember": "Musí být členem skupiny.", "mustBeGroupMember": "Musí být členem skupiny.",
"keepOrRemoveAll": "req.query.keep must be either \"keep-all\" or \"remove-all\"",
"keepOrRemove": "req.query.keep must be either \"keep\" or \"remove\"",
"canOnlyInviteEmailUuid": "Lze použít pouze uuids nebo emaily.", "canOnlyInviteEmailUuid": "Lze použít pouze uuids nebo emaily.",
"inviteMissingEmail": "Chybějící emailová adresa v pozvánce.", "inviteMissingEmail": "Chybějící emailová adresa v pozvánce.",
"inviteMissingUuid": "Missing user id in invite", "inviteMissingUuid": "Missing user id in invite",
@@ -315,7 +316,7 @@
"approvalsTitle": "Tasks Awaiting Approval", "approvalsTitle": "Tasks Awaiting Approval",
"upgradeTitle": "Upgrade", "upgradeTitle": "Upgrade",
"blankApprovalsDescription": "When your group completes tasks that need your approval, they'll appear here! Adjust approval requirement settings under task editing.", "blankApprovalsDescription": "When your group completes tasks that need your approval, they'll appear here! Adjust approval requirement settings under task editing.",
"userIsClamingTask": "`<%= username %> has claimed \"<%= task %>\"`", "userIsClamingTask": "`<%= username %> has claimed:` <%= task %>",
"approvalRequested": "Approval Requested", "approvalRequested": "Approval Requested",
"refreshApprovals": "Refresh Approvals", "refreshApprovals": "Refresh Approvals",
"refreshGroupTasks": "Refresh Group Tasks", "refreshGroupTasks": "Refresh Group Tasks",
@@ -323,7 +324,6 @@
"cantDeleteAssignedGroupTasks": "Can't delete group tasks that are assigned to you.", "cantDeleteAssignedGroupTasks": "Can't delete group tasks that are assigned to you.",
"confirmGuildPlanCreation": "Create this group?", "confirmGuildPlanCreation": "Create this group?",
"onlyGroupLeaderCanInviteToGroupPlan": "Only the group leader can invite users to a group with a subscription.", "onlyGroupLeaderCanInviteToGroupPlan": "Only the group leader can invite users to a group with a subscription.",
"remainOrLeaveChallenges": "req.query.keep must be either 'remain-in-challenges' or 'leave-challenges'",
"paymentDetails": "Payment Details", "paymentDetails": "Payment Details",
"aboutToJoinCancelledGroupPlan": "You are about to join a group with a canceled plan. You will NOT receive a free subscription.", "aboutToJoinCancelledGroupPlan": "You are about to join a group with a canceled plan. You will NOT receive a free subscription.",
"cannotChangeLeaderWithActiveGroupPlan": "You can not change the leader while the group has an active plan.", "cannotChangeLeaderWithActiveGroupPlan": "You can not change the leader while the group has an active plan.",
@@ -366,9 +366,11 @@
"recentActivity": "Recent Activity", "recentActivity": "Recent Activity",
"myGuilds": "My Guilds", "myGuilds": "My Guilds",
"guildsDiscovery": "Discover Guilds", "guildsDiscovery": "Discover Guilds",
"role": "Role",
"guildOrPartyLeader": "Leader", "guildOrPartyLeader": "Leader",
"guildLeader": "Guild Leader", "guildLeader": "Guild Leader",
"member": "Member", "member": "Member",
"guildSize": "Guild Size",
"goldTier": "Gold Tier", "goldTier": "Gold Tier",
"silverTier": "Silver Tier", "silverTier": "Silver Tier",
"bronzeTier": "Bronze Tier", "bronzeTier": "Bronze Tier",

View File

@@ -48,6 +48,7 @@
"featuredItems": "Zmíněné předměty!", "featuredItems": "Zmíněné předměty!",
"hideLocked": "Hide locked", "hideLocked": "Hide locked",
"hidePinned": "Hide pinned", "hidePinned": "Hide pinned",
"hideMissing": "Hide Missing",
"amountExperience": "<%= amount %> Zkušenost", "amountExperience": "<%= amount %> Zkušenost",
"amountGold": "<%= amount %> Zlato", "amountGold": "<%= amount %> Zlato",
"namedHatchingPotion": "<%= type %> Líhnoucí lektvar", "namedHatchingPotion": "<%= type %> Líhnoucí lektvar",
@@ -74,14 +75,7 @@
"ianTextMobile": "Can I interest you in some quest scrolls? Activate them to battle monsters with your Party!", "ianTextMobile": "Can I interest you in some quest scrolls? Activate them to battle monsters with your Party!",
"ianBrokenText": "Vítej v obchodě s Výpravami... Můžeš tu s přáteli využít svitky s výpravami k bojům s monstry... V klidu si prohlédni všechny Výpravy, které tu prodáváme...", "ianBrokenText": "Vítej v obchodě s Výpravami... Můžeš tu s přáteli využít svitky s výpravami k bojům s monstry... V klidu si prohlédni všechny Výpravy, které tu prodáváme...",
"featuredQuests": "Zmíněné výpravy!", "featuredQuests": "Zmíněné výpravy!",
"missingKeyParam": "Je požadovaný \"req.params.key\".",
"itemNotFound": "Předmět „<%= key %>\" nenalezen.",
"cannotBuyItem": "Tento předmět nelze zakoupit.", "cannotBuyItem": "Tento předmět nelze zakoupit.",
"missingTypeKeyEquip": "\"key\" a \"type\" jsou požadované parametry.",
"missingPetFoodFeed": "\"pet\" a \"food\" jsou požadované parametry.",
"invalidPetName": "Neplatné jméno mazlíčka.",
"missingEggHatchingPotionHatch": "\"egg\" a \"hatchingPotion\" jsou požadované parametry.",
"invalidTypeEquip": "\"typ\" vybavení musí být jeden z následujících: 'vybaveno', 'mazlíček', 'zvíře k osedlání', 'kostým'",
"mustPurchaseToSet": "Musíte koupit <%= val %> k nastavení na <%= key %>.", "mustPurchaseToSet": "Musíte koupit <%= val %> k nastavení na <%= key %>.",
"typeRequired": "Je požadován typ", "typeRequired": "Je požadován typ",
"positiveAmountRequired": "Pozitivní množství je požadováno", "positiveAmountRequired": "Pozitivní množství je požadováno",

View File

@@ -96,7 +96,6 @@
"questInvitationDoesNotExist": "Zatím vám nebyla poslána žádná pozvánka na výpravu.", "questInvitationDoesNotExist": "Zatím vám nebyla poslána žádná pozvánka na výpravu.",
"questInviteNotFound": "Nebyla nalezena žádná pozvánka na výpravu.", "questInviteNotFound": "Nebyla nalezena žádná pozvánka na výpravu.",
"guildQuestsNotSupported": "Cechy nelze pozvat na výpravy.", "guildQuestsNotSupported": "Cechy nelze pozvat na výpravy.",
"questNotFound": "Výprava „<%= key %>\" nenalezena.",
"questNotOwned": "Nevlastníte tento svitek výpravy.", "questNotOwned": "Nevlastníte tento svitek výpravy.",
"questNotGoldPurchasable": "Výpravu „<%= key %>\" nelze koupit na zlato.", "questNotGoldPurchasable": "Výpravu „<%= key %>\" nelze koupit na zlato.",
"questLevelTooHigh": "Pro začátek výpravy musíte mít úroveň <%= level %>.", "questLevelTooHigh": "Pro začátek výpravy musíte mít úroveň <%= level %>.",

View File

@@ -600,5 +600,7 @@
"questSquirrelCompletion": "With a gentle approach, offers of trade, and a few soothing spells, youre able to coax the squirrel away from its hoard and back to the stables, which @Shtut has just finished de-acorning. Theyve set aside a few of the acorns on a worktable. “These ones are squirrel eggs! Maybe you can raise some that dont play with their food quite so much.”", "questSquirrelCompletion": "With a gentle approach, offers of trade, and a few soothing spells, youre able to coax the squirrel away from its hoard and back to the stables, which @Shtut has just finished de-acorning. Theyve set aside a few of the acorns on a worktable. “These ones are squirrel eggs! Maybe you can raise some that dont play with their food quite so much.”",
"questSquirrelBoss": "Sneaky Squirrel", "questSquirrelBoss": "Sneaky Squirrel",
"questSquirrelDropSquirrelEgg": "Squirrel (Egg)", "questSquirrelDropSquirrelEgg": "Squirrel (Egg)",
"questSquirrelUnlockText": "Unlocks purchasable Squirrel eggs in the Market" "questSquirrelUnlockText": "Unlocks purchasable Squirrel eggs in the Market",
"cuddleBuddiesText": "Cuddle Buddies Quest Bundle",
"cuddleBuddiesNotes": "Contains 'The Killer Bunny', 'The Nefarious Ferret', and 'The Guinea Pig Gang'. Available until May 31."
} }

View File

@@ -51,7 +51,6 @@
"spellSpecialSeafoamNotes": "Přeměň svého kamaráda na mořskou příšerku!", "spellSpecialSeafoamNotes": "Přeměň svého kamaráda na mořskou příšerku!",
"spellSpecialSandText": "Písek", "spellSpecialSandText": "Písek",
"spellSpecialSandNotes": "Zvrať kouzlo, které z tebe udělalo mořskou hvězdu.", "spellSpecialSandNotes": "Zvrať kouzlo, které z tebe udělalo mořskou hvězdu.",
"spellNotFound": "Schopnost „<%= spellId %>\" nenalezena.",
"partyNotFound": "Družina nenalezena", "partyNotFound": "Družina nenalezena",
"targetIdUUID": "„cílovéId\" musí být platné ID uživatele. ", "targetIdUUID": "„cílovéId\" musí být platné ID uživatele. ",
"challengeTasksNoCast": "Použití schopnosti na úkol z výzvy není povoleno.", "challengeTasksNoCast": "Použití schopnosti na úkol z výzvy není povoleno.",

View File

@@ -175,12 +175,6 @@
"invalidCoupon": "Neplatný kód kupónu.", "invalidCoupon": "Neplatný kód kupónu.",
"couponUsed": "Kód kupónu byl již použit.", "couponUsed": "Kód kupónu byl již použit.",
"couponCodeRequired": "Je požadován kód kupónu.", "couponCodeRequired": "Je požadován kód kupónu.",
"eventRequired": "je požadováno „req.params.event\".",
"countRequired": "je požadováno „req.query.count\".",
"missingPaymentId": "Missing req.query.paymentId",
"missingCustomerId": "Missing req.query.customerId",
"missingPaypalBlock": "Missing req.session.paypalBlock",
"missingSubKey": "Missing req.query.sub",
"paypalCanceled": "Your subscription has been canceled", "paypalCanceled": "Your subscription has been canceled",
"earnGemsMonthly": "Earn up to **<%= cap %> Gems** per month", "earnGemsMonthly": "Earn up to **<%= cap %> Gems** per month",
"receiveMysticHourglass": "Receive a Mystic Hourglass!", "receiveMysticHourglass": "Receive a Mystic Hourglass!",

View File

@@ -145,7 +145,6 @@
"rewardHelp3": "V průběhu světových událostí se speciální vybavení zobrazí zde.", "rewardHelp3": "V průběhu světových událostí se speciální vybavení zobrazí zde.",
"rewardHelp4": "Neboj se vytvořit si své Odměny! Koukni na <a href='http://habitica.wikia.com/wiki/Sample_Custom_Rewards' target='_blank'>na ukázku tady</a>.", "rewardHelp4": "Neboj se vytvořit si své Odměny! Koukni na <a href='http://habitica.wikia.com/wiki/Sample_Custom_Rewards' target='_blank'>na ukázku tady</a>.",
"clickForHelp": "Klikni pro nápovědu", "clickForHelp": "Klikni pro nápovědu",
"taskIdRequired": "\"taskId\" musí být platné UUID.",
"taskAliasAlreadyUsed": "Alias úkolu byl již použit na jiném úkolu.", "taskAliasAlreadyUsed": "Alias úkolu byl již použit na jiném úkolu.",
"taskNotFound": "Úkol nenalezen.", "taskNotFound": "Úkol nenalezen.",
"invalidTaskType": "Typ úkolu musí být „zvyk\", „denní úkol\", „úkol\" nebo „odměna\".", "invalidTaskType": "Typ úkolu musí být „zvyk\", „denní úkol\", „úkol\" nebo „odměna\".",

View File

@@ -13,6 +13,8 @@
"challengeWinner": "Blev vinderen i de følgende udfordringer", "challengeWinner": "Blev vinderen i de følgende udfordringer",
"challenges": "Udfordringer", "challenges": "Udfordringer",
"challengesLink": "<a href='http://habitica.wikia.com/wiki/Challenges' target='_blank'>Udfordringer</a>", "challengesLink": "<a href='http://habitica.wikia.com/wiki/Challenges' target='_blank'>Udfordringer</a>",
"challengePrize": "Challenge Prize",
"endDate": "Ends",
"noChallenges": "Ingen udfordringer endnu, besøg", "noChallenges": "Ingen udfordringer endnu, besøg",
"toCreate": "for at oprette en.", "toCreate": "for at oprette en.",
"selectWinner": "Vælg en vinder og luk udfordringen:", "selectWinner": "Vælg en vinder og luk udfordringen:",
@@ -23,7 +25,9 @@
"filter": "Filter", "filter": "Filter",
"groups": "Grupper", "groups": "Grupper",
"noNone": "Ingen", "noNone": "Ingen",
"category": "Category",
"membership": "Medlemskab", "membership": "Medlemskab",
"ownership": "Ownership",
"participating": "Deltager", "participating": "Deltager",
"notParticipating": "Deltager ikke", "notParticipating": "Deltager ikke",
"either": "Begge", "either": "Begge",

View File

@@ -201,7 +201,6 @@
"showQuickAllocation": "Show Stat Allocation", "showQuickAllocation": "Show Stat Allocation",
"hideQuickAllocation": "Hide Stat Allocation", "hideQuickAllocation": "Hide Stat Allocation",
"quickAllocationLevelPopover": "Each level earns you one Point to assign to a Stat of your choice. You can do so manually, or let the game decide for you using one of the Automatic Allocation options found in User Icon > Stats.", "quickAllocationLevelPopover": "Each level earns you one Point to assign to a Stat of your choice. You can do so manually, or let the game decide for you using one of the Automatic Allocation options found in User Icon > Stats.",
"invalidAttribute": "\"<%= attr %>\" is not a valid Stat.",
"notEnoughAttrPoints": "You don't have enough Stat Points.", "notEnoughAttrPoints": "You don't have enough Stat Points.",
"style": "Stil", "style": "Stil",
"facialhair": "Facial", "facialhair": "Facial",
@@ -219,6 +218,5 @@
"mainHand": "Main-Hand", "mainHand": "Main-Hand",
"offHand": "Off-Hand", "offHand": "Off-Hand",
"pointsAvailable": "Points Available", "pointsAvailable": "Points Available",
"pts": "pts", "pts": "pts"
"statsObjectRequired": "Stats update is required"
} }

View File

@@ -49,7 +49,6 @@
"UUID": "BrugerID", "UUID": "BrugerID",
"loadUser": "Indlæs bruger", "loadUser": "Indlæs bruger",
"noAdminAccess": "Du har ikke administrator-adgang.", "noAdminAccess": "Du har ikke administrator-adgang.",
"pageMustBeNumber": "req.query.page skal være et tal",
"userNotFound": "Bruger ikke fundet.", "userNotFound": "Bruger ikke fundet.",
"invalidUUID": "UUID skal være gyldigt", "invalidUUID": "UUID skal være gyldigt",
"title": "Titel", "title": "Titel",

View File

@@ -106,16 +106,16 @@
"optionalMessage": "Valgfri besked", "optionalMessage": "Valgfri besked",
"yesRemove": "Ja, fjern dem", "yesRemove": "Ja, fjern dem",
"foreverAlone": "Du kan ikke synes godt om din egen besked. Lad være med at være sådan.", "foreverAlone": "Du kan ikke synes godt om din egen besked. Lad være med at være sådan.",
"sortDateJoinedAsc": "Earliest Date Joined", "sortBackground": "Sort by Background",
"sortDateJoinedDesc": "Latest Date Joined", "sortClass": "Sort by Class",
"sortLoginAsc": "Earliest Login", "sortDateJoined": "Sort by Join Date",
"sortLoginDesc": "Latest Login", "sortLogin": "Sort by Login Date",
"sortLevelAsc": "Lowest Level", "sortLevel": "Sort by Level",
"sortLevelDesc": "Highest Level", "sortName": "Sort by Name",
"sortNameAsc": "Name (A - Z)", "sortTier": "Sort by Tier",
"sortNameDesc": "Name (Z - A)", "ascendingAbbrev": "Asc",
"sortTierAsc": "Lowest Tier", "descendingAbbrev": "Desc",
"sortTierDesc": "Highest Tier", "applySortToHeader": "Apply Sort Options to Party Header",
"confirmGuild": "Opret Klan for 4 Ædelsten?", "confirmGuild": "Opret Klan for 4 Ædelsten?",
"leaveGroupCha": "Forlad Klanudfordringer og...", "leaveGroupCha": "Forlad Klanudfordringer og...",
"confirm": "Bekræft", "confirm": "Bekræft",
@@ -131,6 +131,10 @@
"clearAll": "Slet Alle Beskeder", "clearAll": "Slet Alle Beskeder",
"confirmDeleteAllMessages": "Er du sikker på, at du vil slette alle beskeder i din indbakke? Andre brugere kan stadig se beskeder, du har sendt til dem.", "confirmDeleteAllMessages": "Er du sikker på, at du vil slette alle beskeder i din indbakke? Andre brugere kan stadig se beskeder, du har sendt til dem.",
"optOutPopover": "Vil du ikke modtage private beskeder? Klik for at afmelde", "optOutPopover": "Vil du ikke modtage private beskeder? Klik for at afmelde",
"PMPlaceholderTitle": "Nothing Here Yet",
"PMPlaceholderDescription": "Select a conversation on the left",
"PMPlaceholderTitleRevoked": "Your chat privileges have been revoked",
"PMPlaceholderDescriptionRevoked": "You are not able to send private messages because your chat privileges have been revoked. If you have questions or concerns about this, please email <a href=\"mailto:admin@habitica.com\">admin@habitica.com</a> to discuss it with the staff.",
"block": "Blokér", "block": "Blokér",
"unblock": "Fjern blokering", "unblock": "Fjern blokering",
"pm-reply": "Send svar", "pm-reply": "Send svar",
@@ -207,7 +211,6 @@
"partyOnName": "Et godt selskab", "partyOnName": "Et godt selskab",
"partyUpText": "Sluttede sig til en Gruppe med en anden! Hav det sjovt med at bekæmpe monstre og støtte hinanden.", "partyUpText": "Sluttede sig til en Gruppe med en anden! Hav det sjovt med at bekæmpe monstre og støtte hinanden.",
"partyOnText": "Sluttede sig til en gruppe med mindst fire personer! Nyd at du har flere at stå til regnskab for mens du og dine venner går sammen for at besejre jeres fjender!", "partyOnText": "Sluttede sig til en gruppe med mindst fire personer! Nyd at du har flere at stå til regnskab for mens du og dine venner går sammen for at besejre jeres fjender!",
"groupIdRequired": "\"groupId\" skal være et gyldigt Unikt Bruger-ID",
"groupNotFound": "Gruppen blev ikke fundet eller du har ikke adgang.", "groupNotFound": "Gruppen blev ikke fundet eller du har ikke adgang.",
"groupTypesRequired": "Du skal angive en gyldig \"type\" forespørgelses-string.", "groupTypesRequired": "Du skal angive en gyldig \"type\" forespørgelses-string.",
"questLeaderCannotLeaveGroup": "You cannot leave your Party when you have started a quest. Abort the quest first.", "questLeaderCannotLeaveGroup": "You cannot leave your Party when you have started a quest. Abort the quest first.",
@@ -217,8 +220,6 @@
"memberCannotRemoveYourself": "Du kan ikke fjerne dig selv!", "memberCannotRemoveYourself": "Du kan ikke fjerne dig selv!",
"groupMemberNotFound": "Bruger ikke fundet blandt gruppens medlemmer", "groupMemberNotFound": "Bruger ikke fundet blandt gruppens medlemmer",
"mustBeGroupMember": "Skal være medlem af gruppen", "mustBeGroupMember": "Skal være medlem af gruppen",
"keepOrRemoveAll": "req.query.keep skal være enten \"keep-all\" eller \"remove-all\"",
"keepOrRemove": "req.query.keep skal være enten \"keep\" eller \"remove\"",
"canOnlyInviteEmailUuid": "Kan kun invitere via unikke bruger-id eller email.", "canOnlyInviteEmailUuid": "Kan kun invitere via unikke bruger-id eller email.",
"inviteMissingEmail": "Manglende emailadresse i invitationen", "inviteMissingEmail": "Manglende emailadresse i invitationen",
"inviteMissingUuid": "Manglende bruger-id i invitationen", "inviteMissingUuid": "Manglende bruger-id i invitationen",
@@ -315,7 +316,7 @@
"approvalsTitle": "Tasks Awaiting Approval", "approvalsTitle": "Tasks Awaiting Approval",
"upgradeTitle": "Opgradér", "upgradeTitle": "Opgradér",
"blankApprovalsDescription": "When your group completes tasks that need your approval, they'll appear here! Adjust approval requirement settings under task editing.", "blankApprovalsDescription": "When your group completes tasks that need your approval, they'll appear here! Adjust approval requirement settings under task editing.",
"userIsClamingTask": "`<%= username %> har gjort krav på \"<%= task %>\"`", "userIsClamingTask": "`<%= username %> has claimed:` <%= task %>",
"approvalRequested": "Godkendelse anmodet", "approvalRequested": "Godkendelse anmodet",
"refreshApprovals": "Refresh Approvals", "refreshApprovals": "Refresh Approvals",
"refreshGroupTasks": "Refresh Group Tasks", "refreshGroupTasks": "Refresh Group Tasks",
@@ -323,7 +324,6 @@
"cantDeleteAssignedGroupTasks": "Du kan ikke slette gruppe opgaver, der er blevet tildelt til dig.", "cantDeleteAssignedGroupTasks": "Du kan ikke slette gruppe opgaver, der er blevet tildelt til dig.",
"confirmGuildPlanCreation": "Opret denne gruppe?", "confirmGuildPlanCreation": "Opret denne gruppe?",
"onlyGroupLeaderCanInviteToGroupPlan": "Only the group leader can invite users to a group with a subscription.", "onlyGroupLeaderCanInviteToGroupPlan": "Only the group leader can invite users to a group with a subscription.",
"remainOrLeaveChallenges": "req.query.keep must be either 'remain-in-challenges' or 'leave-challenges'",
"paymentDetails": "Betalingsdetaljer", "paymentDetails": "Betalingsdetaljer",
"aboutToJoinCancelledGroupPlan": "You are about to join a group with a canceled plan. You will NOT receive a free subscription.", "aboutToJoinCancelledGroupPlan": "You are about to join a group with a canceled plan. You will NOT receive a free subscription.",
"cannotChangeLeaderWithActiveGroupPlan": "You can not change the leader while the group has an active plan.", "cannotChangeLeaderWithActiveGroupPlan": "You can not change the leader while the group has an active plan.",
@@ -366,9 +366,11 @@
"recentActivity": "Recent Activity", "recentActivity": "Recent Activity",
"myGuilds": "My Guilds", "myGuilds": "My Guilds",
"guildsDiscovery": "Discover Guilds", "guildsDiscovery": "Discover Guilds",
"role": "Role",
"guildOrPartyLeader": "Leader", "guildOrPartyLeader": "Leader",
"guildLeader": "Guild Leader", "guildLeader": "Guild Leader",
"member": "Member", "member": "Member",
"guildSize": "Guild Size",
"goldTier": "Gold Tier", "goldTier": "Gold Tier",
"silverTier": "Silver Tier", "silverTier": "Silver Tier",
"bronzeTier": "Bronze Tier", "bronzeTier": "Bronze Tier",

View File

@@ -48,6 +48,7 @@
"featuredItems": "Featured Items!", "featuredItems": "Featured Items!",
"hideLocked": "Hide locked", "hideLocked": "Hide locked",
"hidePinned": "Hide pinned", "hidePinned": "Hide pinned",
"hideMissing": "Hide Missing",
"amountExperience": "<%= amount %> Experience", "amountExperience": "<%= amount %> Experience",
"amountGold": "<%= amount %> Gold", "amountGold": "<%= amount %> Gold",
"namedHatchingPotion": "<%= type %> Hatching Potion", "namedHatchingPotion": "<%= type %> Hatching Potion",
@@ -74,14 +75,7 @@
"ianTextMobile": "Can I interest you in some quest scrolls? Activate them to battle monsters with your Party!", "ianTextMobile": "Can I interest you in some quest scrolls? Activate them to battle monsters with your Party!",
"ianBrokenText": "Velkommen til quest-butikken... Her kan du aktivere quest-skriftruller for at kæmpe mod monstre sammen med dine venner... Husk at gennemse det fine udvalg af quest-skriftruller til højre...", "ianBrokenText": "Velkommen til quest-butikken... Her kan du aktivere quest-skriftruller for at kæmpe mod monstre sammen med dine venner... Husk at gennemse det fine udvalg af quest-skriftruller til højre...",
"featuredQuests": "Featured Quests!", "featuredQuests": "Featured Quests!",
"missingKeyParam": "\"req.params.key\" nødvendig.",
"itemNotFound": "Objekt \"<%= key %>\" ikke fundet",
"cannotBuyItem": "Du kan ikke købe dette objekt.", "cannotBuyItem": "Du kan ikke købe dette objekt.",
"missingTypeKeyEquip": "\"key\" og \"type\" er nødvendige parametre",
"missingPetFoodFeed": "\"pet\" og \"food\" er nødvendige parametre",
"invalidPetName": "Ugyldigt kæledyrnavn opgivet",
"missingEggHatchingPotionHatch": "\"egg\" og \"hatchingPotion\" er nødvendige parametre.",
"invalidTypeEquip": "\"type\" skal være en af 'equipped', 'pet', 'mount', 'costume'.",
"mustPurchaseToSet": "Skal købes <%= val %> for at putte det på <%= key %>.", "mustPurchaseToSet": "Skal købes <%= val %> for at putte det på <%= key %>.",
"typeRequired": "Type er nødvendig", "typeRequired": "Type er nødvendig",
"positiveAmountRequired": "Positive amount is required", "positiveAmountRequired": "Positive amount is required",

View File

@@ -96,7 +96,6 @@
"questInvitationDoesNotExist": "Ingen quest invitation er blevet udsendt endnu.", "questInvitationDoesNotExist": "Ingen quest invitation er blevet udsendt endnu.",
"questInviteNotFound": "Ingen questinvitation fundet.", "questInviteNotFound": "Ingen questinvitation fundet.",
"guildQuestsNotSupported": "Klaner kan ikke blive inviteret på quests.", "guildQuestsNotSupported": "Klaner kan ikke blive inviteret på quests.",
"questNotFound": "Quest \"<%= key %>\" ikke fundet.",
"questNotOwned": "Du ejer ikke den quest-skriftrulle", "questNotOwned": "Du ejer ikke den quest-skriftrulle",
"questNotGoldPurchasable": "Quest \"<%= key %>\" er ikke en quest, der kan købes for Guld.", "questNotGoldPurchasable": "Quest \"<%= key %>\" er ikke en quest, der kan købes for Guld.",
"questLevelTooHigh": "Du skal være niveau <%= level %> for at starte denne quest.", "questLevelTooHigh": "Du skal være niveau <%= level %> for at starte denne quest.",

View File

@@ -600,5 +600,7 @@
"questSquirrelCompletion": "With a gentle approach, offers of trade, and a few soothing spells, youre able to coax the squirrel away from its hoard and back to the stables, which @Shtut has just finished de-acorning. Theyve set aside a few of the acorns on a worktable. “These ones are squirrel eggs! Maybe you can raise some that dont play with their food quite so much.”", "questSquirrelCompletion": "With a gentle approach, offers of trade, and a few soothing spells, youre able to coax the squirrel away from its hoard and back to the stables, which @Shtut has just finished de-acorning. Theyve set aside a few of the acorns on a worktable. “These ones are squirrel eggs! Maybe you can raise some that dont play with their food quite so much.”",
"questSquirrelBoss": "Sneaky Squirrel", "questSquirrelBoss": "Sneaky Squirrel",
"questSquirrelDropSquirrelEgg": "Squirrel (Egg)", "questSquirrelDropSquirrelEgg": "Squirrel (Egg)",
"questSquirrelUnlockText": "Unlocks purchasable Squirrel eggs in the Market" "questSquirrelUnlockText": "Unlocks purchasable Squirrel eggs in the Market",
"cuddleBuddiesText": "Cuddle Buddies Quest Bundle",
"cuddleBuddiesNotes": "Contains 'The Killer Bunny', 'The Nefarious Ferret', and 'The Guinea Pig Gang'. Available until May 31."
} }

View File

@@ -51,7 +51,6 @@
"spellSpecialSeafoamNotes": "Gør en ven til et søuhyre!", "spellSpecialSeafoamNotes": "Gør en ven til et søuhyre!",
"spellSpecialSandText": "Sand", "spellSpecialSandText": "Sand",
"spellSpecialSandNotes": "Reverse the spell that made you a sea star.", "spellSpecialSandNotes": "Reverse the spell that made you a sea star.",
"spellNotFound": "Evne \"<%= spellId %>\" blev ikke fundet.",
"partyNotFound": "Gruppe blev ikke fundet", "partyNotFound": "Gruppe blev ikke fundet",
"targetIdUUID": "\"targetId\" skal være et gyldigt Bruger ID.", "targetIdUUID": "\"targetId\" skal være et gyldigt Bruger ID.",
"challengeTasksNoCast": "Det er ikke tilladt at kaste evner på en udfordrings-opgave.", "challengeTasksNoCast": "Det er ikke tilladt at kaste evner på en udfordrings-opgave.",

View File

@@ -175,12 +175,6 @@
"invalidCoupon": "Ugyldig kuponkode.", "invalidCoupon": "Ugyldig kuponkode.",
"couponUsed": "Kuponkode allerede i brug.", "couponUsed": "Kuponkode allerede i brug.",
"couponCodeRequired": "Kuponkode påkrævet.", "couponCodeRequired": "Kuponkode påkrævet.",
"eventRequired": "\"req.params.event\" påkrævet.",
"countRequired": "\"req.query.count\" påkrævet.",
"missingPaymentId": "Manglende req.query.paymentId",
"missingCustomerId": "Manglende req.query.customerId",
"missingPaypalBlock": "Manglende req.session.paypalBlock",
"missingSubKey": "Manglende req.query.sub",
"paypalCanceled": "Dit abonnement er blevet annulleret.", "paypalCanceled": "Dit abonnement er blevet annulleret.",
"earnGemsMonthly": "Earn up to **<%= cap %> Gems** per month", "earnGemsMonthly": "Earn up to **<%= cap %> Gems** per month",
"receiveMysticHourglass": "Receive a Mystic Hourglass!", "receiveMysticHourglass": "Receive a Mystic Hourglass!",

View File

@@ -145,7 +145,6 @@
"rewardHelp3": "Specielt Udstyr vil dukke op her når der er Verdensevents.", "rewardHelp3": "Specielt Udstyr vil dukke op her når der er Verdensevents.",
"rewardHelp4": "Vær ikke bange for at oprette selvvalgte Belønninger! Se <a href='http://habitica.wikia.com/wiki/Sample_Custom_Rewards' target='_blank'>nogle eksempler her</a>.", "rewardHelp4": "Vær ikke bange for at oprette selvvalgte Belønninger! Se <a href='http://habitica.wikia.com/wiki/Sample_Custom_Rewards' target='_blank'>nogle eksempler her</a>.",
"clickForHelp": "Klik for hjælp", "clickForHelp": "Klik for hjælp",
"taskIdRequired": "\"taksID\" skal være et gyldigt Unikt Bruger-ID.",
"taskAliasAlreadyUsed": "Alias allerede i brug på en anden opgave.", "taskAliasAlreadyUsed": "Alias allerede i brug på en anden opgave.",
"taskNotFound": "Opgave ikke fundet.", "taskNotFound": "Opgave ikke fundet.",
"invalidTaskType": "Opgave type skal være \"vane\", \"daglig\", \"todo\" eller \"belønning\".", "invalidTaskType": "Opgave type skal være \"vane\", \"daglig\", \"todo\" eller \"belønning\".",

View File

@@ -346,11 +346,11 @@
"backgroundFlyingOverWildflowerFieldNotes": "Schwebe über einer Wildblumenwiese.", "backgroundFlyingOverWildflowerFieldNotes": "Schwebe über einer Wildblumenwiese.",
"backgroundFlyingOverAncientForestText": "Uralter Wald", "backgroundFlyingOverAncientForestText": "Uralter Wald",
"backgroundFlyingOverAncientForestNotes": "Fliege über das Blätterdach eines uralten Waldes.", "backgroundFlyingOverAncientForestNotes": "Fliege über das Blätterdach eines uralten Waldes.",
"backgrounds052018": "SET 48: Released May 2018", "backgrounds052018": "SATZ 48: Erschien im May 2018",
"backgroundTerracedRiceFieldText": "Terraced Rice Field", "backgroundTerracedRiceFieldText": "Terrassenreisfeld",
"backgroundTerracedRiceFieldNotes": "Enjoy a Terraced Rice Field in the growing season.", "backgroundTerracedRiceFieldNotes": "Genieße ein Terrassenreisfeld während der Wachstumsphase.",
"backgroundFantasticalShoeStoreText": "Fantastical Shoe Store", "backgroundFantasticalShoeStoreText": "Großartiges Schuhgeschäft",
"backgroundFantasticalShoeStoreNotes": "Look for fun new footwear in the Fantastical Shoe Store.", "backgroundFantasticalShoeStoreNotes": "Schau' dich im Großartigen Schuhgeschäft nach tollen neuen Schuhen um.",
"backgroundChampionsColosseumText": "Champions' Colosseum", "backgroundChampionsColosseumText": "Kolosseum der Champions",
"backgroundChampionsColosseumNotes": "Bask in the glory of the Champions' Colosseum." "backgroundChampionsColosseumNotes": "Sonne dich im Ruhm des Kolosseums der Champions."
} }

View File

@@ -13,6 +13,8 @@
"challengeWinner": "Hat die folgenden Wettbewerbe gewonnen", "challengeWinner": "Hat die folgenden Wettbewerbe gewonnen",
"challenges": "Wettbewerbe", "challenges": "Wettbewerbe",
"challengesLink": "<a href='http://habitica.wikia.com/wiki/Challenges' target='_blank'>Herausforderungen</a>", "challengesLink": "<a href='http://habitica.wikia.com/wiki/Challenges' target='_blank'>Herausforderungen</a>",
"challengePrize": "Challenge Prize",
"endDate": "Ends",
"noChallenges": "Keine Wettbewerbe gefunden, besuche", "noChallenges": "Keine Wettbewerbe gefunden, besuche",
"toCreate": "um einen Wettbewerb zu erstellen.", "toCreate": "um einen Wettbewerb zu erstellen.",
"selectWinner": "Wähle einen Gewinner und beende den Wettbewerb.", "selectWinner": "Wähle einen Gewinner und beende den Wettbewerb.",
@@ -23,7 +25,9 @@
"filter": "Filter", "filter": "Filter",
"groups": "Gruppen", "groups": "Gruppen",
"noNone": "Niemand", "noNone": "Niemand",
"category": "Category",
"membership": "Mitgliedschaft", "membership": "Mitgliedschaft",
"ownership": "Ownership",
"participating": "Teilnehmer", "participating": "Teilnehmer",
"notParticipating": "Nicht Teilnehmer", "notParticipating": "Nicht Teilnehmer",
"either": "Beides", "either": "Beides",

View File

@@ -201,7 +201,6 @@
"showQuickAllocation": "Attributspunkte verteilung anzeigen", "showQuickAllocation": "Attributspunkte verteilung anzeigen",
"hideQuickAllocation": "Attributwertzuweisung ausblenden", "hideQuickAllocation": "Attributwertzuweisung ausblenden",
"quickAllocationLevelPopover": "Mit jedem Level erhältst Du einen Punkt, den Du einem Attribut Deiner Wahl zuweisen kannst. Du kannst Deine Punkte manuell verteilen, oder das Spiel entscheiden lassen, indem Du eines der vorgegebenen Verteilungsmuster unter Benutzer Icon > Werte wählst.", "quickAllocationLevelPopover": "Mit jedem Level erhältst Du einen Punkt, den Du einem Attribut Deiner Wahl zuweisen kannst. Du kannst Deine Punkte manuell verteilen, oder das Spiel entscheiden lassen, indem Du eines der vorgegebenen Verteilungsmuster unter Benutzer Icon > Werte wählst.",
"invalidAttribute": "\"<%= attr %>\" ist kein gültiges Attribut.",
"notEnoughAttrPoints": "Du hast nicht genug Attributpunkte.", "notEnoughAttrPoints": "Du hast nicht genug Attributpunkte.",
"style": "Stil", "style": "Stil",
"facialhair": "Bart", "facialhair": "Bart",
@@ -219,6 +218,5 @@
"mainHand": "Haupthand", "mainHand": "Haupthand",
"offHand": "Schildhand", "offHand": "Schildhand",
"pointsAvailable": "Verfügbare Punkte", "pointsAvailable": "Verfügbare Punkte",
"pts": "Pkte", "pts": "Pkte"
"statsObjectRequired": "Werte-Update ist erforderlich"
} }

View File

@@ -10,8 +10,8 @@
"commGuideHeadingInteractions": "Interaktionen in Habitica", "commGuideHeadingInteractions": "Interaktionen in Habitica",
"commGuidePara015": "Habitica hat zwei Arten sozialer Orte: öffentliche und private. Öffentliche Orte sind das Gasthaus, öffentliche Gilden, GitHub, Trello und das Wiki. Private Orte sind private Gilden, der Gruppenchat und Private Nachrichten. Alle Anzeigenamen müssen den Community-Richtlinien für öffentliche Orte entsprechen. Um Deinen Anzeigenamen zu ändern, wähle auf der Webseite Benutzer Icon > Profil und klicke auf den \"Bearbeiten\"-Knopf. ", "commGuidePara015": "Habitica hat zwei Arten sozialer Orte: öffentliche und private. Öffentliche Orte sind das Gasthaus, öffentliche Gilden, GitHub, Trello und das Wiki. Private Orte sind private Gilden, der Gruppenchat und Private Nachrichten. Alle Anzeigenamen müssen den Community-Richtlinien für öffentliche Orte entsprechen. Um Deinen Anzeigenamen zu ändern, wähle auf der Webseite Benutzer Icon > Profil und klicke auf den \"Bearbeiten\"-Knopf. ",
"commGuidePara016": "Wenn Du Dich durch die öffentlichen Orte in Habitica bewegst, gibt es ein paar allgemeine Regeln, damit jeder sicher und glücklich ist. Diese sollten für einen Abenteurer wie Dich einfach sein!", "commGuidePara016": "Wenn Du Dich durch die öffentlichen Orte in Habitica bewegst, gibt es ein paar allgemeine Regeln, damit jeder sicher und glücklich ist. Diese sollten für einen Abenteurer wie Dich einfach sein!",
"commGuideList02A": "<strong>Respect each other</strong>. Be courteous, kind, friendly, and helpful. Remember: Habiticans come from all backgrounds and have had wildly divergent experiences. This is part of what makes Habitica so cool! Building a community means respecting and celebrating our differences as well as our similarities. Here are some easy ways to respect each other:", "commGuideList02A": "<strong>Respektiert einander</strong>. Sei höflich, freundlich und hilfsbereit. Vergiss nicht: Habiticaner kommen aus den verschiedensten Hintergründen und haben sehr andere Erfahrungen gemacht. Das macht Habitica so eigenartig! Es ist wichtig, das man beim Aufbauen einer Community seine Unterschiede und Ähnlichkeiten respektieren aber natürlich auch feiern kann. Dies sind einfache Möglichkeiten einander zu respektieren:",
"commGuideList02B": "<strong>Obey all of the <a href='/static/terms' target='_blank'>Terms and Conditions</a></strong>.", "commGuideList02B": "<strong>Befolge alle <a href='/static/terms' target='_blank'>allgemeinen Geschäftsbedingungen</a></strong>.",
"commGuideList02C": "<strong>Do not post images or text that are violent, threatening, or sexually explicit/suggestive, or that promote discrimination, bigotry, racism, sexism, hatred, harassment or harm against any individual or group</strong>. Not even as a joke. This includes slurs as well as statements. Not everyone has the same sense of humor, and so something that you consider a joke may be hurtful to another. Attack your Dailies, not each other.", "commGuideList02C": "<strong>Do not post images or text that are violent, threatening, or sexually explicit/suggestive, or that promote discrimination, bigotry, racism, sexism, hatred, harassment or harm against any individual or group</strong>. Not even as a joke. This includes slurs as well as statements. Not everyone has the same sense of humor, and so something that you consider a joke may be hurtful to another. Attack your Dailies, not each other.",
"commGuideList02D": "<strong>Keep discussions appropriate for all ages</strong>. We have many young Habiticans who use the site! Let's not tarnish any innocents or hinder any Habiticans in their goals.", "commGuideList02D": "<strong>Keep discussions appropriate for all ages</strong>. We have many young Habiticans who use the site! Let's not tarnish any innocents or hinder any Habiticans in their goals.",
"commGuideList02E": "<strong>Avoid profanity. This includes milder, religious-based oaths that may be acceptable elsewhere</strong>. We have people from all religious and cultural backgrounds, and we want to make sure that all of them feel comfortable in public spaces. <strong>If a moderator or staff member tells you that a term is disallowed on Habitica, even if it is a term that you did not realize was problematic, that decision is final</strong>. Additionally, slurs will be dealt with very severely, as they are also a violation of the Terms of Service.", "commGuideList02E": "<strong>Avoid profanity. This includes milder, religious-based oaths that may be acceptable elsewhere</strong>. We have people from all religious and cultural backgrounds, and we want to make sure that all of them feel comfortable in public spaces. <strong>If a moderator or staff member tells you that a term is disallowed on Habitica, even if it is a term that you did not realize was problematic, that decision is final</strong>. Additionally, slurs will be dealt with very severely, as they are also a violation of the Terms of Service.",
@@ -119,7 +119,7 @@
"commGuideHeadingLinks": "Nützliche Links", "commGuideHeadingLinks": "Nützliche Links",
"commGuideLink01": "<a href='/groups/guild/5481ccf3-5d2d-48a9-a871-70a7380cee5a' target='_blank'>Habitica Help: Ask a Question</a>: a Guild for users to ask questions!", "commGuideLink01": "<a href='/groups/guild/5481ccf3-5d2d-48a9-a871-70a7380cee5a' target='_blank'>Habitica Help: Ask a Question</a>: a Guild for users to ask questions!",
"commGuideLink02": "<a href='http://habitica.wikia.com/wiki/Habitica_Wiki' target='_blank'>The Wiki</a>: the biggest collection of information about Habitica.", "commGuideLink02": "<a href='http://habitica.wikia.com/wiki/Habitica_Wiki' target='_blank'>The Wiki</a>: the biggest collection of information about Habitica.",
"commGuideLink03": "<a href='https://github.com/HabitRPG/habitica' target='_blank'>GitHub</a>: for bug reports or helping with code!", "commGuideLink03": "<a href='https://github.com/HabitRPG/habitica' target='_blank'>GitHub</a>: für Fehlermeldungen oder für das Mithelfen beim Programmieren.",
"commGuideLink04": "<a href='https://trello.com/b/EpoYEYod/' target='_blank'>The Main Trello</a>: for site feature requests.", "commGuideLink04": "<a href='https://trello.com/b/EpoYEYod/' target='_blank'>The Main Trello</a>: for site feature requests.",
"commGuideLink05": "<a href='https://trello.com/b/mXK3Eavg/' target='_blank'>The Mobile Trello</a>: for mobile feature requests.", "commGuideLink05": "<a href='https://trello.com/b/mXK3Eavg/' target='_blank'>The Mobile Trello</a>: for mobile feature requests.",
"commGuideLink06": "<a href='https://trello.com/b/vwuE9fbO/' target='_blank'>The Art Trello</a>: for submitting pixel art.", "commGuideLink06": "<a href='https://trello.com/b/vwuE9fbO/' target='_blank'>The Art Trello</a>: for submitting pixel art.",

View File

@@ -49,7 +49,6 @@
"UUID": "Benutzer-ID", "UUID": "Benutzer-ID",
"loadUser": "Spieler laden", "loadUser": "Spieler laden",
"noAdminAccess": "Du hast keine Administratorrechte.", "noAdminAccess": "Du hast keine Administratorrechte.",
"pageMustBeNumber": "req.query.page muss eine Zahl sein",
"userNotFound": "Benutzer nicht gefunden.", "userNotFound": "Benutzer nicht gefunden.",
"invalidUUID": "UUID muss gültig sein", "invalidUUID": "UUID muss gültig sein",
"title": "Titel", "title": "Titel",

View File

@@ -156,7 +156,7 @@
"pkAnswer7": "Habitica uses pixel art for several reasons. In addition to the fun nostalgia factor, pixel art is very approachable to our volunteer artists who want to chip in. It's much easier to keep our pixel art consistent even when lots of different artists contribute, and it lets us quickly generate a ton of new content!", "pkAnswer7": "Habitica uses pixel art for several reasons. In addition to the fun nostalgia factor, pixel art is very approachable to our volunteer artists who want to chip in. It's much easier to keep our pixel art consistent even when lots of different artists contribute, and it lets us quickly generate a ton of new content!",
"pkQuestion8": "Wie hat Habitica das reale Leben von Leuten beeinflusst?", "pkQuestion8": "Wie hat Habitica das reale Leben von Leuten beeinflusst?",
"pkAnswer8": "You can find lots of testimonials for how Habitica has helped people here: https://habitversary.tumblr.com", "pkAnswer8": "You can find lots of testimonials for how Habitica has helped people here: https://habitversary.tumblr.com",
"pkMoreQuestions": "Do you have a question thats not on this list? Send an email to admin@habitica.com!", "pkMoreQuestions": "Hast du eine Frage, welche nicht in der Liste zu finden ist? Bitte sende uns eine Email an admin@habitica.com! ",
"pkVideo": "Video", "pkVideo": "Video",
"pkPromo": "Aktionen", "pkPromo": "Aktionen",
"pkLogo": "Logos", "pkLogo": "Logos",
@@ -283,7 +283,7 @@
"invalidLoginCredentialsLong": "Uh-oh - your email address / login name or password is incorrect.\n- Make sure they are typed correctly. Your login name and password are case-sensitive.\n- You may have signed up with Facebook or Google-sign-in, not email so double-check by trying them.\n- If you forgot your password, click \"Forgot Password\".", "invalidLoginCredentialsLong": "Uh-oh - your email address / login name or password is incorrect.\n- Make sure they are typed correctly. Your login name and password are case-sensitive.\n- You may have signed up with Facebook or Google-sign-in, not email so double-check by trying them.\n- If you forgot your password, click \"Forgot Password\".",
"invalidCredentials": "Es gibt kein Konto, das diese Anmeldedaten verwendet.", "invalidCredentials": "Es gibt kein Konto, das diese Anmeldedaten verwendet.",
"accountSuspended": "This account, User ID \"<%= userId %>\", has been blocked for breaking the [Community Guidelines](https://habitica.com/static/community-guidelines) or [Terms of Service](https://habitica.com/static/terms). For details or to ask to be unblocked, please email our Community Manager at <%= communityManagerEmail %> or ask your parent or guardian to email them. Please copy your User ID into the email and include your Profile Name.", "accountSuspended": "This account, User ID \"<%= userId %>\", has been blocked for breaking the [Community Guidelines](https://habitica.com/static/community-guidelines) or [Terms of Service](https://habitica.com/static/terms). For details or to ask to be unblocked, please email our Community Manager at <%= communityManagerEmail %> or ask your parent or guardian to email them. Please copy your User ID into the email and include your Profile Name.",
"accountSuspendedTitle": "Account has been suspended", "accountSuspendedTitle": "Dieser Account wurde suspendiert. ",
"unsupportedNetwork": "Dieses Netzwerk wird aktuell nicht unterstützt.", "unsupportedNetwork": "Dieses Netzwerk wird aktuell nicht unterstützt.",
"cantDetachSocial": "Der Account hat nur noch diese Authentifizierung, sie kann nicht getrennt werden.", "cantDetachSocial": "Der Account hat nur noch diese Authentifizierung, sie kann nicht getrennt werden.",
"onlySocialAttachLocal": "Lokale Authentifizierung kann nur zu einem Social-Media-Konto hinzugefügt werden.", "onlySocialAttachLocal": "Lokale Authentifizierung kann nur zu einem Social-Media-Konto hinzugefügt werden.",

View File

@@ -1021,7 +1021,7 @@
"headMystery201802Text": "Liebeskäfer-Helm", "headMystery201802Text": "Liebeskäfer-Helm",
"headMystery201802Notes": "Die Fühler auf diesem Helm funktionieren wie niedliche Wünschelruten, die Gefühle der Liebe und Unterstützung in der Nähe aufspüren. Gewährt keinen Attributbonus. Abonnentengegenstand, Februar 2018.", "headMystery201802Notes": "Die Fühler auf diesem Helm funktionieren wie niedliche Wünschelruten, die Gefühle der Liebe und Unterstützung in der Nähe aufspüren. Gewährt keinen Attributbonus. Abonnentengegenstand, Februar 2018.",
"headMystery201803Text": "Wagemutiges Libellendiadem", "headMystery201803Text": "Wagemutiges Libellendiadem",
"headMystery201803Notes": "Although its appearance is quite decorative, you can engage the wings on this circlet for extra lift! Confers no benefit. March 2018 Subscriber Item.", "headMystery201803Notes": "Trotz ihres dekorativen Aussehens können Dir die Flügel auf diesen Diadem extra Auftrieb geben! Gewährt keinen Attributbonus. Abonnentengegenstand, März 2018. ",
"headMystery301404Text": "Schicker Zylinder", "headMystery301404Text": "Schicker Zylinder",
"headMystery301404Notes": "Ein schicker Zylinder für die feinsten Ehrenleute! Gewährt keinen Attributbonus. Abonnentengegenstand, Januar 3015.", "headMystery301404Notes": "Ein schicker Zylinder für die feinsten Ehrenleute! Gewährt keinen Attributbonus. Abonnentengegenstand, Januar 3015.",
"headMystery301405Text": "Einfacher Zylinder", "headMystery301405Text": "Einfacher Zylinder",
@@ -1357,11 +1357,11 @@
"backMystery201709Text": "Zauberbücherstapel", "backMystery201709Text": "Zauberbücherstapel",
"backMystery201709Notes": "Magie zu erlernen erfordert eine Menge zu Lesen, aber Du bist Dir sicher, dass Dir nicht langweilig wird! Gewährt keinen Attributbonus. Abonnentengegenstand, September 2017.", "backMystery201709Notes": "Magie zu erlernen erfordert eine Menge zu Lesen, aber Du bist Dir sicher, dass Dir nicht langweilig wird! Gewährt keinen Attributbonus. Abonnentengegenstand, September 2017.",
"backMystery201801Text": "Frostkobold-Flügel", "backMystery201801Text": "Frostkobold-Flügel",
"backMystery201801Notes": "They may look as delicate as snowflakes, but these enchanted wings can carry you anywhere you wish! Confers no benefit. January 2018 Subscriber Item.", "backMystery201801Notes": "Diese verzauberten Flügel sehen vielleicht so delikat wie Schneeflocken aus, aber sie werden Dich tragen wohin du willst! Gewährt keinen Attributbonus. Abonnentengegenstand, Januar 2018.",
"backMystery201803Text": "Wagemutige Libellenflügel", "backMystery201803Text": "Wagemutige Libellenflügel",
"backMystery201803Notes": "These bright and shiny wings will carry you through soft spring breezes and across lily ponds with ease. Confers no benefit. March 2018 Subscriber Item.", "backMystery201803Notes": "Diese glänzenden, hellen Fügel werden Dich mühelos durch leichte Frühlingsbrisen und über Lilienteiche tragen. Gewährt keinen Attributbonus. Abonnentengegenstand, März 2018.",
"backMystery201804Text": "Squirrel Tail", "backMystery201804Text": "Eichörnchenschwanz",
"backMystery201804Notes": "Sure, it helps you balance while you jump on branches, but the most important thing is MAXIMUM FLUFF. Confers no benefit. April 2018 Subscriber Item.", "backMystery201804Notes": "Klar hilft dieser Schwanz Dir beim Springen von Ast zu Ast, aber viel wichtiger ist seine MAXIMALE FLAUSCHIGKEIT. Gewährt keinen Attributbonus. Abonnentengegenstand, April 2018.",
"backSpecialWonderconRedText": "Mächtiger Umhang", "backSpecialWonderconRedText": "Mächtiger Umhang",
"backSpecialWonderconRedNotes": "Strotzt vor Stärke und Schönheit. Gewährt keinen Attributbonus. Special Edition Convention-Gegenstand.", "backSpecialWonderconRedNotes": "Strotzt vor Stärke und Schönheit. Gewährt keinen Attributbonus. Special Edition Convention-Gegenstand.",
"backSpecialWonderconBlackText": "Tückischer Umhang", "backSpecialWonderconBlackText": "Tückischer Umhang",
@@ -1405,7 +1405,7 @@
"bodyMystery201706Text": "Zerlumpter Korsarenumhang", "bodyMystery201706Text": "Zerlumpter Korsarenumhang",
"bodyMystery201706Notes": "Dieser Umhang hat geheime Taschen um all das Gold zu verstecken, dass Du von Deinen Aufgaben erbeutet hast. Gewährt keinen Attributbonus. Abonnentengegenstand, Juni 2017.", "bodyMystery201706Notes": "Dieser Umhang hat geheime Taschen um all das Gold zu verstecken, dass Du von Deinen Aufgaben erbeutet hast. Gewährt keinen Attributbonus. Abonnentengegenstand, Juni 2017.",
"bodyMystery201711Text": "Teppichreiterschal", "bodyMystery201711Text": "Teppichreiterschal",
"bodyMystery201711Notes": "This soft knitted scarf looks quite majestic blowing in the wind. Confers no benefit. November 2017 Subscriber Item.", "bodyMystery201711Notes": "Dieser weiche Schal sieht sehr majestätisch aus wenn er sich leicht im Wind bewegt. Gewährt keinen Attributbonus. Abonnentengegenstand, November 2017.",
"bodyArmoireCozyScarfText": "Gemütlicher Schal", "bodyArmoireCozyScarfText": "Gemütlicher Schal",
"bodyArmoireCozyScarfNotes": "This fine scarf will keep you warm as you go about your wintry business. Increases Constitution and Perception by <%= attrs %> each. Enchanted Armoire: Lamplighter's Set (Item 4 of 4).", "bodyArmoireCozyScarfNotes": "This fine scarf will keep you warm as you go about your wintry business. Increases Constitution and Perception by <%= attrs %> each. Enchanted Armoire: Lamplighter's Set (Item 4 of 4).",
"headAccessory": "Kopfschmuck", "headAccessory": "Kopfschmuck",
@@ -1474,8 +1474,8 @@
"headAccessoryMystery201510Notes": "Diese schreckenerregenden Hörner sind ein wenig schleimig. Gewährt keinen Attributbonus. Abonnentengegenstand, Oktober 2015.", "headAccessoryMystery201510Notes": "Diese schreckenerregenden Hörner sind ein wenig schleimig. Gewährt keinen Attributbonus. Abonnentengegenstand, Oktober 2015.",
"headAccessoryMystery201801Text": "Frostkobold-Geweih", "headAccessoryMystery201801Text": "Frostkobold-Geweih",
"headAccessoryMystery201801Notes": "Dieses eigige Geweih schimmert mit dem Glanze eines Winterpolarlichts. Gewährt keinen Attributbonus. Abonnentengegenstand, Januar 2018.", "headAccessoryMystery201801Notes": "Dieses eigige Geweih schimmert mit dem Glanze eines Winterpolarlichts. Gewährt keinen Attributbonus. Abonnentengegenstand, Januar 2018.",
"headAccessoryMystery201804Text": "Squirrel Ears", "headAccessoryMystery201804Text": "Eichörnchenohren",
"headAccessoryMystery201804Notes": "These fuzzy sound-catchers will ensure you never miss the rustle of a leaf or the sound of an acorn falling! Confers no benefit. April 2018 Subscriber Item.", "headAccessoryMystery201804Notes": "Mit diesem flauschigen Geräuschfänger wirst Du nie das Rascheln eines Blatts oder das Geräusch einer fallenden Eichel verpassen! Gewährt keinen Attributbonus. Abonnentengegenstand, April 2018.",
"headAccessoryMystery301405Text": "Kopf-Brille", "headAccessoryMystery301405Text": "Kopf-Brille",
"headAccessoryMystery301405Notes": "\"Brillen sind für die Augen,\" haben sie gesagt. \"Niemand will Brillen, die man nur auf dem Kopf tragen kann,\" haben sie gesagt. Ha! Da hast Du es ihnen aber ordentlich gezeigt! Gewährt keinen Attributbonus. Abonnentengegenstand, August 3015.", "headAccessoryMystery301405Notes": "\"Brillen sind für die Augen,\" haben sie gesagt. \"Niemand will Brillen, die man nur auf dem Kopf tragen kann,\" haben sie gesagt. Ha! Da hast Du es ihnen aber ordentlich gezeigt! Gewährt keinen Attributbonus. Abonnentengegenstand, August 3015.",
"headAccessoryArmoireComicalArrowText": "Komischer Pfeil", "headAccessoryArmoireComicalArrowText": "Komischer Pfeil",

View File

@@ -5,7 +5,7 @@
"innCheckIn": "Im Gasthaus erholen", "innCheckIn": "Im Gasthaus erholen",
"innText": "Du erholst Dich im Gasthaus! Während Du dort verweilst, werden Dir Deine täglichen Aufgaben keinen Schaden zufügen, aber trotzdem täglich aktualisiert. Vorsicht: Wenn Du an einem Bosskampf teilnimmst, erhältst Du weiterhin Schaden für die verpassten Aufgaben Deiner Gruppenmitglieder, sofern sich diese nicht auch im Gasthaus befinden! Außerdem wird der Schaden, den Du dem Boss zufügst, (und gefundene Gegenstände) erst angewendet, wenn Du das Gasthaus verlässt.", "innText": "Du erholst Dich im Gasthaus! Während Du dort verweilst, werden Dir Deine täglichen Aufgaben keinen Schaden zufügen, aber trotzdem täglich aktualisiert. Vorsicht: Wenn Du an einem Bosskampf teilnimmst, erhältst Du weiterhin Schaden für die verpassten Aufgaben Deiner Gruppenmitglieder, sofern sich diese nicht auch im Gasthaus befinden! Außerdem wird der Schaden, den Du dem Boss zufügst, (und gefundene Gegenstände) erst angewendet, wenn Du das Gasthaus verlässt.",
"innTextBroken": "Du erholst Dich im Gasthaus, schätze ich ... Während Du dort verweilst, werden Dir Deine täglichen Aufgaben keinen Schaden zufügen, aber trotzdem täglich aktualisiert ... Wenn Du an einem Bosskampf teilnimmst, erhältst Du weiterhin Schaden für die verpassten Aufgaben Deiner Gruppenmitglieder ... sofern sich diese nicht auch im Gasthaus befinden ... Außerdem wird Dein Schaden am Boss (oder gesammelte Gegenstände) nicht berücksichtigt, bis Du das Gasthaus verlässt ... So müde ...", "innTextBroken": "Du erholst Dich im Gasthaus, schätze ich ... Während Du dort verweilst, werden Dir Deine täglichen Aufgaben keinen Schaden zufügen, aber trotzdem täglich aktualisiert ... Wenn Du an einem Bosskampf teilnimmst, erhältst Du weiterhin Schaden für die verpassten Aufgaben Deiner Gruppenmitglieder ... sofern sich diese nicht auch im Gasthaus befinden ... Außerdem wird Dein Schaden am Boss (oder gesammelte Gegenstände) nicht berücksichtigt, bis Du das Gasthaus verlässt ... So müde ...",
"innCheckOutBanner": "You are currently checked into the Inn. Your Dailies won't damage you and you won't make progress towards Quests.", "innCheckOutBanner": "Du hast derzeit in das Gasthaus eingecheckt. Deine Tagesaufgaben können dir nicht schaden und du erzielst keinen Fortschritt bei deinen Quests.",
"resumeDamage": "Schaden fortsetzen", "resumeDamage": "Schaden fortsetzen",
"helpfulLinks": "Weiterführende Links", "helpfulLinks": "Weiterführende Links",
"communityGuidelinesLink": "Community-Richtlinien", "communityGuidelinesLink": "Community-Richtlinien",
@@ -34,7 +34,7 @@
"communityGuidelines": "Community-Richtlinien", "communityGuidelines": "Community-Richtlinien",
"communityGuidelinesRead1": "Bitte lies unsere", "communityGuidelinesRead1": "Bitte lies unsere",
"communityGuidelinesRead2": "vor dem Chatten.", "communityGuidelinesRead2": "vor dem Chatten.",
"bannedWordUsed": "Oops! Looks like this post contains a swearword, religious oath, or reference to an addictive substance or adult topic (<%= swearWordsUsed %>). Habitica has users from all backgrounds, so we keep our chat very clean. Feel free to edit your message so you can post it!", "bannedWordUsed": "Hoppla! Es sieht so aus, als würde dieser Beitrag ein Schimpfwort oder einen religiösen Fluch enthält, oder sich auf Suchtstoffe oder nicht-jugendfreie Themen bezieht (<%= swearWordsUsed %>). Habitica hat Spieler unterschiedlichster Herkunft, weswegen wir unseren Chat besonders sauber halten wollen. Du kannst Deine Nachricht gerne überarbeiten, um sie doch noch posten zu können! ",
"bannedSlurUsed": "Dein Beitrag enthielt unangebrachten Inhalt und deine Chat Privilegien wurden Dir entzogen.", "bannedSlurUsed": "Dein Beitrag enthielt unangebrachten Inhalt und deine Chat Privilegien wurden Dir entzogen.",
"party": "Gruppe", "party": "Gruppe",
"createAParty": "Gruppe erstellen", "createAParty": "Gruppe erstellen",
@@ -106,16 +106,16 @@
"optionalMessage": "Optionale Nachricht", "optionalMessage": "Optionale Nachricht",
"yesRemove": "Ja, entferne sie", "yesRemove": "Ja, entferne sie",
"foreverAlone": "\"Gefällt mir\" funktioniert nicht bei eigenen Nachrichten. Sei nicht so einer.", "foreverAlone": "\"Gefällt mir\" funktioniert nicht bei eigenen Nachrichten. Sei nicht so einer.",
"sortDateJoinedAsc": "Frühestes Beitrittsdatum", "sortBackground": "Nach Hintergrund sortieren",
"sortDateJoinedDesc": "Letztes Beitrittsdatum", "sortClass": "Sortiere nach Klasse",
"sortLoginAsc": "Frühester Login", "sortDateJoined": "Nach Beitrittsdatum sortieren",
"sortLoginDesc": "Letzter Login", "sortLogin": "Sortiere nach Login Datum ",
"sortLevelAsc": "Niedrigster Level", "sortLevel": "Nach Level sortieren",
"sortLevelDesc": "Höchster Level", "sortName": "Sortiere nach Name",
"sortNameAsc": "Name (A - Z)", "sortTier": "Nach Rang sortieren",
"sortNameDesc": "Name (Z - A)", "ascendingAbbrev": "Aufsteigend",
"sortTierAsc": "Niedrigster Rang", "descendingAbbrev": "Absteigend",
"sortTierDesc": "Höchster Rang", "applySortToHeader": "Apply Sort Options to Party Header",
"confirmGuild": "Gilde für 4 Edelsteine gründen?", "confirmGuild": "Gilde für 4 Edelsteine gründen?",
"leaveGroupCha": "Gildenwettbewerbe verlassen und ...", "leaveGroupCha": "Gildenwettbewerbe verlassen und ...",
"confirm": "Bestätigen", "confirm": "Bestätigen",
@@ -131,6 +131,10 @@
"clearAll": "Lösche alle Nachrichten", "clearAll": "Lösche alle Nachrichten",
"confirmDeleteAllMessages": "Bist Du sicher, dass Du alle Nachrichten im Posteingang löschen möchtest? Andere Benutzer können immer noch die Nachrichten sehen, die Du ihnen geschickt hast.", "confirmDeleteAllMessages": "Bist Du sicher, dass Du alle Nachrichten im Posteingang löschen möchtest? Andere Benutzer können immer noch die Nachrichten sehen, die Du ihnen geschickt hast.",
"optOutPopover": "Du willst keine privaten Nachrichten? Klick hier um sie zu deaktivieren", "optOutPopover": "Du willst keine privaten Nachrichten? Klick hier um sie zu deaktivieren",
"PMPlaceholderTitle": "Nothing Here Yet",
"PMPlaceholderDescription": "Select a conversation on the left",
"PMPlaceholderTitleRevoked": "Your chat privileges have been revoked",
"PMPlaceholderDescriptionRevoked": "You are not able to send private messages because your chat privileges have been revoked. If you have questions or concerns about this, please email <a href=\"mailto:admin@habitica.com\">admin@habitica.com</a> to discuss it with the staff.",
"block": "Sperren", "block": "Sperren",
"unblock": "Entsperren", "unblock": "Entsperren",
"pm-reply": "Eine Antwort schicken", "pm-reply": "Eine Antwort schicken",
@@ -146,12 +150,12 @@
"report": "Melden", "report": "Melden",
"abuseFlag": "Verletzung der Community-Richtlinien melden", "abuseFlag": "Verletzung der Community-Richtlinien melden",
"abuseFlagModalHeading": "Melde einen Verstoß", "abuseFlagModalHeading": "Melde einen Verstoß",
"abuseFlagModalBody": "Are you sure you want to report this post? You should <strong>only</strong> report a post that violates the <%= firstLinkStart %>Community Guidelines<%= linkEnd %> and/or <%= secondLinkStart %>Terms of Service<%= linkEnd %>. Inappropriately reporting a post is a violation of the Community Guidelines and may give you an infraction.", "abuseFlagModalBody": "Möchtest Du diesen Beitrag wirklich melden? Du solltest <strong>ausschließlich</strong> Beiträge melden, die unsere <%= firstLinkStart %>Community-Richtlinien<%= linkEnd %> und/oder unsere <%= secondLinkStart %>Nutzungsbedingungen<%= linkEnd %> verletzen. Das ungerechtfertigte Melden von Beiträgen stellt eine Verletzung der Community-Richtlinien dar und kann geahndet werden.",
"abuseFlagModalButton": "Verstoß melden", "abuseFlagModalButton": "Verstoß melden",
"abuseReported": "Danke, dass Du diesen Verstoß gemeldet hast. Die Moderatoren wurden benachrichtigt.", "abuseReported": "Danke, dass Du diesen Verstoß gemeldet hast. Die Moderatoren wurden benachrichtigt.",
"abuseAlreadyReported": "Du hast diese Nachricht bereits gemeldet.", "abuseAlreadyReported": "Du hast diese Nachricht bereits gemeldet.",
"whyReportingPost": "Wieso meldest Du diesen Post?", "whyReportingPost": "Wieso meldest Du diesen Post?",
"whyReportingPostPlaceholder": "Please help our moderators by letting us know why you are reporting this post for a violation, e.g., spam, swearing, religious oaths, bigotry, slurs, adult topics, violence.", "whyReportingPostPlaceholder": "Bitte hilf unseren Moderatoren und gib einen Grund an, warum Du diesen Beitrag als Verstoß gemeldet hast, z.B. Spam, Fluchen, Religiöse Schwüre, Intoleranz, Beleidigungen, Nicht jugendfreie Themen, Gewalt.",
"optional": "Wahlweise", "optional": "Wahlweise",
"needsText": "Bitte gib eine Nachricht ein.", "needsText": "Bitte gib eine Nachricht ein.",
"needsTextPlaceholder": "Gib Deine Nachricht hier ein.", "needsTextPlaceholder": "Gib Deine Nachricht hier ein.",
@@ -163,7 +167,7 @@
"leaderOnlyChallenges": "Nur der Gruppenleiter kann Wettbewerbe erstellen", "leaderOnlyChallenges": "Nur der Gruppenleiter kann Wettbewerbe erstellen",
"sendGift": "Geschenk schicken", "sendGift": "Geschenk schicken",
"inviteFriends": "Lade Freunde ein", "inviteFriends": "Lade Freunde ein",
"partyMembersInfo": "Your Party currently has <%= memberCount %> members and <%= invitationCount %> pending invitations. The limit of members in a Party is <%= limitMembers %>. Invitations above this limit cannot be sent.", "partyMembersInfo": "Deine Gruppe hat aktuell <%= memberCount %> Mitglieder und <%= invitationCount %> ausstehende Einladungen. Die maximale Anzahl an Mitgliedern in einer Gruppe ist <%= limitMembers %>. Einladungen über diesem Limit können nicht verschickt werden.",
"inviteByEmail": "Lade per E-Mail ein", "inviteByEmail": "Lade per E-Mail ein",
"inviteByEmailExplanation": "Wenn Freunde über Deine E-Mail zu Habitica stoßen, werden sie automatisch zu Deiner Gruppe eingeladen!", "inviteByEmailExplanation": "Wenn Freunde über Deine E-Mail zu Habitica stoßen, werden sie automatisch zu Deiner Gruppe eingeladen!",
"inviteMembersHowTo": "Leute einladen: mit einer gültigen Email-Adresse oder der 36-stelligen Nutzer ID. Wenn eine Email-Adresse noch nicht registriert ist, laden wir diejenigen nach Habitica ein.", "inviteMembersHowTo": "Leute einladen: mit einer gültigen Email-Adresse oder der 36-stelligen Nutzer ID. Wenn eine Email-Adresse noch nicht registriert ist, laden wir diejenigen nach Habitica ein.",
@@ -197,17 +201,16 @@
"partyExplanation2": "Bekämpfe Monster und nimm an Wettbewerben teil!", "partyExplanation2": "Bekämpfe Monster und nimm an Wettbewerben teil!",
"partyExplanation3": "Lade jetzt Freunde ein und erhalte eine Questschriftrolle!", "partyExplanation3": "Lade jetzt Freunde ein und erhalte eine Questschriftrolle!",
"wantToStartParty": "Willst Du eine Gruppe gründen?", "wantToStartParty": "Willst Du eine Gruppe gründen?",
"exclusiveQuestScroll": "Inviting a friend to your Party will grant you an exclusive Quest Scroll to battle the Basi-List together!", "exclusiveQuestScroll": "Wenn Du Freunde in Deine Gruppe einlädst, erhältst Du eine exklusive Questschriftrolle, mit der ihr gemeinsam den Basi-List bekämpfen könnt!",
"nameYourParty": "Gib Deiner neuen Gruppe einen Namen!", "nameYourParty": "Gib Deiner neuen Gruppe einen Namen!",
"partyEmpty": "Du bist alleine in Deiner Gruppe. Lade Deine Freunde ein!", "partyEmpty": "Du bist alleine in Deiner Gruppe. Lade Deine Freunde ein!",
"partyChatEmpty": "Dein Gruppenchat ist leer. Tippe eine Nachricht in die Box oben, um mit dem Chat zu beginnen.", "partyChatEmpty": "Dein Gruppenchat ist leer. Tippe eine Nachricht in die Box oben, um mit dem Chat zu beginnen.",
"guildChatEmpty": "Dieser Gildenchat ist leer. Gib eine Nachricht ein und beginne mit dem Chat.", "guildChatEmpty": "Dieser Gildenchat ist leer. Gib eine Nachricht ein und beginne mit dem Chat.",
"requestAcceptGuidelines": "If you would like to post messages in the Tavern or any Party or Guild chat, please first read our <%= linkStart %>Community Guidelines<%= linkEnd %> and then click the button below to indicate that you accept them.", "requestAcceptGuidelines": "Wenn Du Nachrichten im Gasthaus oder in irgendeinem Gruppen- oder Gilden-Chat posten willst, lies bitte zuerst unsere <%= linkStart %>Community-Richtlinien<%= linkEnd %>. Klicke danach unten auf den Button, um sie zu akzeptieren.",
"partyUpName": "Party!", "partyUpName": "Party!",
"partyOnName": "Riesenparty!", "partyOnName": "Riesenparty!",
"partyUpText": "Du bist einer Gruppe mit einer anderen Person beigetreten! Ihr werdet zusammen Monster bekämpfen und euch unterstützen - viel Spaß dabei. ", "partyUpText": "Du bist einer Gruppe mit einer anderen Person beigetreten! Ihr werdet zusammen Monster bekämpfen und euch unterstützen - viel Spaß dabei. ",
"partyOnText": "Du bist einer Gruppe mit mindestens vier Personen beigetreten! Erkenne die Vorteile einer erhöhten Verantwortung während Du Dich mit Deinen Freunden vereinst, um Eure Gegner zu besiegen!", "partyOnText": "Du bist einer Gruppe mit mindestens vier Personen beigetreten! Erkenne die Vorteile einer erhöhten Verantwortung während Du Dich mit Deinen Freunden vereinst, um Eure Gegner zu besiegen!",
"groupIdRequired": "\"groupId\" muss eine gültige UUID sein",
"groupNotFound": "Team nicht gefunden, oder Du hast keine Zugriffsrechte.", "groupNotFound": "Team nicht gefunden, oder Du hast keine Zugriffsrechte.",
"groupTypesRequired": "Du musst einen gültigen \"Type\" Suchbegriff eingeben.", "groupTypesRequired": "Du musst einen gültigen \"Type\" Suchbegriff eingeben.",
"questLeaderCannotLeaveGroup": "Du kannst Deine Gruppe nicht verlassen, wenn Du eine Quest gestartet hast. Brich die Quest zuvor ab.", "questLeaderCannotLeaveGroup": "Du kannst Deine Gruppe nicht verlassen, wenn Du eine Quest gestartet hast. Brich die Quest zuvor ab.",
@@ -217,15 +220,13 @@
"memberCannotRemoveYourself": "Du kannst Dich nicht selbst entfernen!", "memberCannotRemoveYourself": "Du kannst Dich nicht selbst entfernen!",
"groupMemberNotFound": "Benutzer nicht unter den Team-Mitgliedern gefunden", "groupMemberNotFound": "Benutzer nicht unter den Team-Mitgliedern gefunden",
"mustBeGroupMember": "Muss ein Mitglied des Teams sein.", "mustBeGroupMember": "Muss ein Mitglied des Teams sein.",
"keepOrRemoveAll": "req.query.keep muss entweder \"keep-all\" oder \"remove-all\" sein",
"keepOrRemove": "req.query.keep muss entweder \"keep\" oder \"remove\" sein",
"canOnlyInviteEmailUuid": "Es kann nur mittels UUID oder E-Mail eingeladen werden.", "canOnlyInviteEmailUuid": "Es kann nur mittels UUID oder E-Mail eingeladen werden.",
"inviteMissingEmail": "Fehlende E-Mail-Adresse zum Einladen.", "inviteMissingEmail": "Fehlende E-Mail-Adresse zum Einladen.",
"inviteMissingUuid": "User-ID in der Einladung fehlt", "inviteMissingUuid": "User-ID in der Einladung fehlt",
"inviteMustNotBeEmpty": "Einladung muss Daten enthalten", "inviteMustNotBeEmpty": "Einladung muss Daten enthalten",
"partyMustbePrivate": "Gruppen müssen privat sein", "partyMustbePrivate": "Gruppen müssen privat sein",
"userAlreadyInGroup": "Nutzer-ID: <%= userId %>, Nutzer \"<%= username %>\" ist bereits in dieser Gruppe.", "userAlreadyInGroup": "Nutzer-ID: <%= userId %>, Nutzer \"<%= username %>\" ist bereits in dieser Gruppe.",
"youAreAlreadyInGroup": "You are already a member of this group.", "youAreAlreadyInGroup": "Du bist bereits Mitglied dieser Gruppe. ",
"cannotInviteSelfToGroup": "Du kannst Dich nicht selbst in eine Gruppe einladen.", "cannotInviteSelfToGroup": "Du kannst Dich nicht selbst in eine Gruppe einladen.",
"userAlreadyInvitedToGroup": "Nutzer-ID: <%= userId %>, Nutzer \"<%= username %>\" wurde bereits zu dieser Gruppe eingeladen.", "userAlreadyInvitedToGroup": "Nutzer-ID: <%= userId %>, Nutzer \"<%= username %>\" wurde bereits zu dieser Gruppe eingeladen.",
"userAlreadyPendingInvitation": "Nutzer-ID: <%= userId %>, Nutzer \"<%= username %>\" hat bereits eine ausstehende Einladung.", "userAlreadyPendingInvitation": "Nutzer-ID: <%= userId %>, Nutzer \"<%= username %>\" hat bereits eine ausstehende Einladung.",
@@ -248,13 +249,13 @@
"confirmClaim": "Bist Du sicher, dass Du diese Aufgabe beanspruchen möchtest?", "confirmClaim": "Bist Du sicher, dass Du diese Aufgabe beanspruchen möchtest?",
"confirmUnClaim": "Bist Du sicher, dass Du diese Aufgabe abgeben möchtest?", "confirmUnClaim": "Bist Du sicher, dass Du diese Aufgabe abgeben möchtest?",
"confirmApproval": "Bist Du sicher, dass Du diese Aufgabe bestätigen möchtest?", "confirmApproval": "Bist Du sicher, dass Du diese Aufgabe bestätigen möchtest?",
"confirmNeedsWork": "Are you sure you want to mark this task as needing work?", "confirmNeedsWork": "Bist Du sicher, dass Du diese Aufgabe auf \"Benötigt Arbeit\" setzen möchtest?",
"userRequestsApproval": "<%= userName %> beantragt eine Bestätigung", "userRequestsApproval": "<%= userName %> beantragt eine Bestätigung",
"userCountRequestsApproval": "<%= userCount %> beantragen eine Bestätigung", "userCountRequestsApproval": "<%= userCount %> beantragen eine Bestätigung",
"youAreRequestingApproval": "Du beantragst eine Bestätigung", "youAreRequestingApproval": "Du beantragst eine Bestätigung",
"chatPrivilegesRevoked": "You cannot do that because your chat privileges have been revoked.", "chatPrivilegesRevoked": "Du kannst dies nicht tun, da Dir Deine Chat-Privilegien entzogen wurden.",
"cannotCreatePublicGuildWhenMuted": "You cannot create a public guild because your chat privileges have been revoked.", "cannotCreatePublicGuildWhenMuted": "Du kannst keine öffentliche Gilde erstellen, da Dir Deine Chat-Privilegien entzogen wurden.",
"cannotInviteWhenMuted": "You cannot invite anyone to a guild or party because your chat privileges have been revoked.", "cannotInviteWhenMuted": "Du kannst niemanden zu einer Gruppe oder Gilde einladen, da Dir Deine Chat-Privilegien entzogen wurden.",
"newChatMessagePlainNotification": "Neue Nachricht in <%= groupName %> von <%= authorName %>. Hier geht's zur Chat Seite!", "newChatMessagePlainNotification": "Neue Nachricht in <%= groupName %> von <%= authorName %>. Hier geht's zur Chat Seite!",
"newChatMessageTitle": "Neue Nachricht in <%= groupName %>", "newChatMessageTitle": "Neue Nachricht in <%= groupName %>",
"exportInbox": "Nachrichten exportieren", "exportInbox": "Nachrichten exportieren",
@@ -268,7 +269,7 @@
"groupHomeTitle": "Startseite", "groupHomeTitle": "Startseite",
"assignTask": "Aufgabe zuweisen", "assignTask": "Aufgabe zuweisen",
"claim": "Anspruch", "claim": "Anspruch",
"removeClaim": "Remove Claim", "removeClaim": "Anspruch abtreten",
"onlyGroupLeaderCanManageSubscription": "Nur der Team-Leiter kann Team-Registrierungen verwalten", "onlyGroupLeaderCanManageSubscription": "Nur der Team-Leiter kann Team-Registrierungen verwalten",
"yourTaskHasBeenApproved": "Your task <span class=\"notification-green\"><%= taskText %></span> has been approved.", "yourTaskHasBeenApproved": "Your task <span class=\"notification-green\"><%= taskText %></span> has been approved.",
"taskNeedsWork": "<span class=\"notification-bold\"><%= managerName %></span> marked <span class=\"notification-bold\"><%= taskText %></span> as needing additional work.", "taskNeedsWork": "<span class=\"notification-bold\"><%= managerName %></span> marked <span class=\"notification-bold\"><%= taskText %></span> as needing additional work.",
@@ -315,7 +316,7 @@
"approvalsTitle": "Aufgaben-Zustimmung erwartet", "approvalsTitle": "Aufgaben-Zustimmung erwartet",
"upgradeTitle": "Upgrade", "upgradeTitle": "Upgrade",
"blankApprovalsDescription": "Wenn Dein Team Aufgaben erledigt, die deine Zustimmung brauchen, erscheinen sie hier! Passe die Zustimmungs-Einstellungen in den Aufgaben an.", "blankApprovalsDescription": "Wenn Dein Team Aufgaben erledigt, die deine Zustimmung brauchen, erscheinen sie hier! Passe die Zustimmungs-Einstellungen in den Aufgaben an.",
"userIsClamingTask": "`<%= username %> hat \"<%= task %>\"` eingefordert", "userIsClamingTask": "`<%= username %> has claimed:` <%= task %>",
"approvalRequested": "Zustimmung erbeten", "approvalRequested": "Zustimmung erbeten",
"refreshApprovals": "Zustimmungen aktualisieren", "refreshApprovals": "Zustimmungen aktualisieren",
"refreshGroupTasks": "Team-Aufgaben aktualisieren", "refreshGroupTasks": "Team-Aufgaben aktualisieren",
@@ -323,7 +324,6 @@
"cantDeleteAssignedGroupTasks": "Du kannst Team-Aufgaben, die Dir zugewiesen wurden, nicht löschen.", "cantDeleteAssignedGroupTasks": "Du kannst Team-Aufgaben, die Dir zugewiesen wurden, nicht löschen.",
"confirmGuildPlanCreation": "Dieses Team erstellen?", "confirmGuildPlanCreation": "Dieses Team erstellen?",
"onlyGroupLeaderCanInviteToGroupPlan": "Nur der Teamleiter kann Nutzer zu einem Team mit einem Abonnement hinzufügen.", "onlyGroupLeaderCanInviteToGroupPlan": "Nur der Teamleiter kann Nutzer zu einem Team mit einem Abonnement hinzufügen.",
"remainOrLeaveChallenges": "req.query.keep muss entweder 'remain-in-challenges' oder 'leave-challenges' sein",
"paymentDetails": "Zahlungsinformationen", "paymentDetails": "Zahlungsinformationen",
"aboutToJoinCancelledGroupPlan": "Du bist dabei einem Team mit gekündigtem Plan beizutreten. Du erhältst KEIN freies Abonnement.", "aboutToJoinCancelledGroupPlan": "Du bist dabei einem Team mit gekündigtem Plan beizutreten. Du erhältst KEIN freies Abonnement.",
"cannotChangeLeaderWithActiveGroupPlan": "Du kannst den Leiter nicht ändern während das Team einen aktiven Plan hat.", "cannotChangeLeaderWithActiveGroupPlan": "Du kannst den Leiter nicht ändern während das Team einen aktiven Plan hat.",
@@ -366,9 +366,11 @@
"recentActivity": "Kürzliche Aktivitäten", "recentActivity": "Kürzliche Aktivitäten",
"myGuilds": "Meine Gilden", "myGuilds": "Meine Gilden",
"guildsDiscovery": "Gilden entdecken", "guildsDiscovery": "Gilden entdecken",
"role": "Role",
"guildOrPartyLeader": "Leiter", "guildOrPartyLeader": "Leiter",
"guildLeader": "Gildenleiter", "guildLeader": "Gildenleiter",
"member": "Mitglied", "member": "Mitglied",
"guildSize": "Guild Size",
"goldTier": "Gold", "goldTier": "Gold",
"silverTier": "Silber", "silverTier": "Silber",
"bronzeTier": "Bronze", "bronzeTier": "Bronze",
@@ -424,10 +426,10 @@
"managerAdded": "Manager erfolgreich hinzugefügt", "managerAdded": "Manager erfolgreich hinzugefügt",
"managerRemoved": "Manager erfolgreich entfernt", "managerRemoved": "Manager erfolgreich entfernt",
"leaderChanged": "Gruppenleitung wurde gewechselt", "leaderChanged": "Gruppenleitung wurde gewechselt",
"groupNoNotifications": "This Guild does not have notifications due to member size. Be sure to check back often for replies to your messages!", "groupNoNotifications": "Diese Gilde ist zu groß, um Hinweismeldungen zu unterstützen! Schau öfter rein, um keine Antwort auf Deine Nachrichten zu verpassen!",
"whatIsWorldBoss": "Was ist ein Weltboss?", "whatIsWorldBoss": "Was ist ein Weltboss?",
"worldBossDesc": "A World Boss is a special event that brings the Habitica community together to take down a powerful monster with their tasks! All Habitica users are rewarded upon its defeat, even those who have been resting in the Inn or have not used Habitica for the entirety of the quest.", "worldBossDesc": "Ein Weltboss ist ein besonderes Ereignis, bei dem die ganze Habitica Community zusammen arbeitet, um ein mächtiges Monster durch ihre Aufgaben zu besiegen! Alle Benutzer Habiticas erhalten nach dem Sieg eine Belohnung, sogar diejenigen, die im Gasthaus waren oder Habitica während der ganzen Quest nicht genutzt haben.",
"worldBossLink": "Read more about the previous World Bosses of Habitica on the Wiki.", "worldBossLink": "Erfahre mehr über die vorigen Weltbosse von Habitica im Wiki.",
"worldBossBullet1": "Erfülle Deine Aufgaben, um dem Welt-Boss Schaden zuzufügen", "worldBossBullet1": "Erfülle Deine Aufgaben, um dem Welt-Boss Schaden zuzufügen",
"worldBossBullet2": "Der Welt-Boss wird Dir keinen Schaden für nicht erledigte Aufgaben zufügen, aber sein Raserei-Balken wird ansteigen. Wenn dieser voll ist, wird der Boss einen von Habiticas Händlern angreifen!", "worldBossBullet2": "Der Welt-Boss wird Dir keinen Schaden für nicht erledigte Aufgaben zufügen, aber sein Raserei-Balken wird ansteigen. Wenn dieser voll ist, wird der Boss einen von Habiticas Händlern angreifen!",
"worldBossBullet3": "Du kannst weiterhin Quest-Bosse bekämpfen, Dein Schaden wird beiden zugefügt werden.", "worldBossBullet3": "Du kannst weiterhin Quest-Bosse bekämpfen, Dein Schaden wird beiden zugefügt werden.",
@@ -436,16 +438,16 @@
"groupPlanTitle": "Need more for your crew?", "groupPlanTitle": "Need more for your crew?",
"groupPlanDesc": "Managing a small team or organizing household chores? Our group plans grant you exclusive access to a private task board and chat area dedicated to you and your group members!", "groupPlanDesc": "Managing a small team or organizing household chores? Our group plans grant you exclusive access to a private task board and chat area dedicated to you and your group members!",
"billedMonthly": "*billed as a monthly subscription", "billedMonthly": "*billed as a monthly subscription",
"teamBasedTasksList": "Team-Based Task List", "teamBasedTasksList": "Teambasierte Aufgabenliste",
"teamBasedTasksListDesc": "Set up an easily-viewed shared task list for the group. Assign tasks to your fellow group members, or let them claim their own tasks to make it clear what everyone is working on!", "teamBasedTasksListDesc": "Set up an easily-viewed shared task list for the group. Assign tasks to your fellow group members, or let them claim their own tasks to make it clear what everyone is working on!",
"groupManagementControls": "Group Management Controls", "groupManagementControls": "Group Management Controls",
"groupManagementControlsDesc": "Use task approvals to verify that a task that was really completed, add Group Managers to share responsibilities, and enjoy a private group chat for all team members.", "groupManagementControlsDesc": "Use task approvals to verify that a task that was really completed, add Group Managers to share responsibilities, and enjoy a private group chat for all team members.",
"inGameBenefits": "In-Game Benefits", "inGameBenefits": "In-Game Benefits",
"inGameBenefitsDesc": "Group members get an exclusive Jackalope Mount, as well as full subscription benefits, including special monthly equipment sets and the ability to buy gems with gold.", "inGameBenefitsDesc": "Group members get an exclusive Jackalope Mount, as well as full subscription benefits, including special monthly equipment sets and the ability to buy gems with gold.",
"inspireYourParty": "Inspire your party, gamify life together.", "inspireYourParty": "Inspire your party, gamify life together.",
"letsMakeAccount": "First, lets make you an account", "letsMakeAccount": "Lass uns dir als erstes einen Account erstellen",
"nameYourGroup": "Next, Name Your Group", "nameYourGroup": "Wähle als nächstes einen Namen für deine Gruppe",
"exampleGroupName": "Example: Avengers Academy", "exampleGroupName": "Beispiel: Avangers Academy",
"exampleGroupDesc": "For those selected to join the training academy for The Avengers Superhero Initiative", "exampleGroupDesc": "For those selected to join the training academy for The Avengers Superhero Initiative",
"thisGroupInviteOnly": "This group is invitation only.", "thisGroupInviteOnly": "This group is invitation only.",
"gettingStarted": "Getting Started", "gettingStarted": "Getting Started",
@@ -454,12 +456,12 @@
"whatsIncludedGroupDesc": "All members of the Group receive full subscription benefits, including the monthly subscriber items, the ability to buy Gems with Gold, and the Royal Purple Jackalope mount, which is exclusive to users with a Group Plan membership.", "whatsIncludedGroupDesc": "All members of the Group receive full subscription benefits, including the monthly subscriber items, the ability to buy Gems with Gold, and the Royal Purple Jackalope mount, which is exclusive to users with a Group Plan membership.",
"howDoesBillingWork": "How does billing work?", "howDoesBillingWork": "How does billing work?",
"howDoesBillingWorkDesc": "Group Leaders are billed based on group member count on a monthly basis. This charge includes the $9 (USD) price for the Group Leader subscription, plus $3 USD for each additional group member. For example: A group of four users will cost $18 USD/month, as the group consists of 1 Group Leader + 3 group members.", "howDoesBillingWorkDesc": "Group Leaders are billed based on group member count on a monthly basis. This charge includes the $9 (USD) price for the Group Leader subscription, plus $3 USD for each additional group member. For example: A group of four users will cost $18 USD/month, as the group consists of 1 Group Leader + 3 group members.",
"howToAssignTask": "How do you assign a Task?", "howToAssignTask": "Wie weise ich eine Aufgabe zu? ",
"howToAssignTaskDesc": "Assign any Task to one or more Group members (including the Group Leader or Managers themselves) by entering their usernames in the \"Assign To\" field within the Create Task modal. You can also decide to assign a Task after creating it, by editing the Task and adding the user in the \"Assign To\" field!", "howToAssignTaskDesc": "Assign any Task to one or more Group members (including the Group Leader or Managers themselves) by entering their usernames in the \"Assign To\" field within the Create Task modal. You can also decide to assign a Task after creating it, by editing the Task and adding the user in the \"Assign To\" field!",
"howToRequireApproval": "How do you mark a Task as requiring approval?", "howToRequireApproval": "How do you mark a Task as requiring approval?",
"howToRequireApprovalDesc": "Toggle the \"Requires Approval\" setting to mark a specific task as requiring Group Leader or Manager confirmation. The user who checked off the task won't get their rewards for completing it until it has been approved.", "howToRequireApprovalDesc": "Toggle the \"Requires Approval\" setting to mark a specific task as requiring Group Leader or Manager confirmation. The user who checked off the task won't get their rewards for completing it until it has been approved.",
"howToRequireApprovalDesc2": "Group Leaders and Managers can approve completed Tasks directly from the Task Board or from the Notifications panel.", "howToRequireApprovalDesc2": "Group Leaders and Managers can approve completed Tasks directly from the Task Board or from the Notifications panel.",
"whatIsGroupManager": "What is a Group Manager?", "whatIsGroupManager": "Was ist ein Gruppen Manager? ",
"whatIsGroupManagerDesc": "A Group Manager is a user role that do not have access to the group's billing details, but can create, assign, and approve shared Tasks for the Group's members. Promote Group Managers from the Groups member list.", "whatIsGroupManagerDesc": "A Group Manager is a user role that do not have access to the group's billing details, but can create, assign, and approve shared Tasks for the Group's members. Promote Group Managers from the Groups member list.",
"goToTaskBoard": "Go to Task Board" "goToTaskBoard": "Gehe zum Aufgabenbrett"
} }

View File

@@ -25,7 +25,7 @@
"tip23": "Erreiche Level 100, um die Sphäre der Wiedergeburt kostenlos zu erhalten und ein neues Abenteuer zu beginnen.", "tip23": "Erreiche Level 100, um die Sphäre der Wiedergeburt kostenlos zu erhalten und ein neues Abenteuer zu beginnen.",
"tip24": "Du hast eine Frage? Stelle sie in der Habitica Help Gilde!", "tip24": "Du hast eine Frage? Stelle sie in der Habitica Help Gilde!",
"tip25": "Die vier großen Galas der Jahreszeiten starten um die Sonnenwenden und Tagundnachtgleichen.", "tip25": "Die vier großen Galas der Jahreszeiten starten um die Sonnenwenden und Tagundnachtgleichen.",
"tip26": "You can look for a Party or find Party members in the Party Wanted Guild!", "tip26": "Du kannst dich nach einer Gruppe umsehen oder Gruppenmitglieder in der Gruppe-Gesucht-Gilde finden!",
"tip27": "Du hast gestern eine tägliche Aufgabe abgeschlossen, aber vergessen, sie abzuhaken? Mach Dir keine Sorgen! Mit der Funktion \"Gestrige Aktivität aufzeichnen\" hast Du die Chance, einzutragen, was Du gemacht hast, bevor Du einen neuen Tag startest.", "tip27": "Du hast gestern eine tägliche Aufgabe abgeschlossen, aber vergessen, sie abzuhaken? Mach Dir keine Sorgen! Mit der Funktion \"Gestrige Aktivität aufzeichnen\" hast Du die Chance, einzutragen, was Du gemacht hast, bevor Du einen neuen Tag startest.",
"tip28": "Setze Deinen Tageswechsel individuell unter Benutzer Icon > Einstellungen, um festzulegen, wann Dein Tag beginnt.", "tip28": "Setze Deinen Tageswechsel individuell unter Benutzer Icon > Einstellungen, um festzulegen, wann Dein Tag beginnt.",
"tip29": "Erledige alle Deine Tagesaufgaben und Du erhältst einen Perfekter-Tag-Bonus, der Deine Attribute erhöht!", "tip29": "Erledige alle Deine Tagesaufgaben und Du erhältst einen Perfekter-Tag-Bonus, der Deine Attribute erhöht!",

View File

@@ -48,6 +48,7 @@
"featuredItems": "Besondere Empfehlungen!", "featuredItems": "Besondere Empfehlungen!",
"hideLocked": "Gesperrte verbergen", "hideLocked": "Gesperrte verbergen",
"hidePinned": "In der Pinnwand angezeigte verbergen", "hidePinned": "In der Pinnwand angezeigte verbergen",
"hideMissing": "Hide Missing",
"amountExperience": "<%= amount %> Erfahrung", "amountExperience": "<%= amount %> Erfahrung",
"amountGold": "<%= amount %> Gold", "amountGold": "<%= amount %> Gold",
"namedHatchingPotion": "<%= type %> Schlüpfelixier", "namedHatchingPotion": "<%= type %> Schlüpfelixier",
@@ -74,20 +75,13 @@
"ianTextMobile": "Kann ich Dein Interesse an einigen Questschriftrollen wecken? Aktiviere sie um mit deiner Gruppe Monster zu bekämpfen!", "ianTextMobile": "Kann ich Dein Interesse an einigen Questschriftrollen wecken? Aktiviere sie um mit deiner Gruppe Monster zu bekämpfen!",
"ianBrokenText": "Willkommen im Quest-Shop ... Hier kannst Du Questschriftrollen besorgen, um mit Deinen Freunden Monster zu bekämpfen ... Durchstöbere unsere große Anzahl an Schriftrollen und investiere in die Richtige ...", "ianBrokenText": "Willkommen im Quest-Shop ... Hier kannst Du Questschriftrollen besorgen, um mit Deinen Freunden Monster zu bekämpfen ... Durchstöbere unsere große Anzahl an Schriftrollen und investiere in die Richtige ...",
"featuredQuests": "Empfohlene Quests!", "featuredQuests": "Empfohlene Quests!",
"missingKeyParam": "\"req.params.key\" wird benötigt.",
"itemNotFound": "Eintrag \"<%= key %>\" nicht gefunden.",
"cannotBuyItem": "Du kannst diesen Gegenstand nicht kaufen.", "cannotBuyItem": "Du kannst diesen Gegenstand nicht kaufen.",
"missingTypeKeyEquip": "\"Schlüssel\" und \"Typ\" sind erforderliche Parameter.",
"missingPetFoodFeed": "\"Haustier\" und \"Futter\" sind erforderliche Parameter.",
"invalidPetName": "Haustier-Name ist ungültig.",
"missingEggHatchingPotionHatch": "\"Ei\" und \"Schlüpfelixier\" sind erforderliche Parameter.",
"invalidTypeEquip": "\"Typ\" muss eines der folgenden sein: 'ausgerüstet', 'Haustier', 'Reittier', 'Kostüm'.",
"mustPurchaseToSet": "Du musst <%= val %> kaufen, um es auf <%= key %> zu setzen.", "mustPurchaseToSet": "Du musst <%= val %> kaufen, um es auf <%= key %> zu setzen.",
"typeRequired": "Typ ist erforderlich", "typeRequired": "Typ ist erforderlich",
"positiveAmountRequired": "Positiver Betrag benötigt", "positiveAmountRequired": "Positiver Betrag benötigt",
"notAccteptedType": "Typ muss eins der Folgenden sein: [Eier, Schlüpftränke, Premium-Schlüpftränke, Futter, Quests, Ausrüstung]", "notAccteptedType": "Typ muss eins der Folgenden sein: [Eier, Schlüpftränke, Premium-Schlüpftränke, Futter, Quests, Ausrüstung]",
"contentKeyNotFound": "Schlüssel für Inhalt <%= type %> nicht gefunden", "contentKeyNotFound": "Schlüssel für Inhalt <%= type %> nicht gefunden",
"plusGem": "+<%= count %> Gem", "plusGem": "+<%= count %> Edelstein",
"typeNotSellable": "Typ ist nicht verkäuflich. Dieser muss einer der Folgenden sein: <%= acceptedTypes %>", "typeNotSellable": "Typ ist nicht verkäuflich. Dieser muss einer der Folgenden sein: <%= acceptedTypes %>",
"userItemsKeyNotFound": "Schlüssel für user.items <%= type %> nicht gefunden", "userItemsKeyNotFound": "Schlüssel für user.items <%= type %> nicht gefunden",
"userItemsNotEnough": "Du hast nicht genug <%= type %>", "userItemsNotEnough": "Du hast nicht genug <%= type %>",

View File

@@ -96,7 +96,6 @@
"questInvitationDoesNotExist": "Es wurde noch keine Questeinladung verschickt.", "questInvitationDoesNotExist": "Es wurde noch keine Questeinladung verschickt.",
"questInviteNotFound": "Keine Questeinladung gefunden.", "questInviteNotFound": "Keine Questeinladung gefunden.",
"guildQuestsNotSupported": "Gilden können nicht zu Quests eingeladen werden.", "guildQuestsNotSupported": "Gilden können nicht zu Quests eingeladen werden.",
"questNotFound": "Quest \"<%= key %>\" nicht gefunden.",
"questNotOwned": "Du besitzt diese Quest-Schriftrolle nicht.", "questNotOwned": "Du besitzt diese Quest-Schriftrolle nicht.",
"questNotGoldPurchasable": "Quest \"<%= key %>\" ist nicht mit Gold käuflich.", "questNotGoldPurchasable": "Quest \"<%= key %>\" ist nicht mit Gold käuflich.",
"questLevelTooHigh": "Du musst Level <%= level %> haben, um diese Quest zu starten.", "questLevelTooHigh": "Du musst Level <%= level %> haben, um diese Quest zu starten.",

View File

@@ -599,6 +599,8 @@
"questSquirrelNotes": "You wake up and find youve overslept! Why didnt your alarm go off? … How did an acorn get stuck in the ringer?<br><br>When you try to make breakfast, the toaster is stuffed with acorns. When you go to retrieve your mount, @Shtut is there, trying unsuccessfully to unlock their stable. They look into the keyhole. “Is that an acorn in there?”<br><br>@randomdaisy cries out, “Oh no! I knew my pet squirrels had gotten out, but I didnt know theyd made such trouble! Can you help me round them up before they make any more of a mess?”<br><br>Following the trail of mischievously placed oak nuts, you track and catch the wayward sciurines, with @Cantras helping secure each one safely at home. But just when you think your task is almost complete, an acorn bounces off your helm! You look up to see a mighty beast of a squirrel, crouched in defense of a prodigious pile of seeds.<br><br>“Oh dear,” says @randomdaisy, softly. “Shes always been something of a resource guarder. Well have to proceed very carefully!” You circle up with your party, ready for trouble!", "questSquirrelNotes": "You wake up and find youve overslept! Why didnt your alarm go off? … How did an acorn get stuck in the ringer?<br><br>When you try to make breakfast, the toaster is stuffed with acorns. When you go to retrieve your mount, @Shtut is there, trying unsuccessfully to unlock their stable. They look into the keyhole. “Is that an acorn in there?”<br><br>@randomdaisy cries out, “Oh no! I knew my pet squirrels had gotten out, but I didnt know theyd made such trouble! Can you help me round them up before they make any more of a mess?”<br><br>Following the trail of mischievously placed oak nuts, you track and catch the wayward sciurines, with @Cantras helping secure each one safely at home. But just when you think your task is almost complete, an acorn bounces off your helm! You look up to see a mighty beast of a squirrel, crouched in defense of a prodigious pile of seeds.<br><br>“Oh dear,” says @randomdaisy, softly. “Shes always been something of a resource guarder. Well have to proceed very carefully!” You circle up with your party, ready for trouble!",
"questSquirrelCompletion": "With a gentle approach, offers of trade, and a few soothing spells, youre able to coax the squirrel away from its hoard and back to the stables, which @Shtut has just finished de-acorning. Theyve set aside a few of the acorns on a worktable. “These ones are squirrel eggs! Maybe you can raise some that dont play with their food quite so much.”", "questSquirrelCompletion": "With a gentle approach, offers of trade, and a few soothing spells, youre able to coax the squirrel away from its hoard and back to the stables, which @Shtut has just finished de-acorning. Theyve set aside a few of the acorns on a worktable. “These ones are squirrel eggs! Maybe you can raise some that dont play with their food quite so much.”",
"questSquirrelBoss": "Sneaky Squirrel", "questSquirrelBoss": "Sneaky Squirrel",
"questSquirrelDropSquirrelEgg": "Squirrel (Egg)", "questSquirrelDropSquirrelEgg": "Eichörnchen (Ei)",
"questSquirrelUnlockText": "Unlocks purchasable Squirrel eggs in the Market" "questSquirrelUnlockText": "Ermöglicht den Kauf von Eichörncheneiern auf dem Marktplatz ",
"cuddleBuddiesText": "Cuddle Buddies Quest Bundle",
"cuddleBuddiesNotes": "Contains 'The Killer Bunny', 'The Nefarious Ferret', and 'The Guinea Pig Gang'. Available until May 31."
} }

View File

@@ -32,7 +32,7 @@
"resetAccPop": "Starte neu, dabei werden alle Level, Gold, Ausrüstung, Verlauf und Aufgaben entfernt.", "resetAccPop": "Starte neu, dabei werden alle Level, Gold, Ausrüstung, Verlauf und Aufgaben entfernt.",
"deleteAccount": "Konto löschen", "deleteAccount": "Konto löschen",
"deleteAccPop": "Kündige und entferne Dein Habitica-Konto.", "deleteAccPop": "Kündige und entferne Dein Habitica-Konto.",
"feedback": "If you'd like to give us feedback, please enter it below - we'd love to know what you liked or didn't like about Habitica! Don't speak English well? No problem! Use the language you prefer.", "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.",
"qrCode": "QR-Code", "qrCode": "QR-Code",
"dataExport": "Daten exportieren", "dataExport": "Daten exportieren",
"saveData": "Hier sind ein paar Möglichkeiten Deine Daten zu sichern.", "saveData": "Hier sind ein paar Möglichkeiten Deine Daten zu sichern.",

View File

@@ -2,8 +2,8 @@
"spellWizardFireballText": "Flammenstoß", "spellWizardFireballText": "Flammenstoß",
"spellWizardFireballNotes": "Du erhältst XP und fügst Bossen zusätzlichen Schaden zu! (Basiert auf: INT)", "spellWizardFireballNotes": "Du erhältst XP und fügst Bossen zusätzlichen Schaden zu! (Basiert auf: INT)",
"spellWizardMPHealText": "Ätherischer Schwall", "spellWizardMPHealText": "Ätherischer Schwall",
"spellWizardMPHealNotes": "You sacrifice Mana so the rest of your Party, except Mages, gains MP! (Based on: INT)", "spellWizardMPHealNotes": "Du opferst Mana, demit der Rest deiner Gruppe, außer Magiern, MP erhält! (Basierend auf: INT)",
"spellWizardNoEthOnMage": "Your Skill backfires when mixed with another's magic. Only non-Mages gain MP.", "spellWizardNoEthOnMage": "Dein Zauberspruch geht nach hinten los, wenn er mit der Magie eines anderen gemischt wird. Nur nicht-Magier erhalten MP.",
"spellWizardEarthText": "Erdbeben", "spellWizardEarthText": "Erdbeben",
"spellWizardEarthNotes": "Deine mentalen Kräfte bringen die Erde zum Beben und hebt die Intelligenz Deiner Gruppe an! (Basiert auf: INT ohne Boni)", "spellWizardEarthNotes": "Deine mentalen Kräfte bringen die Erde zum Beben und hebt die Intelligenz Deiner Gruppe an! (Basiert auf: INT ohne Boni)",
"spellWizardFrostText": "Klirrender Frost", "spellWizardFrostText": "Klirrender Frost",
@@ -51,7 +51,6 @@
"spellSpecialSeafoamNotes": "Verwandle einen Freund in ein Meereslebewesen!", "spellSpecialSeafoamNotes": "Verwandle einen Freund in ein Meereslebewesen!",
"spellSpecialSandText": "Sand", "spellSpecialSandText": "Sand",
"spellSpecialSandNotes": "Hebe den Spruch auf, der einen Seestern aus Dir gemacht hat.", "spellSpecialSandNotes": "Hebe den Spruch auf, der einen Seestern aus Dir gemacht hat.",
"spellNotFound": "Fähigkeit \"<%= spellId %>\" nicht gefunden.",
"partyNotFound": "Gruppe nicht gefunden", "partyNotFound": "Gruppe nicht gefunden",
"targetIdUUID": "\"targetId\" muss eine gültige Benutzer-ID sein.", "targetIdUUID": "\"targetId\" muss eine gültige Benutzer-ID sein.",
"challengeTasksNoCast": "Fähigkeiten auf Wettbewerbsaufgaben anzuwenden ist nicht erlaubt.", "challengeTasksNoCast": "Fähigkeiten auf Wettbewerbsaufgaben anzuwenden ist nicht erlaubt.",

Some files were not shown because too many files have changed in this diff Show More