mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-16 14:17:22 +01:00
Merge branch 'develop' into party-chat-translations
This commit is contained in:
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -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)
|
||||
|
||||
[//]: # (Put Issue # or URL here, if applicable. This will automatically close the issue if your PR is merged in)
|
||||
Fixes put_issue_url_here
|
||||
[//]: # (Put Issue # here, if applicable. This will automatically close the issue if your PR is merged in)
|
||||
Fixes put_#_and_issue_numer_here
|
||||
|
||||
### Changes
|
||||
[//]: # (Describe the changes that were made in detail here. Include pictures if necessary)
|
||||
|
||||
@@ -17,7 +17,7 @@ RUN npm install -g gulp-cli mocha
|
||||
# Clone Habitica repo and install dependencies
|
||||
RUN mkdir -p /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 gulp build:prod --force
|
||||
|
||||
|
||||
@@ -167,7 +167,7 @@ gulp.task('test:content:safe', gulp.series('test:prepare:build', (cb) => {
|
||||
|
||||
gulp.task('test:api-v3:unit', (done) => {
|
||||
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) => {
|
||||
if (err) {
|
||||
process.exit(1);
|
||||
|
||||
794
package-lock.json
generated
794
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
42
package.json
42
package.json
@@ -1,16 +1,16 @@
|
||||
{
|
||||
"name": "habitica",
|
||||
"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",
|
||||
"dependencies": {
|
||||
"@slack/client": "^3.8.1",
|
||||
"accepts": "^1.3.5",
|
||||
"amazon-payments": "^0.2.6",
|
||||
"amazon-payments": "^0.2.7",
|
||||
"amplitude": "^3.5.0",
|
||||
"apidoc": "^0.17.5",
|
||||
"autoprefixer": "^8.4.1",
|
||||
"aws-sdk": "^2.230.1",
|
||||
"autoprefixer": "^8.5.0",
|
||||
"aws-sdk": "^2.239.1",
|
||||
"axios": "^0.18.0",
|
||||
"axios-progress-bar": "^1.2.0",
|
||||
"babel-core": "^6.26.3",
|
||||
@@ -26,20 +26,20 @@
|
||||
"babel-register": "^6.6.0",
|
||||
"babel-runtime": "^6.11.6",
|
||||
"bcrypt": "^2.0.0",
|
||||
"body-parser": "^1.15.0",
|
||||
"body-parser": "^1.18.3",
|
||||
"bootstrap": "^4.1.1",
|
||||
"bootstrap-vue": "^2.0.0-rc.9",
|
||||
"compression": "^1.7.2",
|
||||
"cookie-session": "^1.2.0",
|
||||
"coupon-code": "^0.4.5",
|
||||
"cross-env": "^5.1.4",
|
||||
"cross-env": "^5.1.5",
|
||||
"css-loader": "^0.28.11",
|
||||
"csv-stringify": "^2.1.0",
|
||||
"cwait": "^1.1.1",
|
||||
"domain-middleware": "~0.1.0",
|
||||
"express": "^4.16.3",
|
||||
"express-basic-auth": "^1.1.5",
|
||||
"express-validator": "^5.1.2",
|
||||
"express-validator": "^5.2.0",
|
||||
"extract-text-webpack-plugin": "^3.0.2",
|
||||
"glob": "^7.1.2",
|
||||
"got": "^8.3.1",
|
||||
@@ -52,7 +52,7 @@
|
||||
"hellojs": "^1.15.1",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"image-size": "^0.6.2",
|
||||
"in-app-purchase": "^1.9.3",
|
||||
"in-app-purchase": "^1.9.4",
|
||||
"intro.js": "^2.9.3",
|
||||
"jquery": ">=3.0.0",
|
||||
"js2xmlparser": "^3.0.0",
|
||||
@@ -61,7 +61,7 @@
|
||||
"method-override": "^2.3.5",
|
||||
"moment": "^2.22.1",
|
||||
"moment-recur": "^1.0.7",
|
||||
"mongoose": "^5.0.17",
|
||||
"mongoose": "^5.1.1",
|
||||
"morgan": "^1.7.0",
|
||||
"nconf": "^0.10.0",
|
||||
"node-gcm": "^0.14.4",
|
||||
@@ -82,8 +82,8 @@
|
||||
"pusher": "^1.3.0",
|
||||
"rimraf": "^2.4.3",
|
||||
"sass-loader": "^7.0.0",
|
||||
"shelljs": "^0.8.1",
|
||||
"stripe": "^5.8.0",
|
||||
"shelljs": "^0.8.2",
|
||||
"stripe": "^5.9.0",
|
||||
"superagent": "^3.8.3",
|
||||
"svg-inline-loader": "^0.8.0",
|
||||
"svg-url-loader": "^2.3.2",
|
||||
@@ -103,7 +103,7 @@
|
||||
"vue-template-compiler": "^2.5.16",
|
||||
"vuedraggable": "^2.15.0",
|
||||
"vuejs-datepicker": "git://github.com/habitrpg/vuejs-datepicker.git#5d237615463a84a23dd6f3f77c6ab577d68593ec",
|
||||
"webpack": "^3.11.0",
|
||||
"webpack": "^3.12.0",
|
||||
"webpack-merge": "^4.0.0",
|
||||
"winston": "^2.4.2",
|
||||
"winston-loggly-bulk": "^2.0.2",
|
||||
@@ -139,15 +139,15 @@
|
||||
"apidoc": "gulp apidoc"
|
||||
},
|
||||
"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-syntax-object-rest-spread": "^6.13.0",
|
||||
"chai": "^4.1.2",
|
||||
"chai-as-promised": "^7.1.1",
|
||||
"chalk": "^2.4.1",
|
||||
"chromedriver": "^2.38.2",
|
||||
"chromedriver": "^2.38.3",
|
||||
"connect-history-api-fallback": "^1.1.0",
|
||||
"coveralls": "^3.0.0",
|
||||
"coveralls": "^3.0.1",
|
||||
"cross-spawn": "^6.0.5",
|
||||
"eslint": "^4.19.1",
|
||||
"eslint-config-habitrpg": "^4.0.0",
|
||||
@@ -163,7 +163,7 @@
|
||||
"karma-babel-preprocessor": "^7.0.0",
|
||||
"karma-chai-plugins": "^0.9.0",
|
||||
"karma-chrome-launcher": "^2.2.0",
|
||||
"karma-coverage": "^1.1.1",
|
||||
"karma-coverage": "^1.1.2",
|
||||
"karma-mocha": "^1.3.0",
|
||||
"karma-mocha-reporter": "^2.2.5",
|
||||
"karma-sinon-chai": "^1.3.4",
|
||||
@@ -173,17 +173,17 @@
|
||||
"karma-webpack": "^3.0.0",
|
||||
"lcov-result-merger": "^2.0.0",
|
||||
"mocha": "^5.1.1",
|
||||
"monk": "^6.0.5",
|
||||
"monk": "^6.0.6",
|
||||
"nightwatch": "^0.9.21",
|
||||
"puppeteer": "^1.3.0",
|
||||
"puppeteer": "^1.4.0",
|
||||
"require-again": "^2.0.0",
|
||||
"selenium-server": "^3.11.0",
|
||||
"selenium-server": "^3.12.0",
|
||||
"sinon": "^4.5.0",
|
||||
"sinon-chai": "^3.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-hot-middleware": "^2.22.1"
|
||||
"webpack-hot-middleware": "^2.22.2"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"memwatch-next": "^0.3.0",
|
||||
|
||||
@@ -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 challenge = await generateChallenge(user, group);
|
||||
|
||||
|
||||
@@ -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 group = await generateGroup(leader, {type: 'guild', privacy: 'public', name: generateUUID()});
|
||||
|
||||
|
||||
@@ -632,6 +632,15 @@ describe('payments/index', () => {
|
||||
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 () => {
|
||||
await api.buyGems(data);
|
||||
expect(notifications.sendNotification).to.be.calledOnce;
|
||||
|
||||
65
test/client/unit/specs/components/categories/categoryTags.js
Normal file
65
test/client/unit/specs/components/categories/categoryTags.js
Normal 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.');
|
||||
});
|
||||
});
|
||||
54
test/client/unit/specs/components/sidebarSection.js
Normal file
54
test/client/unit/specs/components/sidebarSection.js
Normal 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');
|
||||
});
|
||||
});
|
||||
@@ -122,11 +122,10 @@ describe('common.fns.updateStats', () => {
|
||||
updateStats(user, {
|
||||
exp: 3000,
|
||||
});
|
||||
expect(user.addNotification).to.be.calledTwice; // once is for drops enabled
|
||||
expect(user.addNotification).to.be.calledWith('LEVELED_UP', {
|
||||
expect(user._tmp.leveledUp).to.eql([{
|
||||
initialLvl,
|
||||
newLvl: user.stats.lvl,
|
||||
});
|
||||
}]);
|
||||
});
|
||||
|
||||
it('add user notification when rebirth is enabled', () => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import buySpecialSpell from '../../../../website/common/script/ops/buy/buySpecialSpell';
|
||||
import {BuySpellOperation} from '../../../../website/common/script/ops/buy/buySpell';
|
||||
import {
|
||||
BadRequest,
|
||||
NotFound,
|
||||
@@ -15,6 +15,11 @@ describe('shared.ops.buySpecialSpell', () => {
|
||||
let user;
|
||||
let analytics = {track () {}};
|
||||
|
||||
function buySpecialSpell (_user, _req, _analytics) {
|
||||
const buyOp = new BuySpellOperation(_user, _req, _analytics);
|
||||
|
||||
return buyOp.purchase();
|
||||
}
|
||||
beforeEach(() => {
|
||||
user = generateUser();
|
||||
sinon.stub(analytics, 'track');
|
||||
@@ -44,8 +44,6 @@ div
|
||||
router-view
|
||||
app-footer
|
||||
audio#sound(autoplay, ref="sound")
|
||||
source#oggSource(type="audio/ogg", :src="sound.oggSource")
|
||||
source#mp3Source(type="audio/mp3", :src="sound.mp3Source")
|
||||
</template>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
@@ -118,7 +116,7 @@ div
|
||||
|
||||
/* Push progress bar above modals */
|
||||
#nprogress .bar {
|
||||
z-index: 1043 !important; /* Must stay above nav bar */
|
||||
z-index: 1090 !important; /* Must stay above nav bar */
|
||||
}
|
||||
|
||||
.restingInn {
|
||||
@@ -127,7 +125,7 @@ div
|
||||
}
|
||||
|
||||
#app-header {
|
||||
margin-top: 96px !important;
|
||||
margin-top: 40px !important;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -220,10 +218,9 @@ export default {
|
||||
selectedItemToBuy: null,
|
||||
selectedSpellToBuy: null,
|
||||
|
||||
sound: {
|
||||
oggSource: '',
|
||||
mp3Source: '',
|
||||
},
|
||||
audioSource: null,
|
||||
audioSuffix: null,
|
||||
|
||||
loading: true,
|
||||
currentTipNumber: 0,
|
||||
bannerHidden: false,
|
||||
@@ -259,11 +256,22 @@ export default {
|
||||
return;
|
||||
}
|
||||
|
||||
let file = `/static/audio/${theme}/${sound}`;
|
||||
this.sound = {
|
||||
oggSource: `${file}.ogg`,
|
||||
mp3Source: `${file}.mp3`,
|
||||
};
|
||||
let file = `/static/audio/${theme}/${sound}`;
|
||||
|
||||
if (this.audioSuffix === null) {
|
||||
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();
|
||||
});
|
||||
@@ -317,7 +325,7 @@ export default {
|
||||
title: 'Habitica',
|
||||
text: errorMessage,
|
||||
type: 'error',
|
||||
timeout: true,
|
||||
timeout: false,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,72 +1,48 @@
|
||||
.promo_armoire_backgrounds_201805 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -142px -587px;
|
||||
background-position: -878px 0px;
|
||||
width: 141px;
|
||||
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 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -532px 0px;
|
||||
background-position: 0px -197px;
|
||||
width: 325px;
|
||||
height: 336px;
|
||||
}
|
||||
.promo_mystery_201804 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -340px -383px;
|
||||
background-position: -878px -442px;
|
||||
width: 114px;
|
||||
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 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -340px -474px;
|
||||
background-position: -716px -223px;
|
||||
width: 114px;
|
||||
height: 87px;
|
||||
}
|
||||
.scene_positivity {
|
||||
.scene_casting_spells {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: 0px 0px;
|
||||
width: 531px;
|
||||
height: 243px;
|
||||
background-position: -565px 0px;
|
||||
width: 312px;
|
||||
height: 222px;
|
||||
}
|
||||
.scene_todos {
|
||||
.scene_meditation {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -532px -337px;
|
||||
width: 240px;
|
||||
height: 195px;
|
||||
}
|
||||
.scene_video_games {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: 0px -244px;
|
||||
width: 339px;
|
||||
height: 342px;
|
||||
background-position: -565px -223px;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
}
|
||||
|
||||
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 |
@@ -15,7 +15,7 @@
|
||||
background-color: $gray-600;
|
||||
padding: .5em;
|
||||
display: inline-block;
|
||||
margin-right: .5em;
|
||||
margin: .25em;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
line-height: 1.33;
|
||||
@@ -23,6 +23,21 @@
|
||||
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 {
|
||||
border-radius: 2px;
|
||||
background-color: $white;
|
||||
|
||||
34
website/client/components/categories/categoryTags.vue
Normal file
34
website/client/components/categories/categoryTags.vue
Normal 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>
|
||||
@@ -6,11 +6,15 @@
|
||||
challenge-member-progress-modal(:memberId='progressMemberId', :challengeId='challenge._id')
|
||||
.col-12.col-md-8.standard-page
|
||||
.row
|
||||
.col-12.col-md-8
|
||||
.col-12.col-md-6
|
||||
h1(v-markdown='challenge.name')
|
||||
div
|
||||
strong(v-once) {{$t('createdBy')}}:
|
||||
span(v-if='challenge.leader && challenge.leader.profile') {{challenge.leader.profile.name}}
|
||||
span.mr-1.ml-0
|
||||
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: Implement in V2 strong.margin-left(v-once)
|
||||
.svg-icon.calendar-icon(v-html="icons.calendarIcon")
|
||||
@@ -19,7 +23,7 @@
|
||||
// span {{challenge.endDate}}
|
||||
.tags
|
||||
span.tag(v-for='tag in challenge.tags') {{tag}}
|
||||
.col-12.col-md-4
|
||||
.col-12.col-md-6.text-right
|
||||
.box(@click="showMemberModal()")
|
||||
.svg-icon.member-icon(v-html="icons.memberIcon")
|
||||
| {{challenge.memberCount}}
|
||||
@@ -29,10 +33,10 @@
|
||||
| {{challenge.prize}}
|
||||
.details(v-once) {{$t('prize')}}
|
||||
.row.challenge-actions
|
||||
.col-12.col-md-7.offset-md-5
|
||||
span.view-progress
|
||||
strong {{ $t('viewProgressOf') }}
|
||||
.col-12.col-md-6
|
||||
strong.view-progress {{ $t('viewProgressOf') }}
|
||||
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')
|
||||
b-dropdown.create-dropdown(:text="$t('addTaskToChallenge')", :variant="'success'")
|
||||
b-dropdown-item(v-for="type in columns", :key="type", @click="createTask(type)")
|
||||
@@ -56,24 +60,23 @@
|
||||
v-on:editTask="editTask",
|
||||
v-if='tasksByType[column].length > 0')
|
||||
.col-12.col-md-4.sidebar.standard-page
|
||||
.acitons
|
||||
div(v-if='canJoin')
|
||||
button.btn.btn-success(v-once, @click='joinChallenge()') {{$t('joinChallenge')}}
|
||||
div(v-if='isMember')
|
||||
button.btn.btn-danger(v-once, @click='leaveChallenge()') {{$t('leaveChallenge')}}
|
||||
div(v-if='isLeader || isAdmin')
|
||||
button.btn.btn-secondary(v-once, @click='edit()') {{$t('editChallenge')}}
|
||||
div(v-if='isLeader || isAdmin')
|
||||
button.btn.btn-danger(v-once, @click='closeChallenge()') {{$t('endChallenge')}}
|
||||
div(v-if='isLeader || isAdmin')
|
||||
button.btn.btn-secondary(v-once, @click='exportChallengeCsv()') {{$t('exportChallengeCsv')}}
|
||||
div(v-if='isLeader || isAdmin')
|
||||
button.btn.btn-secondary(v-once, @click='cloneChallenge()') {{$t('clone')}}
|
||||
.description-section
|
||||
h2 {{$t('challengeSummary')}}
|
||||
p(v-markdown='challenge.summary')
|
||||
h2 {{$t('challengeDescription')}}
|
||||
p(v-markdown='challenge.description')
|
||||
.button-container(v-if='canJoin')
|
||||
button.btn.btn-success(v-once, @click='joinChallenge()') {{$t('joinChallenge')}}
|
||||
.button-container(v-if='isLeader || isAdmin')
|
||||
button.btn.btn-primary(v-once, @click='edit()') {{$t('editChallenge')}}
|
||||
.button-container(v-if='isLeader || isAdmin')
|
||||
button.btn.btn-primary(v-once, @click='cloneChallenge()') {{$t('clone')}}
|
||||
.button-container(v-if='isLeader || isAdmin')
|
||||
button.btn.btn-primary(v-once, @click='exportChallengeCsv()') {{$t('exportChallengeCsv')}}
|
||||
.button-container(v-if='isLeader || isAdmin')
|
||||
button.btn.btn-danger(v-once, @click='closeChallenge()') {{$t('endChallenge')}}
|
||||
div
|
||||
sidebar-section(:title="$t('challengeSummary')")
|
||||
p(v-markdown='challenge.summary')
|
||||
sidebar-section(:title="$t('challengeDescription')")
|
||||
p(v-markdown='challenge.description')
|
||||
.text-center(v-if='isMember')
|
||||
button.btn.btn-danger(v-once, @click='leaveChallenge()') {{$t('leaveChallenge')}}
|
||||
</template>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
@@ -91,6 +94,14 @@
|
||||
margin-left: .5em;
|
||||
}
|
||||
|
||||
.button-container {
|
||||
margin-bottom: 1em;
|
||||
|
||||
button {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-icon {
|
||||
width: 12px;
|
||||
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 {
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
.challenge-actions {
|
||||
margin-top: 1em;
|
||||
margin-bottom: 2em;
|
||||
|
||||
.view-progress {
|
||||
margin-right: .5em;
|
||||
@@ -162,14 +163,6 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
.create-dropdown button {
|
||||
width: 100%;
|
||||
font-size: 16px !important;
|
||||
font-weight: bold !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
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 challengeMemberSearchMixin from 'client/mixins/challengeMemberSearch';
|
||||
import leaveChallengeModal from './leaveChallengeModal';
|
||||
|
||||
import sidebarSection from '../sidebarSection';
|
||||
import userLink from '../userLink';
|
||||
import groupLink from '../groupLink';
|
||||
import taskDefaults from 'common/script/libs/taskDefaults';
|
||||
|
||||
import gemIcon from 'assets/svg/gem.svg';
|
||||
@@ -208,8 +203,11 @@ export default {
|
||||
challengeModal,
|
||||
challengeMemberProgressModal,
|
||||
memberSearchDropdown,
|
||||
sidebarSection,
|
||||
TaskColumn: Column,
|
||||
TaskModal,
|
||||
userLink,
|
||||
groupLink,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
|
||||
@@ -1,187 +1,278 @@
|
||||
<template lang="pug">
|
||||
.card
|
||||
.row
|
||||
router-link.col-12(:to="{ name: 'challenge', params: { challengeId: challenge._id } }")
|
||||
h3(v-markdown='challenge.name')
|
||||
.row
|
||||
.col-6
|
||||
div.details
|
||||
span
|
||||
.svg-icon.member-icon(v-html="icons.memberIcon")
|
||||
span {{challenge.memberCount}}
|
||||
// @TODO: Add in V2
|
||||
span
|
||||
.svg-icon.calendar-icon(v-html="icons.calendarIcon")
|
||||
span
|
||||
strong End Date:
|
||||
.challenge
|
||||
.challenge-prize
|
||||
.number
|
||||
span.svg-icon(v-html="icons.gemIcon")
|
||||
span.value {{challenge.prize}}
|
||||
.label {{ $t('challengePrize') }}
|
||||
.challenge-header
|
||||
router-link(
|
||||
:to="{ name: 'challenge', params: { challengeId: challenge._id } }"
|
||||
)
|
||||
h3.challenge-title(v-markdown='challenge.name')
|
||||
.owner(v-if="fullLayout")
|
||||
.owner-item
|
||||
strong {{ $t('createdBy') }}:
|
||||
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}}
|
||||
div.tags
|
||||
span.tag(v-for='tag in challenge.tags') {{tag}}
|
||||
.col-6.prize-section
|
||||
div
|
||||
span.svg-icon.gem(v-html="icons.gemIcon")
|
||||
span.prize {{challenge.prize}}
|
||||
div Challenge Prize
|
||||
.row.description
|
||||
.col-12
|
||||
| {{challenge.summary}}
|
||||
.well.row
|
||||
.col-3
|
||||
.count-details
|
||||
.svg-icon.habit-icon(v-html="icons.habitIcon")
|
||||
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')}}
|
||||
category-tags.challenge-categories(
|
||||
:categories="challenge.categories",
|
||||
:owner="isOwner",
|
||||
:member="isMember",
|
||||
v-once
|
||||
)
|
||||
.challenge-description(v-markdown='challenge.summary')
|
||||
.well-wrapper(v-if="fullLayout")
|
||||
.well
|
||||
div(v-for="task in tasksData", :class="{'muted': task.value === 0}", v-once)
|
||||
.number
|
||||
.svg-icon(v-html="task.icon", :class="task.label + '-icon'")
|
||||
span.value {{ task.value }}
|
||||
.label {{$t(task.label)}}
|
||||
</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>
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
.card {
|
||||
.challenge {
|
||||
background-color: $white;
|
||||
box-shadow: 0 2px 2px 0 $gray-600, 0 1px 4px 0 $gray-600;
|
||||
padding: 2em;
|
||||
height: 350px;
|
||||
box-shadow: 0 2px 2px 0 rgba($black, 0.15), 0 1px 4px 0 rgba($black, 0.1);
|
||||
margin-bottom: 1em;
|
||||
border-radius: 4px;
|
||||
padding-bottom: .5em;
|
||||
|
||||
.gem {
|
||||
width: 32px;
|
||||
.number {
|
||||
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;
|
||||
}
|
||||
|
||||
.calendar-icon {
|
||||
width: 14px;
|
||||
.daily-icon {
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
span {
|
||||
display: inline-block;
|
||||
font-size: 14px;
|
||||
.reward-icon {
|
||||
width: 26px;
|
||||
}
|
||||
|
||||
.challenge-description {
|
||||
color: $gray-200;
|
||||
margin-right: 1em;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
|
||||
.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;
|
||||
margin: 0 1.5em;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.well {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-evenly;
|
||||
background-color: $gray-700;
|
||||
text-align: center;
|
||||
padding: 2em;
|
||||
border-radius: 4px;
|
||||
margin-left: .2em;
|
||||
margin-right: .2em;
|
||||
padding: 1em;
|
||||
border-radius: .25em;
|
||||
|
||||
.svg-icon {
|
||||
display: inline-block;
|
||||
margin-left: .5em;
|
||||
> div {
|
||||
color: $gray-200;
|
||||
|
||||
.svg-icon {
|
||||
color: $gray-300;
|
||||
}
|
||||
}
|
||||
|
||||
.habit-icon {
|
||||
width: 30px;
|
||||
}
|
||||
> div.muted {
|
||||
color: $gray-400;
|
||||
|
||||
.todo-icon {
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.daily-icon {
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
.reward-icon {
|
||||
width: 26px;
|
||||
}
|
||||
|
||||
.count-details span {
|
||||
margin-right: .5em;
|
||||
}
|
||||
|
||||
.count {
|
||||
font-size: 20px;
|
||||
margin-left: .5em;
|
||||
.svg-icon {
|
||||
color: $gray-500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import gemIcon from 'assets/svg/gem.svg';
|
||||
import memberIcon from 'assets/svg/member-icon.svg';
|
||||
import calendarIcon from 'assets/svg/calendar.svg';
|
||||
import habitIcon from 'assets/svg/habit.svg';
|
||||
import todoIcon from 'assets/svg/todo.svg';
|
||||
import dailyIcon from 'assets/svg/daily.svg';
|
||||
import rewardIcon from 'assets/svg/reward.svg';
|
||||
import markdownDirective from 'client/directives/markdown';
|
||||
import { TAVERN_ID } from '../../../common/script/constants';
|
||||
import userLink from '../userLink';
|
||||
import groupLink from '../groupLink';
|
||||
import categoryTags from '../categories/categoryTags';
|
||||
import markdownDirective from 'client/directives/markdown';
|
||||
import {mapState} from 'client/libs/store';
|
||||
|
||||
export default {
|
||||
props: ['challenge'],
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
gemIcon,
|
||||
memberIcon,
|
||||
calendarIcon,
|
||||
habitIcon,
|
||||
todoIcon,
|
||||
dailyIcon,
|
||||
rewardIcon,
|
||||
}),
|
||||
};
|
||||
},
|
||||
directives: {
|
||||
markdown: markdownDirective,
|
||||
},
|
||||
};
|
||||
import gemIcon from 'assets/svg/gem.svg';
|
||||
import memberIcon from 'assets/svg/member-icon.svg';
|
||||
import calendarIcon from 'assets/svg/calendar.svg';
|
||||
import habitIcon from 'assets/svg/habit.svg';
|
||||
import todoIcon from 'assets/svg/todo.svg';
|
||||
import dailyIcon from 'assets/svg/daily.svg';
|
||||
import rewardIcon from 'assets/svg/reward.svg';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
challenge: {
|
||||
required: true,
|
||||
},
|
||||
fullLayout: {
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
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>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
.svg-icon.positive-icon(v-html="icons.positiveIcon")
|
||||
span(v-once) {{$t('createChallenge')}}
|
||||
.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')
|
||||
.row
|
||||
.col-12.text-center
|
||||
@@ -105,9 +105,6 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
memberOf (challenge) {
|
||||
return this.user.challenges.indexOf(challenge._id) !== -1;
|
||||
},
|
||||
updateSearch (eventData) {
|
||||
this.search = eventData.searchTerm;
|
||||
this.page = 0;
|
||||
|
||||
@@ -6,131 +6,87 @@ div
|
||||
.svg-icon.challenge-icon(v-html="icons.challengeIcon")
|
||||
h4(v-once) {{ $t('haveNoChallenges') }}
|
||||
p(v-once) {{ $t('challengeDetails') }}
|
||||
router-link.title(:to="{ name: 'challenge', params: { challengeId: challenge._id } }", v-for='challenge in challenges',:key='challenge._id')
|
||||
.col-12.challenge-item
|
||||
.row
|
||||
.col-9
|
||||
router-link.title(:to="{ name: 'challenge', params: { challengeId: challenge._id } }")
|
||||
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') }}
|
||||
button.btn.btn-secondary(@click='createChallenge()') {{ $t('createChallenge') }}
|
||||
template(v-else)
|
||||
challenge-item(v-for='challenge in challenges',:challenge='challenge',:key='challenge._id',:fullLayout='false')
|
||||
.col-12.text-center
|
||||
button.btn.btn-secondary(@click='createChallenge()') {{ $t('createChallenge') }}
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.title {
|
||||
color: #4E4A57;
|
||||
}
|
||||
<style lang="scss" scoped>
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
.member-icon {
|
||||
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;
|
||||
.no-quest-section {
|
||||
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>
|
||||
|
||||
<script>
|
||||
import challengeModal from './challengeModal';
|
||||
import { mapState } from 'client/libs/store';
|
||||
import markdownDirective from 'client/directives/markdown';
|
||||
import challengeModal from './challengeModal';
|
||||
import {mapState} from 'client/libs/store';
|
||||
import markdownDirective from 'client/directives/markdown';
|
||||
|
||||
import challengeIcon from 'assets/svg/challenge.svg';
|
||||
import gemIcon from 'assets/svg/gem.svg';
|
||||
import memberIcon from 'assets/svg/member-icon.svg';
|
||||
import challengeItem from './challengeItem';
|
||||
import challengeIcon from 'assets/svg/challenge.svg';
|
||||
|
||||
export default {
|
||||
props: ['groupId'],
|
||||
components: {
|
||||
challengeModal,
|
||||
},
|
||||
computed: {
|
||||
...mapState({user: 'user.data'}),
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
challenges: [],
|
||||
icons: Object.freeze({
|
||||
challengeIcon,
|
||||
memberIcon,
|
||||
gemIcon,
|
||||
}),
|
||||
groupIdForChallenges: '',
|
||||
};
|
||||
},
|
||||
directives: {
|
||||
markdown: markdownDirective,
|
||||
},
|
||||
mounted () {
|
||||
this.loadChallenges();
|
||||
},
|
||||
watch: {
|
||||
async groupId () {
|
||||
export default {
|
||||
props: ['groupId'],
|
||||
components: {
|
||||
challengeModal,
|
||||
challengeItem,
|
||||
},
|
||||
computed: {
|
||||
...mapState({user: 'user.data'}),
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
challenges: [],
|
||||
icons: Object.freeze({
|
||||
challengeIcon,
|
||||
}),
|
||||
groupIdForChallenges: '',
|
||||
};
|
||||
},
|
||||
directives: {
|
||||
markdown: markdownDirective,
|
||||
},
|
||||
mounted () {
|
||||
this.loadChallenges();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
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});
|
||||
watch: {
|
||||
async groupId () {
|
||||
this.loadChallenges();
|
||||
},
|
||||
},
|
||||
createChallenge () {
|
||||
this.$root.$emit('bv::show::modal', 'challenge-modal');
|
||||
methods: {
|
||||
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>
|
||||
|
||||
@@ -63,8 +63,6 @@
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'client/libs/store';
|
||||
|
||||
import Sidebar from './sidebar';
|
||||
import ChallengeItem from './challengeItem';
|
||||
import challengeModal from './challengeModal';
|
||||
@@ -111,24 +109,18 @@ export default {
|
||||
},
|
||||
],
|
||||
search: '',
|
||||
filters: {
|
||||
roles: ['participating'], // This is required for my challenges
|
||||
},
|
||||
filters: {},
|
||||
};
|
||||
},
|
||||
mounted () {
|
||||
this.loadchallanges();
|
||||
},
|
||||
computed: {
|
||||
...mapState({user: 'user.data'}),
|
||||
filteredChallenges () {
|
||||
let search = this.search;
|
||||
let filters = this.filters;
|
||||
let user = this.$store.state.user.data;
|
||||
|
||||
// Always filter by member on this page:
|
||||
filters.roles = ['participating'];
|
||||
|
||||
// @TODO: Move this to the server
|
||||
return this.challenges.filter((challenge) => {
|
||||
return this.filterChallenge(challenge, filters, search, user);
|
||||
@@ -136,9 +128,6 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
memberOf (challenge) {
|
||||
return this.user.challenges.indexOf(challenge._id) !== -1;
|
||||
},
|
||||
updateSearch (eventData) {
|
||||
this.search = eventData.searchTerm;
|
||||
},
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
form
|
||||
h2(v-once) {{ $t('filter') }}
|
||||
.form-group
|
||||
h3 Category
|
||||
h3 {{ $t('category') }}
|
||||
.form-check(
|
||||
v-for="group in categoryOptions",
|
||||
:key="group.key",
|
||||
@@ -14,7 +14,7 @@
|
||||
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) }}
|
||||
.form-group(v-if='$route.name !== "findChallenges"')
|
||||
h3 Membership
|
||||
h3 {{ $t('membership') }}
|
||||
.form-check(
|
||||
v-for="group in roleOptions",
|
||||
:key="group.key",
|
||||
@@ -23,7 +23,7 @@
|
||||
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) }}
|
||||
.form-group
|
||||
h3 Ownership
|
||||
h3 {{ $t('ownership') }}
|
||||
.form-check(
|
||||
v-for="group in ownershipOptions",
|
||||
:key="group.key",
|
||||
|
||||
@@ -163,32 +163,27 @@ b-modal#avatar-modal(title="", :size='editing ? "lg" : "md"', :hide-header='true
|
||||
: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})')
|
||||
#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')
|
||||
.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}')
|
||||
.base.sprite.customize-option(:class="`hair_mustache_${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", 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
|
||||
.svg-icon.gem(v-html='icons.gem')
|
||||
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"')
|
||||
.row.sub-menu
|
||||
.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],
|
||||
baseHair3Keys: [9, 10, 11, 12, 13, 14],
|
||||
baseHair4Keys: [15, 16, 17, 18, 19, 20],
|
||||
baseHair5Keys: [1, 2, 3],
|
||||
baseHair6Keys: [1, 2],
|
||||
baseHair5Keys: [1, 2],
|
||||
baseHair6Keys: [1, 2, 3],
|
||||
animalEarsKeys: ['bearEars', 'cactusEars', 'foxEars', 'lionEars', 'pandaEars', 'pigEars', 'tigerEars', 'wolfEars'],
|
||||
icons: Object.freeze({
|
||||
logoPurple,
|
||||
@@ -1228,7 +1223,7 @@ export default {
|
||||
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
|
||||
let keys = this.baseHair5Keys;
|
||||
let options = keys.map(key => {
|
||||
return this.mapKeysToOption(key, 'hair', 'beard');
|
||||
return this.mapKeysToOption(key, 'hair', 'mustache');
|
||||
});
|
||||
return options;
|
||||
},
|
||||
@@ -1237,7 +1232,7 @@ export default {
|
||||
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
|
||||
let keys = this.baseHair6Keys;
|
||||
let options = keys.map(key => {
|
||||
return this.mapKeysToOption(key, 'hair', 'mustache');
|
||||
return this.mapKeysToOption(key, 'hair', 'beard');
|
||||
});
|
||||
return options;
|
||||
},
|
||||
@@ -1335,6 +1330,68 @@ export default {
|
||||
|
||||
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 () {
|
||||
this.modalPage -= 1;
|
||||
},
|
||||
|
||||
25
website/client/components/groupLink.vue
Normal file
25
website/client/components/groupLink.vue
Normal 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>
|
||||
222
website/client/components/groups/chat.vue
Normal file
222
website/client/components/groups/chat.vue
Normal 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>
|
||||
@@ -9,8 +9,10 @@
|
||||
.row
|
||||
.col-12.col-md-6.title-details
|
||||
h1 {{group.name}}
|
||||
strong.float-left(v-once) {{$t('groupLeader')}}
|
||||
span.leader.float-left(v-if='group.leader.profile', @click='showMemberProfile(group.leader)') : {{group.leader.profile.name}}
|
||||
div
|
||||
span.mr-1.ml-0
|
||||
strong(v-once) {{$t('groupLeader')}}:
|
||||
user-link.mx-1(:user="group.leader")
|
||||
.col-12.col-md-6
|
||||
.row.icon-row
|
||||
.col-4.offset-4(v-bind:class="{ 'offset-8': isParty }")
|
||||
@@ -25,25 +27,16 @@
|
||||
.svg-icon.gem(v-html="icons.gem")
|
||||
span.number {{group.balance * 4}}
|
||||
div(v-once) {{ $t('guildBank') }}
|
||||
.row.chat-row
|
||||
.col-12
|
||||
h3(v-once) {{ $t('chat') }}
|
||||
.row.new-message-row
|
||||
textarea(:placeholder="!isParty ? $t('chatPlaceholder') : $t('partyChatPlaceholder')", v-model='newMessage', @keydown='updateCarretPosition', @keyup.ctrl.enter='sendMessage()')
|
||||
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
|
||||
chat(
|
||||
:label="$t('chat')",
|
||||
:group="group",
|
||||
:placeholder="!isParty ? $t('chatPlaceholder') : $t('partyChatPlaceholder')",
|
||||
@fetchRecentMessages="fetchRecentMessages()"
|
||||
)
|
||||
template(slot="additionRow")
|
||||
.row(v-if='showNoNotificationsMessage')
|
||||
.col-12.no-notifications
|
||||
| {{$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
|
||||
.row(:class='{"guild-background": !isParty}')
|
||||
.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
|
||||
.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
|
||||
.section-header(v-if='isParty')
|
||||
quest-sidebar-section(@toggle='toggleQuestSection', :show='sections.quest', :group='group')
|
||||
.section-header(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")
|
||||
div
|
||||
quest-sidebar-section(:group='group', v-if='isParty')
|
||||
sidebar-section(:title="$t('guildSummary')", v-if='!isParty')
|
||||
p(v-markdown='group.summary')
|
||||
.section-header
|
||||
.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")
|
||||
sidebar-section(:title="$t('groupDescription')")
|
||||
p(v-markdown='group.description')
|
||||
.section-header.challenge
|
||||
.row
|
||||
.col-10.information-header
|
||||
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")
|
||||
sidebar-section(
|
||||
:title="$t('challenges')",
|
||||
:tooltip="isParty ? $t('challengeDetails') : $t('privateDescription')"
|
||||
)
|
||||
group-challenges(:groupId='searchId')
|
||||
div.text-center
|
||||
button.btn.btn-danger(v-if='isMember', @click='clickLeave()') {{ isParty ? $t('leaveParty') : $t('leaveGroup') }}
|
||||
@@ -124,10 +86,6 @@
|
||||
color: $purple-200;
|
||||
}
|
||||
|
||||
.leader:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.button-container {
|
||||
margin-bottom: 1em;
|
||||
|
||||
@@ -270,29 +228,6 @@
|
||||
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 {
|
||||
width: 100%;
|
||||
height: 20px;
|
||||
@@ -316,7 +251,6 @@
|
||||
<script>
|
||||
// @TODO: Break this down into components
|
||||
|
||||
import debounce from 'lodash/debounce';
|
||||
import extend from 'lodash/extend';
|
||||
import groupUtilities from 'client/mixins/groupsUtilities';
|
||||
import styleHelper from 'client/mixins/styleHelper';
|
||||
@@ -327,13 +261,13 @@ import startQuestModal from './startQuestModal';
|
||||
import questDetailsModal from './questDetailsModal';
|
||||
import groupFormModal from './groupFormModal';
|
||||
import inviteModal from './inviteModal';
|
||||
import chatMessage from '../chat/chatMessages';
|
||||
import autocomplete from '../chat/autoComplete';
|
||||
import groupChallenges from '../challenges/groupChallenges';
|
||||
import groupGemsModal from 'client/components/groups/groupGemsModal';
|
||||
import questSidebarSection from 'client/components/groups/questSidebarSection';
|
||||
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 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 gemIcon from 'assets/svg/gem.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 upIcon from 'assets/svg/up.svg';
|
||||
import downIcon from 'assets/svg/down.svg';
|
||||
import goldGuildBadgeIcon from 'assets/svg/gold-guild-badge-small.svg';
|
||||
import silverGuildBadgeIcon from 'assets/svg/silver-guild-badge-small.svg';
|
||||
import bronzeGuildBadgeIcon from 'assets/svg/bronze-guild-badge-small.svg';
|
||||
@@ -357,14 +288,14 @@ export default {
|
||||
membersModal,
|
||||
startQuestModal,
|
||||
groupFormModal,
|
||||
chatMessage,
|
||||
inviteModal,
|
||||
groupChallenges,
|
||||
autocomplete,
|
||||
questDetailsModal,
|
||||
groupGemsModal,
|
||||
questSidebarSection,
|
||||
communityGuidelines,
|
||||
sidebarSection,
|
||||
userLink,
|
||||
chat,
|
||||
},
|
||||
directives: {
|
||||
markdown: markdownDirective,
|
||||
@@ -381,26 +312,16 @@ export default {
|
||||
gem: gemIcon,
|
||||
liked: likedIcon,
|
||||
questIcon,
|
||||
information: informationIcon,
|
||||
questBackground,
|
||||
upIcon,
|
||||
downIcon,
|
||||
goldGuildBadgeIcon,
|
||||
silverGuildBadgeIcon,
|
||||
bronzeGuildBadgeIcon,
|
||||
}),
|
||||
members: [],
|
||||
selectedQuest: {},
|
||||
sections: {
|
||||
quest: true,
|
||||
summary: true,
|
||||
description: true,
|
||||
challenges: true,
|
||||
},
|
||||
newMessage: '',
|
||||
coords: {
|
||||
TOP: 0,
|
||||
LEFT: 0,
|
||||
chat: {
|
||||
submitDisable: false,
|
||||
submitTimeout: null,
|
||||
},
|
||||
};
|
||||
},
|
||||
@@ -452,13 +373,6 @@ export default {
|
||||
beforeRouteUpdate (to, from, next) {
|
||||
this.$set(this, 'searchId', to.params.groupId);
|
||||
|
||||
// Reset chat
|
||||
this.newMessage = '';
|
||||
this.coords = {
|
||||
TOP: 0,
|
||||
LEFT: 0,
|
||||
};
|
||||
|
||||
next();
|
||||
},
|
||||
watch: {
|
||||
@@ -510,40 +424,6 @@ export default {
|
||||
|
||||
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 () {
|
||||
this.$store.state.memberModalOptions.groupId = this.group._id;
|
||||
this.$store.state.memberModalOptions.group = this.group;
|
||||
@@ -552,22 +432,9 @@ export default {
|
||||
this.$store.state.memberModalOptions.fetchMoreMembers = this.loadMembers;
|
||||
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 () {
|
||||
this.fetchGuild();
|
||||
},
|
||||
reverseChat () {
|
||||
this.group.chat.reverse();
|
||||
},
|
||||
updateGuild () {
|
||||
this.$store.state.editingGroup = this.group;
|
||||
this.$root.$emit('bv::show::modal', 'guild-form');
|
||||
@@ -688,19 +555,9 @@ export default {
|
||||
}
|
||||
// $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 () {
|
||||
this.$root.$emit('bv::show::modal', 'group-gems-modal');
|
||||
},
|
||||
toggleQuestSection () {
|
||||
this.sections.quest = !this.sections.quest;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -10,13 +10,18 @@ div
|
||||
.col-6
|
||||
button(type="button" aria-label="Close" class="close", @click='close()')
|
||||
span(aria-hidden="true") ×
|
||||
.row
|
||||
.form-group.col-6
|
||||
input.form-control.search(type="text", :placeholder="$t('search')", v-model='searchTerm')
|
||||
.col-5.offset-1
|
||||
span.dropdown-label {{ $t('sortBy') }}
|
||||
b-dropdown(:text="$t('sort')", right=true)
|
||||
b-dropdown-item(v-for='sortOption in sortOptions', @click='sort(sortOption)', :key='sortOption.value') {{sortOption.text}}
|
||||
.row.d-flex.align-items-center
|
||||
.col-4
|
||||
input.form-control.input-search(type="text", :placeholder="$t('search')", v-model='searchTerm')
|
||||
.col
|
||||
select.form-control(@change='changeSortOption($event)')
|
||||
option(v-for='sortOption in sortOptions', :value='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')
|
||||
.col-6.offset-3.nav
|
||||
.nav-item(@click='viewMembers()', :class="{active: selectedPage === 'members'}") {{ $t('members') }}
|
||||
@@ -69,14 +74,30 @@ div
|
||||
|
||||
<style lang='scss'>
|
||||
#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 {
|
||||
color: #878190;
|
||||
}
|
||||
|
||||
.no-padding-left, .modal-body {
|
||||
.no-padding-left {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.member-details {
|
||||
margin: 0;
|
||||
}
|
||||
@@ -88,15 +109,21 @@ div
|
||||
</style>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
header {
|
||||
background-color: #edecee;
|
||||
border-radius: 4px 4px 0 0;
|
||||
.apply-options {
|
||||
padding: 1em;
|
||||
margin: 0;
|
||||
background-color: #f9f9f9;
|
||||
color: #2995cd;
|
||||
}
|
||||
|
||||
.header-wrap {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #4f2a93;
|
||||
}
|
||||
@@ -172,7 +199,6 @@ div
|
||||
</style>
|
||||
|
||||
<script>
|
||||
// import sortBy from "lodash/sortBy";
|
||||
import orderBy from 'lodash/orderBy';
|
||||
import isEmpty from 'lodash/isEmpty';
|
||||
import { mapState } from 'client/libs/store';
|
||||
@@ -193,82 +219,49 @@ export default {
|
||||
data () {
|
||||
return {
|
||||
sortOption: {},
|
||||
sortDirty: false,
|
||||
selectedPage: 'members',
|
||||
members: [],
|
||||
invites: [],
|
||||
memberToRemove: {},
|
||||
sortOptions: [
|
||||
{
|
||||
value: 'class',
|
||||
text: this.$t('class'),
|
||||
order: 'asc',
|
||||
param: 'stats.class',
|
||||
value: 'stats.class',
|
||||
text: this.$t('sortClass'),
|
||||
},
|
||||
{
|
||||
value: 'background',
|
||||
text: this.$t('background'),
|
||||
order: 'asc',
|
||||
param: 'preferences.background',
|
||||
value: 'preferences.background',
|
||||
text: this.$t('sortBackground'),
|
||||
},
|
||||
{
|
||||
value: 'date-joined-asc',
|
||||
text: this.$t('sortDateJoinedAsc'),
|
||||
order: 'asc',
|
||||
param: 'auth.timestamps.created',
|
||||
value: 'auth.timestamps.created',
|
||||
text: this.$t('sortDateJoined'),
|
||||
},
|
||||
{
|
||||
value: 'date-joined-desc',
|
||||
text: this.$t('sortDateJoinedDesc'),
|
||||
order: 'desc',
|
||||
param: 'auth.timestamps.created',
|
||||
value: 'auth.timestamps.loggedin',
|
||||
text: this.$t('sortLogin'),
|
||||
},
|
||||
{
|
||||
value: 'login-asc',
|
||||
text: this.$t('sortLoginAsc'),
|
||||
order: 'asc',
|
||||
param: 'auth.timestamps.loggedin',
|
||||
value: 'stats.lvl',
|
||||
text: this.$t('sortLevel'),
|
||||
},
|
||||
{
|
||||
value: 'login-desc',
|
||||
text: this.$t('sortLoginDesc'),
|
||||
order: 'desc',
|
||||
param: 'auth.timestamps.loggedin',
|
||||
value: 'profile.name',
|
||||
text: this.$t('sortName'),
|
||||
},
|
||||
{
|
||||
value: 'level-asc',
|
||||
text: this.$t('sortLevelAsc'),
|
||||
order: 'asc',
|
||||
param: 'stats.lvl',
|
||||
value: 'contributor.level',
|
||||
text: this.$t('sortTier'),
|
||||
},
|
||||
],
|
||||
sortDirections: [
|
||||
{
|
||||
value: 'asc',
|
||||
text: this.$t('ascendingAbbrev'),
|
||||
},
|
||||
{
|
||||
value: 'level-desc',
|
||||
text: this.$t('sortLevelDesc'),
|
||||
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',
|
||||
value: 'desc',
|
||||
text: this.$t('descendingAbbrev'),
|
||||
},
|
||||
],
|
||||
searchTerm: '',
|
||||
@@ -318,7 +311,7 @@ export default {
|
||||
|
||||
if (!isEmpty(this.sortOption)) {
|
||||
// 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;
|
||||
@@ -424,8 +417,25 @@ export default {
|
||||
close () {
|
||||
this.$root.$emit('bv::hide::modal', 'members-modal');
|
||||
},
|
||||
sort (option) {
|
||||
this.sortOption = option;
|
||||
changeSortOption (e) {
|
||||
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 () {
|
||||
const lastMember = this.members[this.members.length - 1];
|
||||
|
||||
@@ -24,9 +24,7 @@ router-link.card-link(:to="{ name: 'guild', params: { groupId: guild._id } }")
|
||||
span.count {{ guild.balance * 4 }}
|
||||
div.guild-bank(v-if='displayGemBank', v-once) {{$t('guildBank')}}
|
||||
.row
|
||||
.col-md-12
|
||||
.category-label(v-for="category in guild.categorySlugs")
|
||||
| {{$t(category)}}
|
||||
category-tags.col-md-12(:categories="guild.categories", :owner="isOwner", v-once)
|
||||
span.recommend-text(v-if='showSuggested(guild._id)') Suggested because you’re new to Habitica.
|
||||
</template>
|
||||
|
||||
@@ -128,6 +126,7 @@ router-link.card-link(:to="{ name: 'guild', params: { groupId: guild._id } }")
|
||||
<script>
|
||||
import moment from 'moment';
|
||||
import { mapState } from 'client/libs/store';
|
||||
import categoryTags from '../categories/categoryTags';
|
||||
import groupUtilities from 'client/mixins/groupsUtilities';
|
||||
import markdown from 'client/directives/markdown';
|
||||
import gemIcon from 'assets/svg/gem.svg';
|
||||
@@ -142,8 +141,14 @@ export default {
|
||||
markdown,
|
||||
},
|
||||
props: ['guild', 'displayLeave', 'displayGemBank'],
|
||||
components: {
|
||||
categoryTags,
|
||||
},
|
||||
computed: {
|
||||
...mapState({user: 'user.data'}),
|
||||
isOwner () {
|
||||
return this.guild.leader && this.guild.leader === this.user._id;
|
||||
},
|
||||
isMember () {
|
||||
return this.isMemberOfGroup(this.user, this.guild);
|
||||
},
|
||||
|
||||
@@ -1,74 +1,65 @@
|
||||
<template lang="pug">
|
||||
div
|
||||
.row
|
||||
.col-10
|
||||
h3(v-once) {{ $t('questDetailsTitle') }}
|
||||
sidebar-section(:title="$t('questDetailsTitle')")
|
||||
.row.no-quest-section(v-if='!onPendingQuest && !onActiveQuest')
|
||||
.col-12.text-center
|
||||
.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
|
||||
.toggle-up(@click="toggle()", v-if="show")
|
||||
.svg-icon(v-html="icons.upIcon")
|
||||
.toggle-down(@click="toggle()", v-if="!show")
|
||||
.svg-icon(v-html="icons.downIcon")
|
||||
.section(v-if="show")
|
||||
.row.no-quest-section(v-if='!onPendingQuest && !onActiveQuest')
|
||||
.col-12.text-center
|
||||
.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
|
||||
.quest(:class='`inventory_quest_scroll_${questData.key}`')
|
||||
.col-6.titles
|
||||
strong {{ questData.text() }}
|
||||
p {{acceptedCount}} / {{group.memberCount}}
|
||||
.col-4
|
||||
button.btn.btn-secondary(@click="openQuestDetails()") {{ $t('details') }}
|
||||
.row.quest-active-section.quest-invite(v-if='user.party.quest && user.party.quest.RSVPNeeded')
|
||||
span {{ $t('wouldYouParticipate') }}
|
||||
button.btn.btn-primary.accept(@click='questAccept(group._id)') {{$t('accept')}}
|
||||
button.btn.btn-primary.reject(@click='questReject(group._id)') {{$t('reject')}}
|
||||
.row.quest-active-section(v-if='!onPendingQuest && onActiveQuest')
|
||||
.col-12.text-center
|
||||
.quest-boss(:class="'quest_' + questData.key")
|
||||
h3(v-once) {{ questData.text() }}
|
||||
.quest-box
|
||||
.collect-info(v-if='questData.collect')
|
||||
.row(v-for='(value, key) in questData.collect')
|
||||
.col-2
|
||||
div(:class="'quest_' + questData.key + '_' + key")
|
||||
.col-10
|
||||
strong {{value.text()}}
|
||||
.grey-progress-bar
|
||||
.collect-progress-bar(:style="{width: (group.quest.progress.collect[key] / value.count) * 100 + '%'}")
|
||||
strong {{group.quest.progress.collect[key]}} / {{value.count}}
|
||||
div.text-right {{parseFloat(user.party.quest.progress.collectedItems) || 0}} items found
|
||||
.boss-info(v-if='questData.boss')
|
||||
.row
|
||||
.quest(:class='`inventory_quest_scroll_${questData.key}`')
|
||||
.col-6.titles
|
||||
strong {{ questData.text() }}
|
||||
p {{acceptedCount}} / {{group.memberCount}}
|
||||
.col-4
|
||||
button.btn.btn-secondary(@click="openQuestDetails()") {{ $t('details') }}
|
||||
.row.quest-active-section.quest-invite(v-if='user.party.quest && user.party.quest.RSVPNeeded')
|
||||
span {{ $t('wouldYouParticipate') }}
|
||||
button.btn.btn-primary.accept(@click='questAccept(group._id)') {{$t('accept')}}
|
||||
button.btn.btn-primary.reject(@click='questReject(group._id)') {{$t('reject')}}
|
||||
.row.quest-active-section(v-if='!onPendingQuest && onActiveQuest')
|
||||
.col-12.text-center
|
||||
.quest-boss(:class="'quest_' + questData.key")
|
||||
h3(v-once) {{ questData.text() }}
|
||||
.quest-box
|
||||
.collect-info(v-if='questData.collect')
|
||||
.row(v-for='(value, key) in questData.collect')
|
||||
.col-2
|
||||
div(:class="'quest_' + questData.key + '_' + key")
|
||||
.col-10
|
||||
strong {{value.text()}}
|
||||
.grey-progress-bar
|
||||
.collect-progress-bar(:style="{width: (group.quest.progress.collect[key] / value.count) * 100 + '%'}")
|
||||
strong {{group.quest.progress.collect[key]}} / {{value.count}}
|
||||
div.text-right {{parseFloat(user.party.quest.progress.collectedItems) || 0}} items found
|
||||
.boss-info(v-if='questData.boss')
|
||||
.row
|
||||
.col-6
|
||||
h4.float-left(v-once) {{ questData.boss.name() }}
|
||||
.col-6
|
||||
span.float-right(v-once) {{ $t('participantsTitle') }}
|
||||
.row
|
||||
.col-12
|
||||
.grey-progress-bar
|
||||
.boss-health-bar(:style="{width: bossHpPercent + '%'}")
|
||||
.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
|
||||
h4.float-left(v-once) {{ questData.boss.name() }}
|
||||
.col-6
|
||||
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') }}
|
||||
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>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -193,18 +184,18 @@ import { mapState } from 'client/libs/store';
|
||||
|
||||
import quests from 'common/script/content/quests';
|
||||
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';
|
||||
|
||||
export default {
|
||||
props: ['show', 'group'],
|
||||
props: ['group'],
|
||||
components: {
|
||||
sidebarSection,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
upIcon,
|
||||
downIcon,
|
||||
questIcon,
|
||||
}),
|
||||
};
|
||||
@@ -261,9 +252,6 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
toggle () {
|
||||
this.$emit('toggle');
|
||||
},
|
||||
openStartQuestModal () {
|
||||
this.$root.$emit('bv::show::modal', 'start-quest-modal');
|
||||
},
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
form
|
||||
h2(v-once) {{ $t('filter') }}
|
||||
.form-group
|
||||
h3 Category
|
||||
h3 {{ $t('category') }}
|
||||
.form-check(
|
||||
v-for="group in categoryOptions",
|
||||
:key="group.key",
|
||||
@@ -15,7 +15,7 @@
|
||||
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) }}
|
||||
.form-group
|
||||
h3 Role
|
||||
h3 {{ $t('role') }}
|
||||
.form-check(
|
||||
v-for="group in roleOptions",
|
||||
:key="group.key",
|
||||
@@ -24,7 +24,7 @@
|
||||
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) }}
|
||||
.form-group
|
||||
h3 Guild Size
|
||||
h3 {{ $t('guildSize') }}
|
||||
.form-check(
|
||||
v-for="group in guildSizeOptions",
|
||||
:key="group.key",
|
||||
|
||||
@@ -7,26 +7,12 @@
|
||||
.col-6.title-details
|
||||
h1(v-once) {{ $t('welcomeToTavern') }}
|
||||
|
||||
.row.chat-row
|
||||
.col-12
|
||||
h3(v-once) {{ $t('tavernChat') }}
|
||||
|
||||
.row
|
||||
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')
|
||||
chat(
|
||||
:label="$t('tavernChat')",
|
||||
:group="group",
|
||||
:placeholder="$t('tavernCommunityGuidelinesPlaceholder')",
|
||||
@fetchRecentMessages="fetchRecentMessages()"
|
||||
)
|
||||
.col-12.col-sm-4.sidebar
|
||||
.section
|
||||
.grassy-meadow-backdrop
|
||||
@@ -102,18 +88,9 @@
|
||||
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('unpauseDailies') }}
|
||||
|
||||
.below-header-sections
|
||||
.section-header
|
||||
.px-3
|
||||
sidebar-section(:title="$t('staffAndModerators')")
|
||||
.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"}')
|
||||
div
|
||||
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"')
|
||||
.type {{user.type}}
|
||||
|
||||
.section-header
|
||||
.row
|
||||
.col-10
|
||||
h3(v-once) {{ $t('helpfulLinks') }}
|
||||
.col-2
|
||||
.toggle-up(@click="sections.helpfulLinks = !sections.helpfulLinks", v-if="sections.helpfulLinks")
|
||||
.svg-icon(v-html="icons.upIcon")
|
||||
.toggle-down(@click="sections.helpfulLinks = !sections.helpfulLinks", v-if="!sections.helpfulLinks")
|
||||
.svg-icon(v-html="icons.downIcon")
|
||||
.section.row(v-if="sections.helpfulLinks")
|
||||
ul
|
||||
li
|
||||
a(href='', @click.prevent='modForm()') {{ $t('contactForm') }}
|
||||
li
|
||||
router-link(to='/static/community-guidelines', v-once) {{ $t('communityGuidelinesLink') }}
|
||||
li
|
||||
router-link(to="/groups/guild/f2db2a7f-13c5-454d-b3ee-ea1f5089e601") {{ $t('lookingForGroup') }}
|
||||
li
|
||||
router-link(to='/static/faq', v-once) {{ $t('faq') }}
|
||||
li
|
||||
a(href='', v-html="$t('glossary')")
|
||||
li
|
||||
a(href='http://habitica.wikia.com/wiki/Habitica_Wiki', v-once) {{ $t('wiki') }}
|
||||
li
|
||||
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') }}
|
||||
sidebar-section(:title="$t('helpfulLinks')")
|
||||
ul
|
||||
li
|
||||
a(href='', @click.prevent='modForm()') {{ $t('contactForm') }}
|
||||
li
|
||||
router-link(to='/static/community-guidelines', v-once) {{ $t('communityGuidelinesLink') }}
|
||||
li
|
||||
router-link(to="/groups/guild/f2db2a7f-13c5-454d-b3ee-ea1f5089e601") {{ $t('lookingForGroup') }}
|
||||
li
|
||||
router-link(to='/static/faq', v-once) {{ $t('faq') }}
|
||||
li
|
||||
a(href='', v-html="$t('glossary')")
|
||||
li
|
||||
a(href='http://habitica.wikia.com/wiki/Habitica_Wiki', v-once) {{ $t('wiki') }}
|
||||
li
|
||||
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
|
||||
.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
|
||||
p(v-once) {{ $t('playerTiersDesc') }}
|
||||
ul.tier-list
|
||||
@@ -205,49 +165,6 @@
|
||||
@import '~client/assets/scss/colors.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 {
|
||||
color: $purple-200;
|
||||
}
|
||||
@@ -267,10 +184,6 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
.grassy-meadow-backdrop {
|
||||
background-image: url('~assets/images/npc/#{$npc_tavern_flavor}/tavern_background.png');
|
||||
background-repeat: repeat-x;
|
||||
@@ -515,27 +428,24 @@
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import debounce from 'lodash/debounce';
|
||||
import { mapState } from 'client/libs/store';
|
||||
import { goToModForm } from 'client/libs/modform';
|
||||
|
||||
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 worldBossRageModal from '../world-boss/worldBossRageModal';
|
||||
import sidebarSection from '../sidebarSection';
|
||||
import chat from './chat';
|
||||
|
||||
|
||||
import challengeIcon from 'assets/svg/challenge.svg';
|
||||
import chevronIcon from 'assets/svg/chevron-red.svg';
|
||||
import downIcon from 'assets/svg/down.svg';
|
||||
import gemIcon from 'assets/svg/gem.svg';
|
||||
import healthIcon from 'assets/svg/health.svg';
|
||||
import informationIconRed from 'assets/svg/information-red.svg';
|
||||
import questBackground from 'assets/svg/quest-background-border.svg';
|
||||
import rageIcon from 'assets/svg/rage.svg';
|
||||
import swordIcon from 'assets/svg/sword.svg';
|
||||
import upIcon from 'assets/svg/up.svg';
|
||||
|
||||
import tier1 from 'assets/svg/tier-1.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 quests from 'common/script/content/quests';
|
||||
import staffList from '../../libs/staffList';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
chatMessage,
|
||||
autocomplete,
|
||||
communityGuidelines,
|
||||
worldBossInfoModal,
|
||||
worldBossRageModal,
|
||||
sidebarSection,
|
||||
chat,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
@@ -564,7 +474,6 @@ export default {
|
||||
icons: Object.freeze({
|
||||
challengeIcon,
|
||||
chevronIcon,
|
||||
downIcon,
|
||||
gem: gemIcon,
|
||||
healthIcon,
|
||||
informationIcon: informationIconRed,
|
||||
@@ -581,119 +490,14 @@ export default {
|
||||
tierMod,
|
||||
tierNPC,
|
||||
tierStaff,
|
||||
upIcon,
|
||||
}),
|
||||
group: {
|
||||
chat: [],
|
||||
},
|
||||
sections: {
|
||||
staff: true,
|
||||
helpfulLinks: true,
|
||||
playerTiers: true,
|
||||
worldBoss: true,
|
||||
},
|
||||
staff: [
|
||||
{
|
||||
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,
|
||||
},
|
||||
staff: staffList,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -710,59 +514,10 @@ export default {
|
||||
modForm () {
|
||||
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 () {
|
||||
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 () {
|
||||
if (!this.user.party.quest.progress.up) return 0;
|
||||
return this.$options.filters.floor(this.user.party.quest.progress.up, 10);
|
||||
@@ -795,6 +550,10 @@ export default {
|
||||
startingPage: 'profile',
|
||||
});
|
||||
},
|
||||
|
||||
async fetchRecentMessages () {
|
||||
this.group = await this.$store.dispatch('guilds:getGroup', {groupId: TAVERN_ID});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -18,7 +18,7 @@ div
|
||||
@resized="setPartyMembersWidth($event)"
|
||||
)
|
||||
member-details(
|
||||
v-for="(member, $index) in partyMembers",
|
||||
v-for="(member, $index) in sortedPartyMembers",
|
||||
:key="member._id",
|
||||
v-if="member._id !== user._id && $index < membersToShow",
|
||||
:member="member",
|
||||
@@ -55,7 +55,6 @@ div
|
||||
}
|
||||
|
||||
#app-header {
|
||||
margin-top: 56px;
|
||||
padding-left: 24px;
|
||||
padding-top: 9px;
|
||||
padding-bottom: 8px;
|
||||
@@ -107,6 +106,7 @@ div
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import orderBy from 'lodash/orderBy';
|
||||
import { mapGetters, mapActions } from 'client/libs/store';
|
||||
import MemberDetails from '../memberDetails';
|
||||
import createPartyModal from '../groups/createPartyModal';
|
||||
@@ -140,6 +140,9 @@ export default {
|
||||
membersToShow () {
|
||||
return Math.floor(this.currentWidth / 140) + 1;
|
||||
},
|
||||
sortedPartyMembers () {
|
||||
return orderBy(this.partyMembers, [this.user.party.order], [this.user.party.orderAscending]);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
|
||||
@@ -3,60 +3,60 @@ div
|
||||
inbox-modal
|
||||
creator-intro
|
||||
profile
|
||||
b-navbar.navbar.navbar-inverse.fixed-top.navbar-expand-lg(type="dark")
|
||||
.navbar-header
|
||||
b-navbar.topbar.navbar-inverse.static-top.navbar-expand-lg(type="dark", :class="navbarZIndexClass")
|
||||
b-navbar-brand.brand
|
||||
.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-sm-block.d-lg-none.d-md-none
|
||||
b-nav-toggle(target='nav_collapse')
|
||||
b-collapse#nav_collapse.collapse.navbar-collapse.justify-content-between.flex-wrap(is-nav)
|
||||
.ul.navbar-nav
|
||||
router-link.nav-item(tag="li", :to="{name: 'tasks'}", exact)
|
||||
a.nav-link(v-once) {{ $t('tasks') }}
|
||||
router-link.nav-item.dropdown(tag="li", :to="{name: 'items'}", :class="{'active': $route.path.startsWith('/inventory')}")
|
||||
a.nav-link(v-once) {{ $t('inventory') }}
|
||||
.dropdown-menu
|
||||
router-link.dropdown-item(:to="{name: 'items'}", exact) {{ $t('items') }}
|
||||
router-link.dropdown-item(:to="{name: 'equipment'}") {{ $t('equipment') }}
|
||||
router-link.dropdown-item(:to="{name: 'stable'}") {{ $t('stable') }}
|
||||
router-link.nav-item.dropdown(tag="li", :to="{name: 'market'}", :class="{'active': $route.path.startsWith('/shop')}")
|
||||
a.nav-link(v-once) {{ $t('shops') }}
|
||||
.dropdown-menu
|
||||
router-link.dropdown-item(:to="{name: 'market'}", exact) {{ $t('market') }}
|
||||
router-link.dropdown-item(:to="{name: 'quests'}") {{ $t('quests') }}
|
||||
router-link.dropdown-item(:to="{name: 'seasonal'}") {{ $t('titleSeasonalShop') }}
|
||||
router-link.dropdown-item(:to="{name: 'time'}") {{ $t('titleTimeTravelers') }}
|
||||
router-link.nav-item(tag="li", :to="{name: 'party'}", v-if='this.user.party._id')
|
||||
a.nav-link(v-once) {{ $t('party') }}
|
||||
.nav-item(@click='openPartyModal()', v-if='!this.user.party._id')
|
||||
a.nav-link(v-once) {{ $t('party') }}
|
||||
router-link.nav-item.dropdown(tag="li", :to="{name: 'tavern'}", :class="{'active': $route.path.startsWith('/guilds')}")
|
||||
a.nav-link(v-once) {{ $t('guilds') }}
|
||||
.dropdown-menu
|
||||
router-link.dropdown-item(:to="{name: 'tavern'}") {{ $t('tavern') }}
|
||||
router-link.dropdown-item(:to="{name: 'myGuilds'}") {{ $t('myGuilds') }}
|
||||
router-link.dropdown-item(:to="{name: 'guildsDiscovery'}") {{ $t('guildsDiscovery') }}
|
||||
router-link.nav-item.dropdown(tag="li", :to="{name: 'groupPlan'}", :class="{'active': $route.path.startsWith('/group-plans')}")
|
||||
a.nav-link(v-once) {{ $t('group') }}
|
||||
.dropdown-menu
|
||||
router-link.dropdown-item(v-for='group in groupPlans', :key='group._id', :to="{name: 'groupPlanDetailTaskInformation', params: {groupId: group._id}}") {{ group.name }}
|
||||
router-link.nav-item.dropdown(tag="li", :to="{name: 'myChallenges'}", :class="{'active': $route.path.startsWith('/challenges')}")
|
||||
a.nav-link(v-once) {{ $t('challenges') }}
|
||||
.dropdown-menu
|
||||
router-link.dropdown-item(:to="{name: 'myChallenges'}") {{ $t('myChallenges') }}
|
||||
router-link.dropdown-item(:to="{name: 'findChallenges'}") {{ $t('findChallenges') }}
|
||||
router-link.nav-item.dropdown(tag="li", :class="{'active': $route.path.startsWith('/help')}", :to="{name: 'faq'}")
|
||||
a.nav-link(v-once) {{ $t('help') }}
|
||||
.dropdown-menu
|
||||
router-link.dropdown-item(:to="{name: 'faq'}") {{ $t('faq') }}
|
||||
router-link.dropdown-item(:to="{name: 'overview'}") {{ $t('overview') }}
|
||||
router-link.dropdown-item(to="/groups/guild/a29da26b-37de-4a71-b0c6-48e72a900dac") {{ $t('reportBug') }}
|
||||
router-link.dropdown-item(to="/groups/guild/5481ccf3-5d2d-48a9-a871-70a7380cee5a") {{ $t('askAQuestion') }}
|
||||
.svg-icon.gryphon.d-xs-block.d-xl-none
|
||||
b-nav-toggle(target='menu_collapse').menu-toggle
|
||||
.quick-menu.mobile-only.form-inline
|
||||
a.item-with-icon(@click="sync", v-b-tooltip.hover.bottom="$t('sync')")
|
||||
.top-menu-icon.svg-icon(v-html="icons.sync")
|
||||
notification-menu.item-with-icon
|
||||
user-dropdown.item-with-icon
|
||||
b-collapse#menu_collapse.collapse.navbar-collapse
|
||||
b-navbar-nav.menu-list
|
||||
b-nav-item.topbar-item(tag="li", :to="{name: 'tasks'}", exact) {{ $t('tasks') }}
|
||||
li.topbar-item(:class="{'active': $route.path.startsWith('/inventory')}")
|
||||
router-link.nav-link(:to="{name: 'items'}") {{ $t('inventory') }}
|
||||
.topbar-dropdown
|
||||
router-link.topbar-dropdown-item.dropdown-item(:to="{name: 'items'}", exact) {{ $t('items') }}
|
||||
router-link.topbar-dropdown-item.dropdown-item(:to="{name: 'equipment'}") {{ $t('equipment') }}
|
||||
router-link.topbar-dropdown-item.dropdown-item(:to="{name: 'stable'}") {{ $t('stable') }}
|
||||
li.topbar-item(:class="{'active': $route.path.startsWith('/shop')}")
|
||||
router-link.nav-link(:to="{name: 'market'}") {{ $t('shops') }}
|
||||
.topbar-dropdown
|
||||
router-link.topbar-dropdown-item.dropdown-item(:to="{name: 'market'}", exact) {{ $t('market') }}
|
||||
router-link.topbar-dropdown-item.dropdown-item(:to="{name: 'quests'}") {{ $t('quests') }}
|
||||
router-link.topbar-dropdown-item.dropdown-item(:to="{name: 'seasonal'}") {{ $t('titleSeasonalShop') }}
|
||||
router-link.topbar-dropdown-item.dropdown-item(:to="{name: 'time'}") {{ $t('titleTimeTravelers') }}
|
||||
b-nav-item.topbar-item(tag="li", :to="{name: 'party'}", v-if='this.user.party._id') {{ $t('party') }}
|
||||
b-nav-item.topbar-item(@click='openPartyModal()', v-if='!this.user.party._id') {{ $t('party') }}
|
||||
li.topbar-item(:class="{'active': $route.path.startsWith('/guilds')}")
|
||||
router-link.nav-link(:to="{name: 'tavern'}") {{ $t('guilds') }}
|
||||
.topbar-dropdown
|
||||
router-link.topbar-dropdown-item.dropdown-item(:to="{name: 'tavern'}") {{ $t('tavern') }}
|
||||
router-link.topbar-dropdown-item.dropdown-item(:to="{name: 'myGuilds'}") {{ $t('myGuilds') }}
|
||||
router-link.topbar-dropdown-item.dropdown-item(:to="{name: 'guildsDiscovery'}") {{ $t('guildsDiscovery') }}
|
||||
li.topbar-item(:class="{'active': $route.path.startsWith('/group-plans')}")
|
||||
router-link.nav-link(:to="{name: 'groupPlan'}") {{ $t('group') }}
|
||||
.topbar-dropdown
|
||||
router-link.topbar-dropdown-item.dropdown-item(v-for='group in groupPlans', :key='group._id', :to="{name: 'groupPlanDetailTaskInformation', params: {groupId: group._id}}") {{ group.name }}
|
||||
li.topbar-item(:class="{'active': $route.path.startsWith('/challenges')}")
|
||||
router-link.nav-link(:to="{name: 'myChallenges'}") {{ $t('challenges') }}
|
||||
.topbar-dropdown
|
||||
router-link.topbar-dropdown-item.dropdown-item(:to="{name: 'myChallenges'}") {{ $t('myChallenges') }}
|
||||
router-link.topbar-dropdown-item.dropdown-item(:to="{name: 'findChallenges'}") {{ $t('findChallenges') }}
|
||||
li.topbar-item(:class="{'active': $route.path.startsWith('/help')}")
|
||||
router-link.nav-link(:to="{name: 'faq'}") {{ $t('help') }}
|
||||
.topbar-dropdown
|
||||
router-link.topbar-dropdown-item.dropdown-item(:to="{name: 'faq'}") {{ $t('faq') }}
|
||||
router-link.topbar-dropdown-item.dropdown-item(:to="{name: 'overview'}") {{ $t('overview') }}
|
||||
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="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(@click='modForm()') {{ $t('contactForm') }}
|
||||
.user-menu.d-flex.align-items-center
|
||||
.currency-tray.form-inline
|
||||
.item-with-icon(v-if="userHourglasses > 0")
|
||||
.top-menu-icon.svg-icon(v-html="icons.hourglasses", v-b-tooltip.hover.bottom="$t('mysticHourglassesTooltip')")
|
||||
span {{ userHourglasses }}
|
||||
@@ -66,6 +66,7 @@ div
|
||||
.item-with-icon.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}}
|
||||
.form-inline.desktop-only
|
||||
a.item-with-icon(@click="sync", v-b-tooltip.hover.bottom="$t('sync')")
|
||||
.top-menu-icon.svg-icon(v-html="icons.sync")
|
||||
notification-menu.item-with-icon
|
||||
@@ -76,16 +77,6 @@ div
|
||||
@import '~client/assets/scss/colors.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) {
|
||||
.gryphon {
|
||||
background-image: url('~assets/images/melior@3x.png');
|
||||
@@ -94,127 +85,185 @@ div
|
||||
background-size: cover;
|
||||
color: $white;
|
||||
margin: 0 auto;
|
||||
|
||||
}
|
||||
|
||||
.svg-icon.gryphon.d-sm-block {
|
||||
position: absolute;
|
||||
left: calc(50% - 30px);
|
||||
top: 1em;
|
||||
}
|
||||
|
||||
.nav-item .nav-link {
|
||||
.topbar-item {
|
||||
font-size: 14px !important;
|
||||
padding: 16px 12px !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 990px) {
|
||||
#nav_collapse {
|
||||
margin-top: 0.6em;
|
||||
flex-direction: row !important;
|
||||
max-height: 650px;
|
||||
overflow: auto;
|
||||
@media only screen and (min-width: 992px) {
|
||||
.mobile-only {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.navbar-nav {
|
||||
width: 100%;
|
||||
background: $purple-100;
|
||||
}
|
||||
.topbar {
|
||||
max-height: 56px;
|
||||
|
||||
.user-menu {
|
||||
flex-direction: column !important;
|
||||
align-items: left !important;
|
||||
background: $purple-100;
|
||||
width: 100%;
|
||||
.currency-tray {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.item-with-icon {
|
||||
width: 100%;
|
||||
padding-bottom: 1em;
|
||||
.topbar-item {
|
||||
padding-top: 5px;
|
||||
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;
|
||||
}
|
||||
|
||||
nav.navbar {
|
||||
background: $purple-100 url(~assets/svg/for-css/bits.svg) right no-repeat;
|
||||
padding-left: 25px;
|
||||
padding-right: 12.5px;
|
||||
height: 56px;
|
||||
box-shadow: 0 1px 2px 0 rgba($black, 0.24);
|
||||
z-index: 1042; // To stay above snakbar notifications and modals
|
||||
}
|
||||
.topbar-item {
|
||||
font-size: 16px;
|
||||
color: $white !important;
|
||||
font-weight: bold;
|
||||
transition: none;
|
||||
|
||||
.navbar-header {
|
||||
margin-right: 48px;
|
||||
|
||||
.logo {
|
||||
width: 128px;
|
||||
height: 28px;
|
||||
.topbar-dropdown {
|
||||
display: none; // Display is set to block on hover.
|
||||
}
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
.nav-link {
|
||||
font-size: 16px;
|
||||
color: $white !important;
|
||||
font-weight: bold;
|
||||
line-height: 1.5;
|
||||
padding: 16px 20px;
|
||||
transition: none;
|
||||
|
||||
>a {
|
||||
padding: .8em 1em !important;
|
||||
}
|
||||
|
||||
&: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;
|
||||
}
|
||||
}
|
||||
border-radius: 0px;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
padding: 0px;
|
||||
|
||||
&.active:not(:hover) {
|
||||
.nav-link {
|
||||
box-shadow: 0px -4px 0px $purple-300 inset;
|
||||
}
|
||||
}
|
||||
}
|
||||
border-bottom-right-radius: 5px;
|
||||
border-bottom-left-radius: 5px;
|
||||
|
||||
// Make the dropdown menu open on hover
|
||||
.dropdown:hover .dropdown-menu {
|
||||
display: block;
|
||||
margin-top: 0; // remove the gap so it doesn't close
|
||||
}
|
||||
.topbar-dropdown-item {
|
||||
font-size: 16px;
|
||||
box-shadow: none;
|
||||
color: $white;
|
||||
border: none;
|
||||
line-height: 1.5;
|
||||
display: list-item;
|
||||
|
||||
.dropdown-menu {
|
||||
background: $purple-200;
|
||||
border-radius: 0px;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
padding: 0px;
|
||||
&.active {
|
||||
background: $purple-300;
|
||||
}
|
||||
|
||||
border-bottom-right-radius: 5px;
|
||||
border-bottom-left-radius: 5px;
|
||||
&:hover {
|
||||
background: $purple-300;
|
||||
|
||||
.dropdown-item {
|
||||
font-size: 16px;
|
||||
box-shadow: none;
|
||||
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;
|
||||
&:last-child {
|
||||
border-bottom-right-radius: 5px;
|
||||
border-bottom-left-radius: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -327,7 +376,14 @@ export default {
|
||||
user: 'user.data',
|
||||
userHourglasses: 'user.data.purchased.plan.consecutive.trinkets',
|
||||
groupPlans: 'groupPlans',
|
||||
modalStack: 'modalStack',
|
||||
}),
|
||||
navbarZIndexClass () {
|
||||
if (this.modalStack.length > 0) {
|
||||
return 'navbar-z-index-modal';
|
||||
}
|
||||
return 'navbar-z-index-normal';
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
this.getUserGroupPlans();
|
||||
@@ -364,6 +420,7 @@ export default {
|
||||
|
||||
this.$root.$emit('bv::show::modal', 'buy-gems', {alreadyTracked: true});
|
||||
},
|
||||
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
label.custom-control-label(v-once, :for="mountGroup.key") {{ mountGroup.label }}
|
||||
|
||||
div.form-group.clearfix
|
||||
h3.float-left Hide Missing
|
||||
h3.float-left {{ $t('hideMissing') }}
|
||||
toggle-switch.float-right(
|
||||
:checked="hideMissing",
|
||||
@change="updateHideMissing"
|
||||
@@ -935,10 +935,22 @@
|
||||
}
|
||||
},
|
||||
async feedAction (petKey, foodKey) {
|
||||
const result = await this.$store.dispatch('common:feed', {pet: petKey, food: foodKey});
|
||||
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);
|
||||
try {
|
||||
const result = await this.$store.dispatch('common:feed', {pet: petKey, food: foodKey});
|
||||
|
||||
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 () {
|
||||
this.$root.$emit('bv::hide::modal', 'hatching-modal');
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
b.how-many-to-sell {{ $t('howManyToSell') }}
|
||||
|
||||
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.value {{ item.value }}
|
||||
@@ -144,11 +144,16 @@
|
||||
preventNegative ($event) {
|
||||
let value = $event.target.value;
|
||||
|
||||
if (isNaN($event.target.valueAsNumber) || Number(value) < 0) {
|
||||
if (Number(value) < 0) {
|
||||
this.selectedAmountToSell = 0;
|
||||
}
|
||||
},
|
||||
sellItems () {
|
||||
if (!Number.isInteger(Number(this.selectedAmountToSell))) {
|
||||
this.selectedAmountToSell = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
this.$store.dispatch('shops:sellItems', {
|
||||
type: this.itemType,
|
||||
key: this.item.key,
|
||||
|
||||
@@ -139,7 +139,7 @@
|
||||
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.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})}` }}
|
||||
questInfo(v-if='!item.locked', :quest="item")
|
||||
|
||||
@@ -486,6 +486,11 @@ export default {
|
||||
|
||||
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>
|
||||
|
||||
91
website/client/components/sidebarSection.vue
Normal file
91
website/client/components/sidebarSection.vue
Normal 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>
|
||||
@@ -130,7 +130,6 @@ export default {
|
||||
};
|
||||
},
|
||||
created () {
|
||||
// @TODO the notifications always close even if timeout is false
|
||||
let timeout = this.notification.hasOwnProperty('timeout') ? this.notification.timeout : true;
|
||||
if (timeout) {
|
||||
let delay = this.notification.delay || 1500;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template lang="pug">
|
||||
.notifications
|
||||
div(v-for='notification in notifications', :key='notification.uuid')
|
||||
.notifications(:class="notificationsTopPos")
|
||||
div(v-for='notification in notificationStore', :key='notification.uuid')
|
||||
notification(:notification='notification')
|
||||
</template>
|
||||
|
||||
@@ -8,13 +8,23 @@
|
||||
.notifications {
|
||||
position: fixed;
|
||||
right: 10px;
|
||||
top: 65px;
|
||||
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>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'client/libs/store';
|
||||
import notification from './notification';
|
||||
|
||||
export default {
|
||||
@@ -22,8 +32,19 @@ export default {
|
||||
notification,
|
||||
},
|
||||
computed: {
|
||||
notifications () {
|
||||
return this.$store.state.notificationStore;
|
||||
...mapState({
|
||||
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}`;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
@focus="quickAddFocused = true", @blur="quickAddFocused = false",
|
||||
)
|
||||
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")
|
||||
.column-background(
|
||||
v-if="isUser === true",
|
||||
@@ -370,7 +370,7 @@ export default {
|
||||
let rewards = inAppRewards(this.user);
|
||||
|
||||
// Add season rewards if user is affected
|
||||
// @TODO: Add buff coniditional
|
||||
// @TODO: Add buff conditional
|
||||
const seasonalSkills = {
|
||||
snowball: 'salt',
|
||||
spookySparkles: 'opaquePotion',
|
||||
|
||||
@@ -55,10 +55,6 @@
|
||||
.custom-control-label {
|
||||
color: $gray-50 !important;
|
||||
font-weight: normal;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: pre;
|
||||
width: 8em;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
type="checkbox",
|
||||
:checked="item.completed",
|
||||
@change="toggleChecklistItem(item)",
|
||||
:disabled="castingSpell",
|
||||
:disabled="castingSpell || !isUser",
|
||||
:id="`checklist-${item.id}`"
|
||||
)
|
||||
label.custom-control-label(v-markdown="item.text", :for="`checklist-${item.id}`")
|
||||
|
||||
@@ -1,44 +1,57 @@
|
||||
<template lang="pug">
|
||||
div.header-tabs
|
||||
.drawer-tab-container
|
||||
.drawer-tab(v-for="(tab, index) in tabs")
|
||||
.header-tabs
|
||||
ul.drawer-tab-container
|
||||
li.drawer-tab(v-for="(tab, index) in tabs")
|
||||
a.drawer-tab-text(
|
||||
@click="changeTab(index)",
|
||||
:class="{'drawer-tab-text-active': selectedTabPosition === index}",
|
||||
:title="tab.label"
|
||||
) {{ tab.label }}
|
||||
|
||||
span.right-item
|
||||
aside.help-item
|
||||
slot(name="right-item")
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.drawer-tab-text {
|
||||
overflow-x: hidden;
|
||||
display: block;
|
||||
overflow-x: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.drawer-tab {
|
||||
white-space: nowrap;
|
||||
overflow-x: hidden;
|
||||
flex: inherit;
|
||||
overflow-x: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.drawer-tab-container {
|
||||
max-width: 50%;
|
||||
margin: 0 auto;
|
||||
grid-column-start: 2;
|
||||
grid-column-end: 3;
|
||||
justify-self: center;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.right-item {
|
||||
position: absolute;
|
||||
.help-item {
|
||||
grid-column-start: 3;
|
||||
position: relative;
|
||||
right: -11px;
|
||||
text-align: right;
|
||||
top: -2px;
|
||||
}
|
||||
|
||||
.header-tabs {
|
||||
position: relative;
|
||||
display: flex;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto 1fr;
|
||||
}
|
||||
|
||||
// MS Edge
|
||||
@supports (-ms-ime-align: auto) {
|
||||
.help-item {
|
||||
align-self: center;
|
||||
top: 1px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
21
website/client/components/userLink.vue
Normal file
21
website/client/components/userLink.vue
Normal 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>
|
||||
@@ -55,7 +55,6 @@
|
||||
|
||||
h3(v-if="label !== 'skip'") {{ label }}
|
||||
h3(v-else) {{ $t('background') }}
|
||||
|
||||
.row.pet-mount-row
|
||||
.col-12.col-md-6
|
||||
h2.text-center(v-once) {{ $t('pets') }}
|
||||
@@ -134,15 +133,15 @@
|
||||
.row
|
||||
.col-12.col-md-3(v-for='(statInfo, stat) in allocateStatsList')
|
||||
.box.white.row.col-12
|
||||
.col-12.col-md-8
|
||||
.col-12.col-md-9
|
||||
div(:class='stat') {{ $t(stats[stat].title) }}
|
||||
.number {{ user.stats[stat] }}
|
||||
.points {{$t('pts')}}
|
||||
.col-12.col-md-4
|
||||
.col-12.col-md-3
|
||||
div
|
||||
.up(v-if='user.stats.points', @click='allocate(stat)')
|
||||
div
|
||||
.down(@click='deallocate(stat)')
|
||||
.down(@click='deallocate(stat)', v-if='user.stats.points')
|
||||
.row.save-row
|
||||
.col-12.col-md-6.offset-md-3.text-center
|
||||
button.btn.btn-primary(@click='saveAttributes()', :disabled='loading') {{ this.loading ? $t('loading') : $t('save') }}
|
||||
@@ -212,7 +211,7 @@
|
||||
popover: 'perText',
|
||||
},
|
||||
},
|
||||
statsAtStart: {
|
||||
statUpdates: {
|
||||
str: 0,
|
||||
int: 0,
|
||||
con: 0,
|
||||
@@ -221,9 +220,6 @@
|
||||
content: Content,
|
||||
};
|
||||
},
|
||||
mounted () {
|
||||
this.statsAtStart = Object.assign({}, this.user.stats);
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
flatGear: 'content.gear.flat',
|
||||
@@ -291,25 +287,33 @@
|
||||
},
|
||||
allocate (stat) {
|
||||
allocate(this.user, {query: { stat }});
|
||||
this.statUpdates[stat] += 1;
|
||||
},
|
||||
deallocate (stat) {
|
||||
if (this.user.stats[stat] === 0) return;
|
||||
this.user.stats[stat] -= 1;
|
||||
this.user.stats.points += 1;
|
||||
this.statUpdates[stat] -= 1;
|
||||
},
|
||||
async saveAttributes () {
|
||||
this.loading = true;
|
||||
|
||||
const statUpdates = {};
|
||||
['str', 'int', 'per', 'con'].forEach(stat => {
|
||||
const diff = this.user.stats[stat] - this.statsAtStart[stat];
|
||||
statUpdates[stat] = diff;
|
||||
if (this.statUpdates[stat] > 0) statUpdates[stat] = this.statUpdates[stat];
|
||||
});
|
||||
|
||||
await axios.post('/api/v3/user/allocate-bulk', {
|
||||
stats: statUpdates,
|
||||
});
|
||||
|
||||
this.statUpdates = {
|
||||
str: 0,
|
||||
int: 0,
|
||||
con: 0,
|
||||
per: 0,
|
||||
};
|
||||
|
||||
this.loading = false;
|
||||
},
|
||||
allocateNow () {
|
||||
|
||||
@@ -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 };
|
||||
97
website/client/libs/staffList.js
Normal file
97
website/client/libs/staffList.js
Normal 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',
|
||||
},
|
||||
];
|
||||
@@ -133,23 +133,6 @@ export default {
|
||||
|
||||
|
||||
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;
|
||||
let questProgress = this.questProgress() - beforeQuestProgress;
|
||||
if (questProgress > 0) {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import axios from 'axios';
|
||||
import buyOp from 'common/script/ops/buy/buy';
|
||||
import content from 'common/script/content/index';
|
||||
import purchaseOp from 'common/script/ops/buy/purchaseWithSpell';
|
||||
import hourglassPurchaseOp from 'common/script/ops/buy/hourglassPurchase';
|
||||
import sellOp from 'common/script/ops/sell';
|
||||
import unlockOp from 'common/script/ops/unlock';
|
||||
@@ -91,7 +90,7 @@ async function buyArmoire (store, params) {
|
||||
export function purchase (store, params) {
|
||||
const quantity = params.quantity || 1;
|
||||
const user = store.state.user.data;
|
||||
let opResult = purchaseOp(user, {params, quantity});
|
||||
let opResult = buyOp(user, {params, quantity});
|
||||
|
||||
return {
|
||||
result: opResult,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { loadAsyncResource } from 'client/libs/asyncResource';
|
||||
import spellQueue from 'client/libs/spellQueue';
|
||||
import setProps from 'lodash/set';
|
||||
import axios from 'axios';
|
||||
|
||||
@@ -118,11 +117,6 @@ export async function movePinnedItem (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}`;
|
||||
|
||||
const data = {};
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
"challengeWinner": "Беше победител в следните предизвикателства",
|
||||
"challenges": "Предизвикателства",
|
||||
"challengesLink": "<a href='http://habitica.wikia.com/wiki/Challenges' target='_blank'>Предизвикателства</a>",
|
||||
"challengePrize": "Challenge Prize",
|
||||
"endDate": "Ends",
|
||||
"noChallenges": "Все още няма предизвикателства. Посетете",
|
||||
"toCreate": "за да създадете.",
|
||||
"selectWinner": "Изберете победител и завършете предизвикателството:",
|
||||
@@ -23,7 +25,9 @@
|
||||
"filter": "Филтриране",
|
||||
"groups": "Групи",
|
||||
"noNone": "Нищо",
|
||||
"category": "Category",
|
||||
"membership": "Участие",
|
||||
"ownership": "Ownership",
|
||||
"participating": "Участвам",
|
||||
"notParticipating": "Не участвам",
|
||||
"either": "Без значение",
|
||||
|
||||
@@ -201,7 +201,6 @@
|
||||
"showQuickAllocation": "Показване на разпределението на показателните точки",
|
||||
"hideQuickAllocation": "Скриване на разпределението на показателните точки",
|
||||
"quickAllocationLevelPopover": "Всяко ниво Ви дава една точка, която можете да разпределите на показател по свой избор. Можете да го направите ръчно или да оставите играта да реши вместо Вас, използвайки една възможностите за автоматично разпределяне, които можете да намерите в Потребителската иконка > Показатели.",
|
||||
"invalidAttribute": "„<%= attr %>“ не е правилен показател.",
|
||||
"notEnoughAttrPoints": "Нямате достатъчно показателни точки.",
|
||||
"style": "Стил",
|
||||
"facialhair": "Лице",
|
||||
@@ -219,6 +218,5 @@
|
||||
"mainHand": "Основна ръка",
|
||||
"offHand": "Страничен",
|
||||
"pointsAvailable": "Налични точки",
|
||||
"pts": "точки",
|
||||
"statsObjectRequired": "Промяната на показателите е задължителна"
|
||||
"pts": "точки"
|
||||
}
|
||||
@@ -49,7 +49,6 @@
|
||||
"UUID": "Потребителски идентификатор",
|
||||
"loadUser": "Зареждане на потребителя",
|
||||
"noAdminAccess": "Нямате администраторски достъп.",
|
||||
"pageMustBeNumber": "req.query.page трябва да бъде число",
|
||||
"userNotFound": "Потребителят не е намерен.",
|
||||
"invalidUUID": "Идентификаторът UUID трябва да бъде правилен",
|
||||
"title": "Звание",
|
||||
|
||||
@@ -304,7 +304,7 @@
|
||||
"alreadyHaveAccountLogin": "Вече имате регистрация? <strong>Влезте.</strong>",
|
||||
"dontHaveAccountSignup": "Нямате регистрация? <strong>Регистрирайте се.</strong>",
|
||||
"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": "Регистрирайте се безплатно",
|
||||
"or": "ИЛИ",
|
||||
"gamifyYourLife": "Превърнете живота си в игра",
|
||||
|
||||
@@ -106,16 +106,16 @@
|
||||
"optionalMessage": "Незадължително съобщение",
|
||||
"yesRemove": "Да, нека бъдат премахнати",
|
||||
"foreverAlone": "Не можете да харесате собственото си съобщение. Не бъдете такъв човек.",
|
||||
"sortDateJoinedAsc": "Най-ранна дата на присъединяване",
|
||||
"sortDateJoinedDesc": "Най-скорошна дата на присъединяване",
|
||||
"sortLoginAsc": "Най-ранно вписване",
|
||||
"sortLoginDesc": "Най-скорошно вписване",
|
||||
"sortLevelAsc": "Най-ниско ниво",
|
||||
"sortLevelDesc": "Най-високо ниво",
|
||||
"sortNameAsc": "Име (А-Я)",
|
||||
"sortNameDesc": "Име (Я-А)",
|
||||
"sortTierAsc": "Най-ниско ниво в системата",
|
||||
"sortTierDesc": "Най-високо ниво в системата",
|
||||
"sortBackground": "Подреждане по фоново изображение",
|
||||
"sortClass": "Подреждане по клас",
|
||||
"sortDateJoined": "Подреждане по дата на присъединяване",
|
||||
"sortLogin": "Подреждане по дата на вписване",
|
||||
"sortLevel": "Подреждане по ниво",
|
||||
"sortName": "Подреждане по име",
|
||||
"sortTier": "Подреждане по ниво на сътрудник",
|
||||
"ascendingAbbrev": "Възходящ ред",
|
||||
"descendingAbbrev": "Низходящ ред",
|
||||
"applySortToHeader": "Прилагане на настройките за подреждане към заглавната част на групата",
|
||||
"confirmGuild": "Създавате ли гилдията за 4 диаманта?",
|
||||
"leaveGroupCha": "Напускане на предизвикателствата на гилдията и…",
|
||||
"confirm": "Потвърждаване",
|
||||
@@ -131,6 +131,10 @@
|
||||
"clearAll": "Изтриване на всички съобщения",
|
||||
"confirmDeleteAllMessages": "Наистина ли искате да изтриете всички съобщения от входящата поща? Другите потребители ще виждат изпратените от Вас съобщения.",
|
||||
"optOutPopover": "Личните съобщения не Ви допадат? Щракнете тук, за да се откажете напълно от тях.",
|
||||
"PMPlaceholderTitle": "Тук все още няма нищо",
|
||||
"PMPlaceholderDescription": "Изберете разговор отляво",
|
||||
"PMPlaceholderTitleRevoked": "Привилегиите Ви в чата Ви бяха отнети",
|
||||
"PMPlaceholderDescriptionRevoked": "Не можете да изпращате лични съобщения, тъй като привилегиите Ви в чата Ви бяха отнети. Ако имате въпроси или притеснения относно това, моля, пишете на <a href=\"mailto:admin@habitica.com\">admin@habitica.com</a>, за да ги обсъдите с екипа.",
|
||||
"block": "Блокиране",
|
||||
"unblock": "Отблокиране",
|
||||
"pm-reply": "Изпращане на отговор",
|
||||
@@ -207,7 +211,6 @@
|
||||
"partyOnName": "Купонът продължава",
|
||||
"partyUpText": "Присъединил(а) се към група с още един човек! Забавлявайте се, докато заедно се биете с чудовища и се подкрепяте взаимно.",
|
||||
"partyOnText": "Присъединил(а) се към група с поне четири човека! Радвайте се на допълнителната отговорност, докато се съюзявате с приятелите си, за да побеждавате враговете си!",
|
||||
"groupIdRequired": "„groupId“ трябва да бъде правилно форматиран идентификатор UUID",
|
||||
"groupNotFound": "Групата не е намерена или нямате достъп.",
|
||||
"groupTypesRequired": "Трябва да подадете правилен низ за заявка в „type“.",
|
||||
"questLeaderCannotLeaveGroup": "Не можете да напуснете групата си, след като сте започнали мисия. Първо прекратете мисията.",
|
||||
@@ -217,8 +220,6 @@
|
||||
"memberCannotRemoveYourself": "Не можете да премахнете себе си!",
|
||||
"groupMemberNotFound": "Потребителят не е намерен сред членовете на групата",
|
||||
"mustBeGroupMember": "Трябва да бъде член на групата.",
|
||||
"keepOrRemoveAll": "req.query.keep трябва да бъде или „keep-all“, или „remove-all“",
|
||||
"keepOrRemove": "req.query.keep трябва да бъде или „keep“, или „remove“",
|
||||
"canOnlyInviteEmailUuid": "Покани могат да бъдат изпращани само чрез UUID идентификатор или е-поща.",
|
||||
"inviteMissingEmail": "В поканата липсва адрес на е-поща.",
|
||||
"inviteMissingUuid": "В поканата липсва потребителски идентификатор",
|
||||
@@ -252,7 +253,7 @@
|
||||
"userRequestsApproval": "<%= userName %> иска одобрение",
|
||||
"userCountRequestsApproval": "<%= userCount %> потребители искат одобрение",
|
||||
"youAreRequestingApproval": "Вие искате одобрение",
|
||||
"chatPrivilegesRevoked": "You cannot do that because your chat privileges have been revoked.",
|
||||
"chatPrivilegesRevoked": "Не можете да направите това, защото привилегиите Ви в чата са Ви били отнети.",
|
||||
"cannotCreatePublicGuildWhenMuted": "Не можете да създадете обществена гилдия, защото привилегиите Ви в чата са Ви били отнети.",
|
||||
"cannotInviteWhenMuted": "Не можете да изпратите покана за гилдия или група, защото привилегиите Ви в чата са Ви били отнети.",
|
||||
"newChatMessagePlainNotification": "Има ново съобщение в <%= groupName %> от <%= authorName %>. Щракнете тук, за да отворите страницата!",
|
||||
@@ -315,7 +316,7 @@
|
||||
"approvalsTitle": "Задачи, чакащи одобрение",
|
||||
"upgradeTitle": "Надграждане",
|
||||
"blankApprovalsDescription": "Когато групата Ви завърши задача, която се нуждае от одобрение, тя ще се появи тук! Можете да зададете дали дадена задача се нуждае от одобрение в настройките ѝ при редактиране.",
|
||||
"userIsClamingTask": "`<%= username %> пое „<%= task %>“`",
|
||||
"userIsClamingTask": "`<%= username %> has claimed:` <%= task %>",
|
||||
"approvalRequested": "Заявено е одобрение",
|
||||
"refreshApprovals": "Опресняване на одобренията",
|
||||
"refreshGroupTasks": "Опресняване на груповите задачи",
|
||||
@@ -323,7 +324,6 @@
|
||||
"cantDeleteAssignedGroupTasks": "Не можете да изтриете груповите задачи, които са Ви разпределени.",
|
||||
"confirmGuildPlanCreation": "Създаване на тази група?",
|
||||
"onlyGroupLeaderCanInviteToGroupPlan": "Само водачът на групата може да кани хора в група с абонамент.",
|
||||
"remainOrLeaveChallenges": "req.query.keep трябва да бъде или „remain-in-challenges“ или „leave-challenges“",
|
||||
"paymentDetails": "Подробности за разплащането",
|
||||
"aboutToJoinCancelledGroupPlan": "На път сте да се присъедините към група, чийто план е прекратен. НЯМА да получите безплатен абонамент.",
|
||||
"cannotChangeLeaderWithActiveGroupPlan": "Не можете да промените водача, докато групата има план.",
|
||||
@@ -366,9 +366,11 @@
|
||||
"recentActivity": "Последна дейност",
|
||||
"myGuilds": "Моите гилдии",
|
||||
"guildsDiscovery": "Разглеждане на гилдиите",
|
||||
"role": "Role",
|
||||
"guildOrPartyLeader": "Водач",
|
||||
"guildLeader": "Водач на гилдията",
|
||||
"member": "Член",
|
||||
"guildSize": "Guild Size",
|
||||
"goldTier": "Златно ниво",
|
||||
"silverTier": "Сребърно ниво",
|
||||
"bronzeTier": "Бронзово ниво",
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
"tip23": "Достигнете ниво 100, за да отключите Кълбото за прераждане безплатно и да започнете ново приключение!",
|
||||
"tip24": "Имате въпрос? Задайте го в помощната гилдия на Хабитика)",
|
||||
"tip25": "Четирите сезонни големи празненства започват около слънцестоенията и равноденствията.",
|
||||
"tip26": "You can look for a Party or find Party members in the Party Wanted Guild!",
|
||||
"tip26": "Можете да си потърсите група, или да откриете хора, желаещи да влязат в група, в гилдията „Търсене на група“ (Party Wanted Guild)!",
|
||||
"tip27": "Изпълнихте ежедневна задача вчера, но забравихте да го отбележите? Не се притеснявайте! С възможността за запис на вчерашната дейност можете да записвате това, което сте свършили, преди да започнете новия си ден.",
|
||||
"tip28": "Задайте свое персонализирано начало на деня от Потребителската иконка > Настройки, за да определите кога започва Вашият ден.",
|
||||
"tip29": "Завършете всичките си ежедневни задачи, за да получите подсилването „Перфектен ден“, което увеличава показателите Ви!",
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
"featuredItems": "Препоръчани предмети!",
|
||||
"hideLocked": "Скриване на заключените",
|
||||
"hidePinned": "Скриване на закачените",
|
||||
"hideMissing": "Hide Missing",
|
||||
"amountExperience": "<%= amount %> точки опит",
|
||||
"amountGold": "<%= amount %> злато",
|
||||
"namedHatchingPotion": "Излюпваща отвара с(ъс) <%= type %>",
|
||||
@@ -74,20 +75,13 @@
|
||||
"ianTextMobile": "Мога ли да Ви заинтересовам с няколко свитъка за мисии? Активирайте ги, за да се биете срещу чудовища заедно с групата си!",
|
||||
"ianBrokenText": "Добре дошли в магазина за мисии… Тук може да използвате свитъците си с мисии, за да се биете срещу чудовища заедно с приятелите си… Вижте чудесните ни свитъци с мисии, налични за купуване, вдясно…",
|
||||
"featuredQuests": "Препоръчани мисии!",
|
||||
"missingKeyParam": "„req.params.key“ е задължително.",
|
||||
"itemNotFound": "Предметът „<%= key %>“ не е намерен.",
|
||||
"cannotBuyItem": "Не може да купите този предмет.",
|
||||
"missingTypeKeyEquip": "„key“ и „type“ са задължителни параметри.",
|
||||
"missingPetFoodFeed": "„pet“ и „food“ са задължителни параметри.",
|
||||
"invalidPetName": "Подадено е неправилно име на любимец.",
|
||||
"missingEggHatchingPotionHatch": "„egg“ и „hatchingPotion“ са задължителни параметри.",
|
||||
"invalidTypeEquip": "„type“ трябва да бъде едно от следните: „equipped“, „pet“, „mount“ или „costume“.",
|
||||
"mustPurchaseToSet": "Трябва да закупите <%= val %>, за да го/я зададете на <%= key %>.",
|
||||
"typeRequired": "Типът е задължителен",
|
||||
"positiveAmountRequired": "Изисква се положително количество",
|
||||
"notAccteptedType": "Типът трябва да бъде един от следните: eggs, hatchingPotions, premiumHatchingPotions, food, quests, gear",
|
||||
"contentKeyNotFound": "Ключът не е открит за съдържанието <%= type %>",
|
||||
"plusGem": "+<%= count %> Gem",
|
||||
"plusGem": "+<%= count %> диамант",
|
||||
"typeNotSellable": "Този тип не може да се продава. Трябва да бъде един от следните: <%= acceptedTypes %>",
|
||||
"userItemsKeyNotFound": "Ключът не е намерен за user.items <%= type %>",
|
||||
"userItemsNotEnough": "Нямате достатъчно <%= type %>",
|
||||
|
||||
@@ -96,7 +96,6 @@
|
||||
"questInvitationDoesNotExist": "Няма изпратени покани за мисията.",
|
||||
"questInviteNotFound": "Няма намерени покани за мисията.",
|
||||
"guildQuestsNotSupported": "Гилдиите не могат да бъдат канени в мисии.",
|
||||
"questNotFound": "Мисията „<%= key %>“ не беше намерена.",
|
||||
"questNotOwned": "Не притежавате този свитък с мисия.",
|
||||
"questNotGoldPurchasable": "Мисията „<%= key %>“ не може да бъде купена със злато.",
|
||||
"questLevelTooHigh": "Трябва да бъдете ниво <%= level %>, за да започнете тази мисия.",
|
||||
|
||||
@@ -102,7 +102,7 @@
|
||||
"questGoldenknight2Text": "Златният рицар, част 2: Златен рицар",
|
||||
"questGoldenknight2Notes": "Въоръжен(а) със стотици показания на хабитиканци, ти най-после се изправяш срещу Златния рицар. Започваш да четеш оплакванията на хабитиканците срещу нея, едно по едно: „А @Pfeffernusse казва, че постоянното ти натякване…“ — рицарят вдига ръка, за да те спре, и казва надменно: „Моля те, тези хора просто завиждат на успеха ми. Вместо да се оплакват, може просто да работят усърдно като мен! Може би трябва да ти демонстрирам силата, която може да получиш, ако се стараеш като мен!“ — тя вдига боздугана си и се приготвя да те нападне!",
|
||||
"questGoldenknight2Boss": "Златен рицар",
|
||||
"questGoldenknight2Completion": "The Golden Knight lowers her Morningstar in consternation. “I apologize for my rash outburst,” she says. “The truth is, it’s painful to think that I’ve been inadvertently hurting others, and it made me lash out in defense… but perhaps I can still apologize?”",
|
||||
"questGoldenknight2Completion": "Златният рицар със смайване сваля боздугана си. — „Извинявам се за прибързаното си избухване“ — казва тя. — „Истината е, че ме боли, когато си помисля, че може да наранявам останалите, и това ме накара да се защитавам твърде упорито… Надявам се, че не е късно да се извиня?“",
|
||||
"questGoldenknight2DropGoldenknight3Quest": "Златният рицар, част 3: Железният рицар (свитък)",
|
||||
"questGoldenknight3Text": "Златният рицар, част 3: Железният рицар",
|
||||
"questGoldenknight3Notes": "@Jon Arinbjorn изкрещява, за да привлече вниманието ти. След края на битката ти се е появила някаква нова фигура. Рицар, облечен в желязо на черни петна, бавно се приближава към теб с меч в ръка. Златният рицар извиква към фигурата: „Татко, не!“ — но рицарят изглежда не смята да спира. Тя се обръща към теб и казва: „Съжалявам. Бях глупачка, не осъзнавах колко съм жестока. Но баща ми е по-жесток, отколкото аз бих могла да бъда някога. Ако не бъде спрян, ще унищожи всички ни. Ето, използвай боздугана ми и спри Железния рицар!“",
|
||||
@@ -600,5 +600,7 @@
|
||||
"questSquirrelCompletion": "С внимателен подход, подкупи и няколко успокояващи заклинания, успявате да придумате катерицата да се отмести от плячката си и да се насочи към конюшнята, където @Shtut вече е успял да премахне всички жълъди. Няколко от жълъдите са подредени на една работна маса. „Това са яйца на катерица! Може би ще успееш да отгледаш някоя катерица, която няма да си играе толкова много с храната си.“",
|
||||
"questSquirrelBoss": "Хитра катерица",
|
||||
"questSquirrelDropSquirrelEgg": "Катерица (яйце)",
|
||||
"questSquirrelUnlockText": "Отключва възможността за купуване на яйца на катерица от пазара."
|
||||
"questSquirrelUnlockText": "Отключва възможността за купуване на яйца на катерица от пазара.",
|
||||
"cuddleBuddiesText": "Пакет мисии „Пухкави приятелчета“",
|
||||
"cuddleBuddiesNotes": "Съдържа: „Зайчето-убиец“, „Нечестивият пор“ и „Бандата на морските свинчета“. Наличен до 31 май."
|
||||
}
|
||||
@@ -32,7 +32,7 @@
|
||||
"resetAccPop": "Започнете отначало, премахвайки всички нива, злато, екипировка, история и задачи.",
|
||||
"deleteAccount": "Изтриване на профила",
|
||||
"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-код",
|
||||
"dataExport": "Изнасяне на данни",
|
||||
"saveData": "Ето няколко възможности за запазване на данните Ви.",
|
||||
|
||||
@@ -51,7 +51,6 @@
|
||||
"spellSpecialSeafoamNotes": "Превърнете приятел в морско създание!",
|
||||
"spellSpecialSandText": "Пясък",
|
||||
"spellSpecialSandNotes": "Развалете заклинанието, което Ви е превърнало в морска звезда.",
|
||||
"spellNotFound": "Умението „<%= spellId %>“ не е намерено.",
|
||||
"partyNotFound": "Групата не е намерена",
|
||||
"targetIdUUID": "„targetId“ трябва да бъде правилен потребителски идентификатор.",
|
||||
"challengeTasksNoCast": "Използването на умения върху задачи от предизвикателства не е позволено.",
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"buyGemsGoldText": "Александър Търговеца ще Ви продава диаманти на цената от 20 злато за диамант. Месечните му доставки първоначално са ограничени до 25 диаманта на месец, но това ограничение се увеличава с 5 диаманта за всеки 3 месеца на непрекъснат абонамент, докато достигне 50 диаманта на месец!",
|
||||
"mustSubscribeToPurchaseGems": "Купуването на диаманти със злато изисква абонамент",
|
||||
"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": "Запазвате по-голяма история",
|
||||
"retainHistoryText": "Завършените задачи за изпълнение остават по-дълго в историята.",
|
||||
"doubleDrops": "Ежедневното ограничение на паданията е два пъти по-голямо",
|
||||
@@ -175,12 +175,6 @@
|
||||
"invalidCoupon": "Грешен код от купон.",
|
||||
"couponUsed": "Този код от купон вече е използван.",
|
||||
"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": "Абонаментът Ви е прекратен",
|
||||
"earnGemsMonthly": "Получавайте до **<%= cap %> диаманта** на месец",
|
||||
"receiveMysticHourglass": "Получете Тайнствен пясъчен часовник!",
|
||||
|
||||
@@ -145,7 +145,6 @@
|
||||
"rewardHelp3": "По време на световни събития, тук ще се появява специалната екипировка.",
|
||||
"rewardHelp4": "Не се притеснявайте да си създадете свои собствени награди! Вижте <a href='http://habitica.wikia.com/wiki/Sample_Custom_Rewards' target='_blank'>примерите тук</a>.",
|
||||
"clickForHelp": "Щракнете за помощ",
|
||||
"taskIdRequired": "„taskId“ трябва да бъде правилно форматиран идентификатор UUID.",
|
||||
"taskAliasAlreadyUsed": "Псевдонимът на задачата вече се използва за друга задача.",
|
||||
"taskNotFound": "Задачата не е намерена.",
|
||||
"invalidTaskType": "Типът на задачата трябва да бъде един от следните: „habit“, „daily“, „todo“, „reward“.",
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
"challengeWinner": "Stal se výhercem následujících výzev",
|
||||
"challenges": "Výzvy",
|
||||
"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",
|
||||
"toCreate": "abys nějakou vytvořil.",
|
||||
"selectWinner": "Zvolit vítěze a zavřít výzvu:",
|
||||
@@ -23,7 +25,9 @@
|
||||
"filter": "Filtr",
|
||||
"groups": "Skupiny",
|
||||
"noNone": "Žádné",
|
||||
"category": "Category",
|
||||
"membership": "Členství",
|
||||
"ownership": "Ownership",
|
||||
"participating": "Účastní se",
|
||||
"notParticipating": "Neúčastní se",
|
||||
"either": "Obojí",
|
||||
|
||||
@@ -201,7 +201,6 @@
|
||||
"showQuickAllocation": "Zobrazit 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.",
|
||||
"invalidAttribute": "\"<%= attr %>\" není platný atribut.",
|
||||
"notEnoughAttrPoints": "Nemáš dostatek vlastnostních bodů",
|
||||
"style": "Styl",
|
||||
"facialhair": "Vousy",
|
||||
@@ -219,6 +218,5 @@
|
||||
"mainHand": "Hlavní ruka",
|
||||
"offHand": "Druhá ruka",
|
||||
"pointsAvailable": "Dostupné body",
|
||||
"pts": "Body",
|
||||
"statsObjectRequired": "Je požadována aktualizace atributů"
|
||||
"pts": "Body"
|
||||
}
|
||||
@@ -49,7 +49,6 @@
|
||||
"UUID": "ID uživatele",
|
||||
"loadUser": "Načíst uživatele",
|
||||
"noAdminAccess": "Nemáte adminský přístup.",
|
||||
"pageMustBeNumber": "req.query.page musí být číslo",
|
||||
"userNotFound": "Uživatel nenalezen.",
|
||||
"invalidUUID": "UUID musí být platné.",
|
||||
"title": "Název",
|
||||
|
||||
@@ -106,16 +106,16 @@
|
||||
"optionalMessage": "Nepovinná zpráva",
|
||||
"yesRemove": "Ano, odstraň je",
|
||||
"foreverAlone": "Nemůže se ti líbit tvoje vlastní zpráva. Nebuď takový.",
|
||||
"sortDateJoinedAsc": "Earliest Date Joined",
|
||||
"sortDateJoinedDesc": "Latest Date Joined",
|
||||
"sortLoginAsc": "Earliest Login",
|
||||
"sortLoginDesc": "Latest Login",
|
||||
"sortLevelAsc": "Lowest Level",
|
||||
"sortLevelDesc": "Highest Level",
|
||||
"sortNameAsc": "Name (A - Z)",
|
||||
"sortNameDesc": "Name (Z - A)",
|
||||
"sortTierAsc": "Lowest Tier",
|
||||
"sortTierDesc": "Highest Tier",
|
||||
"sortBackground": "Sort by Background",
|
||||
"sortClass": "Sort by Class",
|
||||
"sortDateJoined": "Sort by Join Date",
|
||||
"sortLogin": "Sort by Login Date",
|
||||
"sortLevel": "Sort by Level",
|
||||
"sortName": "Sort by Name",
|
||||
"sortTier": "Sort by Tier",
|
||||
"ascendingAbbrev": "Asc",
|
||||
"descendingAbbrev": "Desc",
|
||||
"applySortToHeader": "Apply Sort Options to Party Header",
|
||||
"confirmGuild": "Vytvořit cech za 4 drahokamy?",
|
||||
"leaveGroupCha": "Opustit výzvy cechu a...",
|
||||
"confirm": "Potvrdit",
|
||||
@@ -131,6 +131,10 @@
|
||||
"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.",
|
||||
"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",
|
||||
"unblock": "Odblokovat",
|
||||
"pm-reply": "Poslat odpověď",
|
||||
@@ -207,7 +211,6 @@
|
||||
"partyOnName": "Velká družina",
|
||||
"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!",
|
||||
"groupIdRequired": "„groupId\" musí být platné UUID",
|
||||
"groupNotFound": "Group not found or you don't have access.",
|
||||
"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.",
|
||||
@@ -217,8 +220,6 @@
|
||||
"memberCannotRemoveYourself": "Nemůžete se sám odebrat!",
|
||||
"groupMemberNotFound": "Uživatel nenalezen mezi členy 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.",
|
||||
"inviteMissingEmail": "Chybějící emailová adresa v pozvánce.",
|
||||
"inviteMissingUuid": "Missing user id in invite",
|
||||
@@ -315,7 +316,7 @@
|
||||
"approvalsTitle": "Tasks Awaiting Approval",
|
||||
"upgradeTitle": "Upgrade",
|
||||
"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",
|
||||
"refreshApprovals": "Refresh Approvals",
|
||||
"refreshGroupTasks": "Refresh Group Tasks",
|
||||
@@ -323,7 +324,6 @@
|
||||
"cantDeleteAssignedGroupTasks": "Can't delete group tasks that are assigned to you.",
|
||||
"confirmGuildPlanCreation": "Create this group?",
|
||||
"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",
|
||||
"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.",
|
||||
@@ -366,9 +366,11 @@
|
||||
"recentActivity": "Recent Activity",
|
||||
"myGuilds": "My Guilds",
|
||||
"guildsDiscovery": "Discover Guilds",
|
||||
"role": "Role",
|
||||
"guildOrPartyLeader": "Leader",
|
||||
"guildLeader": "Guild Leader",
|
||||
"member": "Member",
|
||||
"guildSize": "Guild Size",
|
||||
"goldTier": "Gold Tier",
|
||||
"silverTier": "Silver Tier",
|
||||
"bronzeTier": "Bronze Tier",
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
"featuredItems": "Zmíněné předměty!",
|
||||
"hideLocked": "Hide locked",
|
||||
"hidePinned": "Hide pinned",
|
||||
"hideMissing": "Hide Missing",
|
||||
"amountExperience": "<%= amount %> Zkušenost",
|
||||
"amountGold": "<%= amount %> Zlato",
|
||||
"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!",
|
||||
"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!",
|
||||
"missingKeyParam": "Je požadovaný \"req.params.key\".",
|
||||
"itemNotFound": "Předmět „<%= key %>\" nenalezen.",
|
||||
"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 %>.",
|
||||
"typeRequired": "Je požadován typ",
|
||||
"positiveAmountRequired": "Pozitivní množství je požadováno",
|
||||
|
||||
@@ -96,7 +96,6 @@
|
||||
"questInvitationDoesNotExist": "Zatím vám nebyla poslána žádná pozvánka na výpravu.",
|
||||
"questInviteNotFound": "Nebyla nalezena žádná pozvánka na výpravu.",
|
||||
"guildQuestsNotSupported": "Cechy nelze pozvat na výpravy.",
|
||||
"questNotFound": "Výprava „<%= key %>\" nenalezena.",
|
||||
"questNotOwned": "Nevlastníte tento svitek výpravy.",
|
||||
"questNotGoldPurchasable": "Výpravu „<%= key %>\" nelze koupit na zlato.",
|
||||
"questLevelTooHigh": "Pro začátek výpravy musíte mít úroveň <%= level %>.",
|
||||
|
||||
@@ -600,5 +600,7 @@
|
||||
"questSquirrelCompletion": "With a gentle approach, offers of trade, and a few soothing spells, you’re able to coax the squirrel away from its hoard and back to the stables, which @Shtut has just finished de-acorning. They’ve set aside a few of the acorns on a worktable. “These ones are squirrel eggs! Maybe you can raise some that don’t play with their food quite so much.”",
|
||||
"questSquirrelBoss": "Sneaky Squirrel",
|
||||
"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."
|
||||
}
|
||||
@@ -51,7 +51,6 @@
|
||||
"spellSpecialSeafoamNotes": "Přeměň svého kamaráda na mořskou příšerku!",
|
||||
"spellSpecialSandText": "Písek",
|
||||
"spellSpecialSandNotes": "Zvrať kouzlo, které z tebe udělalo mořskou hvězdu.",
|
||||
"spellNotFound": "Schopnost „<%= spellId %>\" nenalezena.",
|
||||
"partyNotFound": "Družina nenalezena",
|
||||
"targetIdUUID": "„cílovéId\" musí být platné ID uživatele. ",
|
||||
"challengeTasksNoCast": "Použití schopnosti na úkol z výzvy není povoleno.",
|
||||
|
||||
@@ -175,12 +175,6 @@
|
||||
"invalidCoupon": "Neplatný kód kupónu.",
|
||||
"couponUsed": "Kód kupónu byl již použit.",
|
||||
"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",
|
||||
"earnGemsMonthly": "Earn up to **<%= cap %> Gems** per month",
|
||||
"receiveMysticHourglass": "Receive a Mystic Hourglass!",
|
||||
|
||||
@@ -145,7 +145,6 @@
|
||||
"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>.",
|
||||
"clickForHelp": "Klikni pro nápovědu",
|
||||
"taskIdRequired": "\"taskId\" musí být platné UUID.",
|
||||
"taskAliasAlreadyUsed": "Alias úkolu byl již použit na jiném úkolu.",
|
||||
"taskNotFound": "Úkol nenalezen.",
|
||||
"invalidTaskType": "Typ úkolu musí být „zvyk\", „denní úkol\", „úkol\" nebo „odměna\".",
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
"challengeWinner": "Blev vinderen i de følgende udfordringer",
|
||||
"challenges": "Udfordringer",
|
||||
"challengesLink": "<a href='http://habitica.wikia.com/wiki/Challenges' target='_blank'>Udfordringer</a>",
|
||||
"challengePrize": "Challenge Prize",
|
||||
"endDate": "Ends",
|
||||
"noChallenges": "Ingen udfordringer endnu, besøg",
|
||||
"toCreate": "for at oprette en.",
|
||||
"selectWinner": "Vælg en vinder og luk udfordringen:",
|
||||
@@ -23,7 +25,9 @@
|
||||
"filter": "Filter",
|
||||
"groups": "Grupper",
|
||||
"noNone": "Ingen",
|
||||
"category": "Category",
|
||||
"membership": "Medlemskab",
|
||||
"ownership": "Ownership",
|
||||
"participating": "Deltager",
|
||||
"notParticipating": "Deltager ikke",
|
||||
"either": "Begge",
|
||||
|
||||
@@ -201,7 +201,6 @@
|
||||
"showQuickAllocation": "Show 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.",
|
||||
"invalidAttribute": "\"<%= attr %>\" is not a valid Stat.",
|
||||
"notEnoughAttrPoints": "You don't have enough Stat Points.",
|
||||
"style": "Stil",
|
||||
"facialhair": "Facial",
|
||||
@@ -219,6 +218,5 @@
|
||||
"mainHand": "Main-Hand",
|
||||
"offHand": "Off-Hand",
|
||||
"pointsAvailable": "Points Available",
|
||||
"pts": "pts",
|
||||
"statsObjectRequired": "Stats update is required"
|
||||
"pts": "pts"
|
||||
}
|
||||
@@ -49,7 +49,6 @@
|
||||
"UUID": "BrugerID",
|
||||
"loadUser": "Indlæs bruger",
|
||||
"noAdminAccess": "Du har ikke administrator-adgang.",
|
||||
"pageMustBeNumber": "req.query.page skal være et tal",
|
||||
"userNotFound": "Bruger ikke fundet.",
|
||||
"invalidUUID": "UUID skal være gyldigt",
|
||||
"title": "Titel",
|
||||
|
||||
@@ -106,16 +106,16 @@
|
||||
"optionalMessage": "Valgfri besked",
|
||||
"yesRemove": "Ja, fjern dem",
|
||||
"foreverAlone": "Du kan ikke synes godt om din egen besked. Lad være med at være sådan.",
|
||||
"sortDateJoinedAsc": "Earliest Date Joined",
|
||||
"sortDateJoinedDesc": "Latest Date Joined",
|
||||
"sortLoginAsc": "Earliest Login",
|
||||
"sortLoginDesc": "Latest Login",
|
||||
"sortLevelAsc": "Lowest Level",
|
||||
"sortLevelDesc": "Highest Level",
|
||||
"sortNameAsc": "Name (A - Z)",
|
||||
"sortNameDesc": "Name (Z - A)",
|
||||
"sortTierAsc": "Lowest Tier",
|
||||
"sortTierDesc": "Highest Tier",
|
||||
"sortBackground": "Sort by Background",
|
||||
"sortClass": "Sort by Class",
|
||||
"sortDateJoined": "Sort by Join Date",
|
||||
"sortLogin": "Sort by Login Date",
|
||||
"sortLevel": "Sort by Level",
|
||||
"sortName": "Sort by Name",
|
||||
"sortTier": "Sort by Tier",
|
||||
"ascendingAbbrev": "Asc",
|
||||
"descendingAbbrev": "Desc",
|
||||
"applySortToHeader": "Apply Sort Options to Party Header",
|
||||
"confirmGuild": "Opret Klan for 4 Ædelsten?",
|
||||
"leaveGroupCha": "Forlad Klanudfordringer og...",
|
||||
"confirm": "Bekræft",
|
||||
@@ -131,6 +131,10 @@
|
||||
"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.",
|
||||
"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",
|
||||
"unblock": "Fjern blokering",
|
||||
"pm-reply": "Send svar",
|
||||
@@ -207,7 +211,6 @@
|
||||
"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.",
|
||||
"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.",
|
||||
"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.",
|
||||
@@ -217,8 +220,6 @@
|
||||
"memberCannotRemoveYourself": "Du kan ikke fjerne dig selv!",
|
||||
"groupMemberNotFound": "Bruger ikke fundet blandt gruppens medlemmer",
|
||||
"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.",
|
||||
"inviteMissingEmail": "Manglende emailadresse i invitationen",
|
||||
"inviteMissingUuid": "Manglende bruger-id i invitationen",
|
||||
@@ -315,7 +316,7 @@
|
||||
"approvalsTitle": "Tasks Awaiting Approval",
|
||||
"upgradeTitle": "Opgradér",
|
||||
"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",
|
||||
"refreshApprovals": "Refresh Approvals",
|
||||
"refreshGroupTasks": "Refresh Group Tasks",
|
||||
@@ -323,7 +324,6 @@
|
||||
"cantDeleteAssignedGroupTasks": "Du kan ikke slette gruppe opgaver, der er blevet tildelt til dig.",
|
||||
"confirmGuildPlanCreation": "Opret denne gruppe?",
|
||||
"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",
|
||||
"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.",
|
||||
@@ -366,9 +366,11 @@
|
||||
"recentActivity": "Recent Activity",
|
||||
"myGuilds": "My Guilds",
|
||||
"guildsDiscovery": "Discover Guilds",
|
||||
"role": "Role",
|
||||
"guildOrPartyLeader": "Leader",
|
||||
"guildLeader": "Guild Leader",
|
||||
"member": "Member",
|
||||
"guildSize": "Guild Size",
|
||||
"goldTier": "Gold Tier",
|
||||
"silverTier": "Silver Tier",
|
||||
"bronzeTier": "Bronze Tier",
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
"featuredItems": "Featured Items!",
|
||||
"hideLocked": "Hide locked",
|
||||
"hidePinned": "Hide pinned",
|
||||
"hideMissing": "Hide Missing",
|
||||
"amountExperience": "<%= amount %> Experience",
|
||||
"amountGold": "<%= amount %> Gold",
|
||||
"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!",
|
||||
"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!",
|
||||
"missingKeyParam": "\"req.params.key\" nødvendig.",
|
||||
"itemNotFound": "Objekt \"<%= key %>\" ikke fundet",
|
||||
"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 %>.",
|
||||
"typeRequired": "Type er nødvendig",
|
||||
"positiveAmountRequired": "Positive amount is required",
|
||||
|
||||
@@ -96,7 +96,6 @@
|
||||
"questInvitationDoesNotExist": "Ingen quest invitation er blevet udsendt endnu.",
|
||||
"questInviteNotFound": "Ingen questinvitation fundet.",
|
||||
"guildQuestsNotSupported": "Klaner kan ikke blive inviteret på quests.",
|
||||
"questNotFound": "Quest \"<%= key %>\" ikke fundet.",
|
||||
"questNotOwned": "Du ejer ikke den quest-skriftrulle",
|
||||
"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.",
|
||||
|
||||
@@ -600,5 +600,7 @@
|
||||
"questSquirrelCompletion": "With a gentle approach, offers of trade, and a few soothing spells, you’re able to coax the squirrel away from its hoard and back to the stables, which @Shtut has just finished de-acorning. They’ve set aside a few of the acorns on a worktable. “These ones are squirrel eggs! Maybe you can raise some that don’t play with their food quite so much.”",
|
||||
"questSquirrelBoss": "Sneaky Squirrel",
|
||||
"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."
|
||||
}
|
||||
@@ -51,7 +51,6 @@
|
||||
"spellSpecialSeafoamNotes": "Gør en ven til et søuhyre!",
|
||||
"spellSpecialSandText": "Sand",
|
||||
"spellSpecialSandNotes": "Reverse the spell that made you a sea star.",
|
||||
"spellNotFound": "Evne \"<%= spellId %>\" blev ikke fundet.",
|
||||
"partyNotFound": "Gruppe blev ikke fundet",
|
||||
"targetIdUUID": "\"targetId\" skal være et gyldigt Bruger ID.",
|
||||
"challengeTasksNoCast": "Det er ikke tilladt at kaste evner på en udfordrings-opgave.",
|
||||
|
||||
@@ -175,12 +175,6 @@
|
||||
"invalidCoupon": "Ugyldig kuponkode.",
|
||||
"couponUsed": "Kuponkode allerede i brug.",
|
||||
"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.",
|
||||
"earnGemsMonthly": "Earn up to **<%= cap %> Gems** per month",
|
||||
"receiveMysticHourglass": "Receive a Mystic Hourglass!",
|
||||
|
||||
@@ -145,7 +145,6 @@
|
||||
"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>.",
|
||||
"clickForHelp": "Klik for hjælp",
|
||||
"taskIdRequired": "\"taksID\" skal være et gyldigt Unikt Bruger-ID.",
|
||||
"taskAliasAlreadyUsed": "Alias allerede i brug på en anden opgave.",
|
||||
"taskNotFound": "Opgave ikke fundet.",
|
||||
"invalidTaskType": "Opgave type skal være \"vane\", \"daglig\", \"todo\" eller \"belønning\".",
|
||||
|
||||
@@ -346,11 +346,11 @@
|
||||
"backgroundFlyingOverWildflowerFieldNotes": "Schwebe über einer Wildblumenwiese.",
|
||||
"backgroundFlyingOverAncientForestText": "Uralter Wald",
|
||||
"backgroundFlyingOverAncientForestNotes": "Fliege über das Blätterdach eines uralten Waldes.",
|
||||
"backgrounds052018": "SET 48: Released May 2018",
|
||||
"backgroundTerracedRiceFieldText": "Terraced Rice Field",
|
||||
"backgroundTerracedRiceFieldNotes": "Enjoy a Terraced Rice Field in the growing season.",
|
||||
"backgroundFantasticalShoeStoreText": "Fantastical Shoe Store",
|
||||
"backgroundFantasticalShoeStoreNotes": "Look for fun new footwear in the Fantastical Shoe Store.",
|
||||
"backgroundChampionsColosseumText": "Champions' Colosseum",
|
||||
"backgroundChampionsColosseumNotes": "Bask in the glory of the Champions' Colosseum."
|
||||
"backgrounds052018": "SATZ 48: Erschien im May 2018",
|
||||
"backgroundTerracedRiceFieldText": "Terrassenreisfeld",
|
||||
"backgroundTerracedRiceFieldNotes": "Genieße ein Terrassenreisfeld während der Wachstumsphase.",
|
||||
"backgroundFantasticalShoeStoreText": "Großartiges Schuhgeschäft",
|
||||
"backgroundFantasticalShoeStoreNotes": "Schau' dich im Großartigen Schuhgeschäft nach tollen neuen Schuhen um.",
|
||||
"backgroundChampionsColosseumText": "Kolosseum der Champions",
|
||||
"backgroundChampionsColosseumNotes": "Sonne dich im Ruhm des Kolosseums der Champions."
|
||||
}
|
||||
@@ -13,6 +13,8 @@
|
||||
"challengeWinner": "Hat die folgenden Wettbewerbe gewonnen",
|
||||
"challenges": "Wettbewerbe",
|
||||
"challengesLink": "<a href='http://habitica.wikia.com/wiki/Challenges' target='_blank'>Herausforderungen</a>",
|
||||
"challengePrize": "Challenge Prize",
|
||||
"endDate": "Ends",
|
||||
"noChallenges": "Keine Wettbewerbe gefunden, besuche",
|
||||
"toCreate": "um einen Wettbewerb zu erstellen.",
|
||||
"selectWinner": "Wähle einen Gewinner und beende den Wettbewerb.",
|
||||
@@ -23,7 +25,9 @@
|
||||
"filter": "Filter",
|
||||
"groups": "Gruppen",
|
||||
"noNone": "Niemand",
|
||||
"category": "Category",
|
||||
"membership": "Mitgliedschaft",
|
||||
"ownership": "Ownership",
|
||||
"participating": "Teilnehmer",
|
||||
"notParticipating": "Nicht Teilnehmer",
|
||||
"either": "Beides",
|
||||
|
||||
@@ -201,7 +201,6 @@
|
||||
"showQuickAllocation": "Attributspunkte verteilung anzeigen",
|
||||
"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.",
|
||||
"invalidAttribute": "\"<%= attr %>\" ist kein gültiges Attribut.",
|
||||
"notEnoughAttrPoints": "Du hast nicht genug Attributpunkte.",
|
||||
"style": "Stil",
|
||||
"facialhair": "Bart",
|
||||
@@ -219,6 +218,5 @@
|
||||
"mainHand": "Haupthand",
|
||||
"offHand": "Schildhand",
|
||||
"pointsAvailable": "Verfügbare Punkte",
|
||||
"pts": "Pkte",
|
||||
"statsObjectRequired": "Werte-Update ist erforderlich"
|
||||
"pts": "Pkte"
|
||||
}
|
||||
@@ -10,8 +10,8 @@
|
||||
"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. ",
|
||||
"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:",
|
||||
"commGuideList02B": "<strong>Obey all of the <a href='/static/terms' target='_blank'>Terms and Conditions</a></strong>.",
|
||||
"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>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.",
|
||||
"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.",
|
||||
@@ -119,7 +119,7 @@
|
||||
"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!",
|
||||
"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.",
|
||||
"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.",
|
||||
|
||||
@@ -49,7 +49,6 @@
|
||||
"UUID": "Benutzer-ID",
|
||||
"loadUser": "Spieler laden",
|
||||
"noAdminAccess": "Du hast keine Administratorrechte.",
|
||||
"pageMustBeNumber": "req.query.page muss eine Zahl sein",
|
||||
"userNotFound": "Benutzer nicht gefunden.",
|
||||
"invalidUUID": "UUID muss gültig sein",
|
||||
"title": "Titel",
|
||||
|
||||
@@ -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!",
|
||||
"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",
|
||||
"pkMoreQuestions": "Do you have a question that’s 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",
|
||||
"pkPromo": "Aktionen",
|
||||
"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\".",
|
||||
"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.",
|
||||
"accountSuspendedTitle": "Account has been suspended",
|
||||
"accountSuspendedTitle": "Dieser Account wurde suspendiert. ",
|
||||
"unsupportedNetwork": "Dieses Netzwerk wird aktuell nicht unterstützt.",
|
||||
"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.",
|
||||
|
||||
@@ -1021,7 +1021,7 @@
|
||||
"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.",
|
||||
"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",
|
||||
"headMystery301404Notes": "Ein schicker Zylinder für die feinsten Ehrenleute! Gewährt keinen Attributbonus. Abonnentengegenstand, Januar 3015.",
|
||||
"headMystery301405Text": "Einfacher Zylinder",
|
||||
@@ -1357,11 +1357,11 @@
|
||||
"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.",
|
||||
"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",
|
||||
"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.",
|
||||
"backMystery201804Text": "Squirrel Tail",
|
||||
"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.",
|
||||
"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": "Eichörnchenschwanz",
|
||||
"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",
|
||||
"backSpecialWonderconRedNotes": "Strotzt vor Stärke und Schönheit. Gewährt keinen Attributbonus. Special Edition Convention-Gegenstand.",
|
||||
"backSpecialWonderconBlackText": "Tückischer Umhang",
|
||||
@@ -1405,7 +1405,7 @@
|
||||
"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.",
|
||||
"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",
|
||||
"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",
|
||||
@@ -1474,8 +1474,8 @@
|
||||
"headAccessoryMystery201510Notes": "Diese schreckenerregenden Hörner sind ein wenig schleimig. Gewährt keinen Attributbonus. Abonnentengegenstand, Oktober 2015.",
|
||||
"headAccessoryMystery201801Text": "Frostkobold-Geweih",
|
||||
"headAccessoryMystery201801Notes": "Dieses eigige Geweih schimmert mit dem Glanze eines Winterpolarlichts. Gewährt keinen Attributbonus. Abonnentengegenstand, Januar 2018.",
|
||||
"headAccessoryMystery201804Text": "Squirrel Ears",
|
||||
"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.",
|
||||
"headAccessoryMystery201804Text": "Eichörnchenohren",
|
||||
"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",
|
||||
"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",
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"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.",
|
||||
"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",
|
||||
"helpfulLinks": "Weiterführende Links",
|
||||
"communityGuidelinesLink": "Community-Richtlinien",
|
||||
@@ -34,7 +34,7 @@
|
||||
"communityGuidelines": "Community-Richtlinien",
|
||||
"communityGuidelinesRead1": "Bitte lies unsere",
|
||||
"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.",
|
||||
"party": "Gruppe",
|
||||
"createAParty": "Gruppe erstellen",
|
||||
@@ -106,16 +106,16 @@
|
||||
"optionalMessage": "Optionale Nachricht",
|
||||
"yesRemove": "Ja, entferne sie",
|
||||
"foreverAlone": "\"Gefällt mir\" funktioniert nicht bei eigenen Nachrichten. Sei nicht so einer.",
|
||||
"sortDateJoinedAsc": "Frühestes Beitrittsdatum",
|
||||
"sortDateJoinedDesc": "Letztes Beitrittsdatum",
|
||||
"sortLoginAsc": "Frühester Login",
|
||||
"sortLoginDesc": "Letzter Login",
|
||||
"sortLevelAsc": "Niedrigster Level",
|
||||
"sortLevelDesc": "Höchster Level",
|
||||
"sortNameAsc": "Name (A - Z)",
|
||||
"sortNameDesc": "Name (Z - A)",
|
||||
"sortTierAsc": "Niedrigster Rang",
|
||||
"sortTierDesc": "Höchster Rang",
|
||||
"sortBackground": "Nach Hintergrund sortieren",
|
||||
"sortClass": "Sortiere nach Klasse",
|
||||
"sortDateJoined": "Nach Beitrittsdatum sortieren",
|
||||
"sortLogin": "Sortiere nach Login Datum ",
|
||||
"sortLevel": "Nach Level sortieren",
|
||||
"sortName": "Sortiere nach Name",
|
||||
"sortTier": "Nach Rang sortieren",
|
||||
"ascendingAbbrev": "Aufsteigend",
|
||||
"descendingAbbrev": "Absteigend",
|
||||
"applySortToHeader": "Apply Sort Options to Party Header",
|
||||
"confirmGuild": "Gilde für 4 Edelsteine gründen?",
|
||||
"leaveGroupCha": "Gildenwettbewerbe verlassen und ...",
|
||||
"confirm": "Bestätigen",
|
||||
@@ -131,6 +131,10 @@
|
||||
"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.",
|
||||
"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",
|
||||
"unblock": "Entsperren",
|
||||
"pm-reply": "Eine Antwort schicken",
|
||||
@@ -146,12 +150,12 @@
|
||||
"report": "Melden",
|
||||
"abuseFlag": "Verletzung der Community-Richtlinien melden",
|
||||
"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",
|
||||
"abuseReported": "Danke, dass Du diesen Verstoß gemeldet hast. Die Moderatoren wurden benachrichtigt.",
|
||||
"abuseAlreadyReported": "Du hast diese Nachricht bereits gemeldet.",
|
||||
"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",
|
||||
"needsText": "Bitte gib eine Nachricht ein.",
|
||||
"needsTextPlaceholder": "Gib Deine Nachricht hier ein.",
|
||||
@@ -163,7 +167,7 @@
|
||||
"leaderOnlyChallenges": "Nur der Gruppenleiter kann Wettbewerbe erstellen",
|
||||
"sendGift": "Geschenk schicken",
|
||||
"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",
|
||||
"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.",
|
||||
@@ -197,17 +201,16 @@
|
||||
"partyExplanation2": "Bekämpfe Monster und nimm an Wettbewerben teil!",
|
||||
"partyExplanation3": "Lade jetzt Freunde ein und erhalte eine Questschriftrolle!",
|
||||
"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!",
|
||||
"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.",
|
||||
"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!",
|
||||
"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. ",
|
||||
"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.",
|
||||
"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.",
|
||||
@@ -217,15 +220,13 @@
|
||||
"memberCannotRemoveYourself": "Du kannst Dich nicht selbst entfernen!",
|
||||
"groupMemberNotFound": "Benutzer nicht unter den Team-Mitgliedern gefunden",
|
||||
"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.",
|
||||
"inviteMissingEmail": "Fehlende E-Mail-Adresse zum Einladen.",
|
||||
"inviteMissingUuid": "User-ID in der Einladung fehlt",
|
||||
"inviteMustNotBeEmpty": "Einladung muss Daten enthalten",
|
||||
"partyMustbePrivate": "Gruppen müssen privat sein",
|
||||
"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.",
|
||||
"userAlreadyInvitedToGroup": "Nutzer-ID: <%= userId %>, Nutzer \"<%= username %>\" wurde bereits zu dieser Gruppe eingeladen.",
|
||||
"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?",
|
||||
"confirmUnClaim": "Bist Du sicher, dass Du diese Aufgabe abgeben 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",
|
||||
"userCountRequestsApproval": "<%= userCount %> beantragen eine Bestätigung",
|
||||
"youAreRequestingApproval": "Du beantragst eine Bestätigung",
|
||||
"chatPrivilegesRevoked": "You cannot do that because your chat privileges have been revoked.",
|
||||
"cannotCreatePublicGuildWhenMuted": "You cannot create a public guild because your chat privileges have been revoked.",
|
||||
"cannotInviteWhenMuted": "You cannot invite anyone to a guild or party because your chat privileges have been revoked.",
|
||||
"chatPrivilegesRevoked": "Du kannst dies nicht tun, da Dir Deine Chat-Privilegien entzogen wurden.",
|
||||
"cannotCreatePublicGuildWhenMuted": "Du kannst keine öffentliche Gilde erstellen, da Dir Deine Chat-Privilegien entzogen wurden.",
|
||||
"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!",
|
||||
"newChatMessageTitle": "Neue Nachricht in <%= groupName %>",
|
||||
"exportInbox": "Nachrichten exportieren",
|
||||
@@ -268,7 +269,7 @@
|
||||
"groupHomeTitle": "Startseite",
|
||||
"assignTask": "Aufgabe zuweisen",
|
||||
"claim": "Anspruch",
|
||||
"removeClaim": "Remove Claim",
|
||||
"removeClaim": "Anspruch abtreten",
|
||||
"onlyGroupLeaderCanManageSubscription": "Nur der Team-Leiter kann Team-Registrierungen verwalten",
|
||||
"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.",
|
||||
@@ -315,7 +316,7 @@
|
||||
"approvalsTitle": "Aufgaben-Zustimmung erwartet",
|
||||
"upgradeTitle": "Upgrade",
|
||||
"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",
|
||||
"refreshApprovals": "Zustimmungen aktualisieren",
|
||||
"refreshGroupTasks": "Team-Aufgaben aktualisieren",
|
||||
@@ -323,7 +324,6 @@
|
||||
"cantDeleteAssignedGroupTasks": "Du kannst Team-Aufgaben, die Dir zugewiesen wurden, nicht löschen.",
|
||||
"confirmGuildPlanCreation": "Dieses Team erstellen?",
|
||||
"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",
|
||||
"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.",
|
||||
@@ -366,9 +366,11 @@
|
||||
"recentActivity": "Kürzliche Aktivitäten",
|
||||
"myGuilds": "Meine Gilden",
|
||||
"guildsDiscovery": "Gilden entdecken",
|
||||
"role": "Role",
|
||||
"guildOrPartyLeader": "Leiter",
|
||||
"guildLeader": "Gildenleiter",
|
||||
"member": "Mitglied",
|
||||
"guildSize": "Guild Size",
|
||||
"goldTier": "Gold",
|
||||
"silverTier": "Silber",
|
||||
"bronzeTier": "Bronze",
|
||||
@@ -424,10 +426,10 @@
|
||||
"managerAdded": "Manager erfolgreich hinzugefügt",
|
||||
"managerRemoved": "Manager erfolgreich entfernt",
|
||||
"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?",
|
||||
"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.",
|
||||
"worldBossLink": "Read more about the previous World Bosses of Habitica on the Wiki.",
|
||||
"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": "Erfahre mehr über die vorigen Weltbosse von Habitica im Wiki.",
|
||||
"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!",
|
||||
"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?",
|
||||
"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",
|
||||
"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!",
|
||||
"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.",
|
||||
"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.",
|
||||
"inspireYourParty": "Inspire your party, gamify life together.",
|
||||
"letsMakeAccount": "First, let’s make you an account",
|
||||
"nameYourGroup": "Next, Name Your Group",
|
||||
"exampleGroupName": "Example: Avengers Academy",
|
||||
"letsMakeAccount": "Lass uns dir als erstes einen Account erstellen",
|
||||
"nameYourGroup": "Wähle als nächstes einen Namen für deine Gruppe",
|
||||
"exampleGroupName": "Beispiel: Avangers Academy",
|
||||
"exampleGroupDesc": "For those selected to join the training academy for The Avengers Superhero Initiative",
|
||||
"thisGroupInviteOnly": "This group is invitation only.",
|
||||
"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.",
|
||||
"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.",
|
||||
"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!",
|
||||
"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.",
|
||||
"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 Group’s member list.",
|
||||
"goToTaskBoard": "Go to Task Board"
|
||||
"goToTaskBoard": "Gehe zum Aufgabenbrett"
|
||||
}
|
||||
@@ -25,7 +25,7 @@
|
||||
"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!",
|
||||
"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.",
|
||||
"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!",
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
"featuredItems": "Besondere Empfehlungen!",
|
||||
"hideLocked": "Gesperrte verbergen",
|
||||
"hidePinned": "In der Pinnwand angezeigte verbergen",
|
||||
"hideMissing": "Hide Missing",
|
||||
"amountExperience": "<%= amount %> Erfahrung",
|
||||
"amountGold": "<%= amount %> Gold",
|
||||
"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!",
|
||||
"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!",
|
||||
"missingKeyParam": "\"req.params.key\" wird benötigt.",
|
||||
"itemNotFound": "Eintrag \"<%= key %>\" nicht gefunden.",
|
||||
"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.",
|
||||
"typeRequired": "Typ ist erforderlich",
|
||||
"positiveAmountRequired": "Positiver Betrag benötigt",
|
||||
"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",
|
||||
"plusGem": "+<%= count %> Gem",
|
||||
"plusGem": "+<%= count %> Edelstein",
|
||||
"typeNotSellable": "Typ ist nicht verkäuflich. Dieser muss einer der Folgenden sein: <%= acceptedTypes %>",
|
||||
"userItemsKeyNotFound": "Schlüssel für user.items <%= type %> nicht gefunden",
|
||||
"userItemsNotEnough": "Du hast nicht genug <%= type %>",
|
||||
|
||||
@@ -96,7 +96,6 @@
|
||||
"questInvitationDoesNotExist": "Es wurde noch keine Questeinladung verschickt.",
|
||||
"questInviteNotFound": "Keine Questeinladung gefunden.",
|
||||
"guildQuestsNotSupported": "Gilden können nicht zu Quests eingeladen werden.",
|
||||
"questNotFound": "Quest \"<%= key %>\" nicht gefunden.",
|
||||
"questNotOwned": "Du besitzt diese Quest-Schriftrolle nicht.",
|
||||
"questNotGoldPurchasable": "Quest \"<%= key %>\" ist nicht mit Gold käuflich.",
|
||||
"questLevelTooHigh": "Du musst Level <%= level %> haben, um diese Quest zu starten.",
|
||||
|
||||
@@ -599,6 +599,8 @@
|
||||
"questSquirrelNotes": "You wake up and find you’ve overslept! Why didn’t 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 didn’t know they’d 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. “She’s always been something of a resource guarder. We’ll 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, you’re able to coax the squirrel away from its hoard and back to the stables, which @Shtut has just finished de-acorning. They’ve set aside a few of the acorns on a worktable. “These ones are squirrel eggs! Maybe you can raise some that don’t play with their food quite so much.”",
|
||||
"questSquirrelBoss": "Sneaky Squirrel",
|
||||
"questSquirrelDropSquirrelEgg": "Squirrel (Egg)",
|
||||
"questSquirrelUnlockText": "Unlocks purchasable Squirrel eggs in the Market"
|
||||
"questSquirrelDropSquirrelEgg": "Eichörnchen (Ei)",
|
||||
"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."
|
||||
}
|
||||
@@ -32,7 +32,7 @@
|
||||
"resetAccPop": "Starte neu, dabei werden alle Level, Gold, Ausrüstung, Verlauf und Aufgaben entfernt.",
|
||||
"deleteAccount": "Konto löschen",
|
||||
"deleteAccPop": "Kündige und entferne Dein Habitica-Konto.",
|
||||
"feedback": "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",
|
||||
"dataExport": "Daten exportieren",
|
||||
"saveData": "Hier sind ein paar Möglichkeiten Deine Daten zu sichern.",
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
"spellWizardFireballText": "Flammenstoß",
|
||||
"spellWizardFireballNotes": "Du erhältst XP und fügst Bossen zusätzlichen Schaden zu! (Basiert auf: INT)",
|
||||
"spellWizardMPHealText": "Ätherischer Schwall",
|
||||
"spellWizardMPHealNotes": "You sacrifice Mana so the rest of your Party, except Mages, gains MP! (Based on: INT)",
|
||||
"spellWizardNoEthOnMage": "Your Skill backfires when mixed with another's magic. Only non-Mages gain MP.",
|
||||
"spellWizardMPHealNotes": "Du opferst Mana, demit der Rest deiner Gruppe, außer Magiern, MP erhält! (Basierend auf: INT)",
|
||||
"spellWizardNoEthOnMage": "Dein Zauberspruch geht nach hinten los, wenn er mit der Magie eines anderen gemischt wird. Nur nicht-Magier erhalten MP.",
|
||||
"spellWizardEarthText": "Erdbeben",
|
||||
"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",
|
||||
@@ -51,7 +51,6 @@
|
||||
"spellSpecialSeafoamNotes": "Verwandle einen Freund in ein Meereslebewesen!",
|
||||
"spellSpecialSandText": "Sand",
|
||||
"spellSpecialSandNotes": "Hebe den Spruch auf, der einen Seestern aus Dir gemacht hat.",
|
||||
"spellNotFound": "Fähigkeit \"<%= spellId %>\" nicht gefunden.",
|
||||
"partyNotFound": "Gruppe nicht gefunden",
|
||||
"targetIdUUID": "\"targetId\" muss eine gültige Benutzer-ID sein.",
|
||||
"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
Reference in New Issue
Block a user