Merge branch 'habitica/develop' into develop

This commit is contained in:
Weblate
2019-04-09 21:14:33 +02:00
329 changed files with 28779 additions and 27316 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
/* eslint-disable no-console */
import { sendTxn } from '../../../website/server/libs/email';
import { sendTxn } from '../../website/server/libs/email';
import { model as User } from '../../website/server/models/user';
import moment from 'moment';
import nconf from 'nconf';
+43 -76
View File
@@ -1,67 +1,24 @@
/* eslint-disable no-console */
const MIGRATION_NAME = 'full-stable';
import each from 'lodash/each';
import keys from 'lodash/keys';
import content from '../../website/common/script/content/index';
const migrationName = 'full-stable.js';
const authorName = 'Sabe'; // in case script author needs to know when their ...
const authorUuid = '7f14ed62-5408-4e1b-be83-ada62d504931'; // ... own data is done
import { model as User } from '../../website/server/models/user';
const progressCount = 1000;
let count = 0;
/*
* Award users every extant pet and mount
*/
const connectionString = 'mongodb://localhost:27017/habitrpg?auto_reconnect=true'; // FOR TEST DATABASE
let monk = require('monk');
let dbUsers = monk(connectionString).get('users', { castIds: false });
function processUsers (lastId) {
// specify a query to limit the affected users (empty for all users):
let query = {
'profile.name': 'SabreCat',
};
if (lastId) {
query._id = {
$gt: lastId,
};
}
dbUsers.find(query, {
sort: {_id: 1},
limit: 250,
fields: [
], // specify fields we are interested in to limit retrieved data (empty if we're not reading data):
})
.then(updateUsers)
.catch((err) => {
console.log(err);
return exiting(1, `ERROR! ${ err}`);
});
}
let progressCount = 1000;
let count = 0;
function updateUsers (users) {
if (!users || users.length === 0) {
console.warn('All appropriate users found and modified.');
displayData();
return;
}
let userPromises = users.map(updateUser);
let lastUser = users[users.length - 1];
return Promise.all(userPromises)
.then(() => {
processUsers(lastUser._id);
});
}
function updateUser (user) {
async function updateUser (user) {
count++;
let set = {
migration: migrationName,
};
const set = {};
set.migration = MIGRATION_NAME;
each(keys(content.pets), (pet) => {
set[`items.pets.${pet}`] = 5;
@@ -88,30 +45,40 @@ function updateUser (user) {
set[`items.mounts.${mount}`] = true;
});
dbUsers.update({_id: user._id}, {$set: set});
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
if (count % progressCount === 0) console.warn(`${count } ${ user._id}`);
if (user._id === authorUuid) console.warn(`${authorName } processed`);
return await User.update({_id: user._id}, {$set: set}).exec();
}
function displayData () {
console.warn(`\n${ count } users processed\n`);
return exiting(0);
}
module.exports = async function processUsers () {
let query = {
migration: {$ne: MIGRATION_NAME},
'auth.local.username': 'olson22',
};
function exiting (code, msg) {
code = code || 0; // 0 = success
if (code && !msg) {
msg = 'ERROR!';
}
if (msg) {
if (code) {
console.error(msg);
} else {
console.log(msg);
const fields = {
_id: 1,
};
while (true) { // eslint-disable-line no-constant-condition
const users = await User // eslint-disable-line no-await-in-loop
.find(query)
.limit(250)
.sort({_id: 1})
.select(fields)
.lean()
.exec();
if (users.length === 0) {
console.warn('All appropriate users found and modified.');
console.warn(`\n${count} users processed\n`);
break;
} else {
query._id = {
$gt: users[users.length - 1],
};
}
}
process.exit(code);
}
module.exports = processUsers;
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
}
};
+2 -2
View File
@@ -1,6 +1,6 @@
/* eslint-disable no-console */
const MIGRATION_NAME = 'mystery_items_201902';
const MYSTERY_ITEMS = ['eyewear_mystery_201902', 'shield_mystery_201902'];
const MIGRATION_NAME = 'mystery_items_201903';
const MYSTERY_ITEMS = ['armor_mystery_201903', 'head_mystery_201903'];
import { model as User } from '../../website/server/models/user';
import { model as UserNotification } from '../../website/server/models/userNotification';
+73
View File
@@ -0,0 +1,73 @@
/* eslint-disable no-console */
const MIGRATION_NAME = '20190314_pi_day';
import { v4 as uuid } from 'uuid';
import { model as User } from '../../website/server/models/user';
const progressCount = 1000;
let count = 0;
async function updateUser (user) {
count++;
const inc = {
'items.food.Pie_Skeleton': 1,
'items.food.Pie_Base': 1,
'items.food.Pie_CottonCandyBlue': 1,
'items.food.Pie_CottonCandyPink': 1,
'items.food.Pie_Shade': 1,
'items.food.Pie_White': 1,
'items.food.Pie_Golden': 1,
'items.food.Pie_Zombie': 1,
'items.food.Pie_Desert': 1,
'items.food.Pie_Red': 1,
};
const set = {};
set.migration = MIGRATION_NAME;
set['items.gear.owned.head_special_piDay'] = false;
set['items.gear.owned.shield_special_piDay'] = false;
const push = [
{type: 'marketGear', path: 'gear.flat.head_special_piDay', _id: uuid()},
{type: 'marketGear', path: 'gear.flat.shield_special_piDay', _id: uuid()},
];
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
return await User.update({_id: user._id}, {$inc: inc, $set: set, $push: {pinnedItems: {$each: push}}}).exec();
}
module.exports = async function processUsers () {
let query = {
migration: {$ne: MIGRATION_NAME},
'auth.timestamps.loggedin': {$gt: new Date('2019-02-15')},
};
const fields = {
_id: 1,
items: 1,
};
while (true) { // eslint-disable-line no-constant-condition
const users = await User // eslint-disable-line no-await-in-loop
.find(query)
.limit(250)
.sort({_id: 1})
.select(fields)
.lean()
.exec();
if (users.length === 0) {
console.warn('All appropriate users found and modified.');
console.warn(`\n${count} users processed\n`);
break;
} else {
query._id = {
$gt: users[users.length - 1],
};
}
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
}
};
+813 -1095
View File
File diff suppressed because it is too large Load Diff
+27 -27
View File
@@ -1,19 +1,19 @@
{
"name": "habitica",
"description": "A habit tracker app which treats your goals like a Role Playing Game.",
"version": "4.86.0",
"version": "4.91.1",
"main": "./website/server/index.js",
"dependencies": {
"@google-cloud/trace-agent": "^3.5.2",
"@google-cloud/trace-agent": "^3.6.0",
"@slack/client": "^3.8.1",
"accepts": "^1.3.5",
"amazon-payments": "^0.2.7",
"amplitude": "^3.5.0",
"amplitude-js": "^4.6.0-beta.2",
"amplitude-js": "^5.0.0",
"apidoc": "^0.17.5",
"apn": "^2.2.0",
"autoprefixer": "^8.5.0",
"aws-sdk": "^2.400.0",
"autoprefixer": "^9.4.0",
"aws-sdk": "^2.432.0",
"axios": "^0.18.0",
"axios-progress-bar": "^1.2.0",
"babel-core": "^6.26.3",
@@ -28,16 +28,16 @@
"babel-preset-es2015": "^6.6.0",
"babel-register": "^6.6.0",
"babel-runtime": "^6.11.6",
"bcrypt": "^3.0.1",
"bcrypt": "^3.0.5",
"body-parser": "^1.18.3",
"bootstrap": "^4.1.1",
"bootstrap-vue": "^2.0.0-rc.13",
"compression": "^1.7.2",
"cookie-session": "^1.2.0",
"bootstrap-vue": "^2.0.0-rc.16",
"compression": "^1.7.4",
"cookie-session": "^1.3.3",
"coupon-code": "^0.4.5",
"cross-env": "^5.2.0",
"css-loader": "^0.28.11",
"csv-stringify": "^4.3.1",
"csv-stringify": "^5.1.0",
"cwait": "^1.1.1",
"domain-middleware": "~0.1.0",
"express": "^4.16.3",
@@ -52,10 +52,10 @@
"gulp-nodemon": "^2.4.1",
"gulp.spritesmith": "^6.9.0",
"habitica-markdown": "^1.3.0",
"hellojs": "^1.15.1",
"hellojs": "^1.18.1",
"html-webpack-plugin": "^3.2.0",
"image-size": "^0.6.2",
"in-app-purchase": "^1.10.2",
"image-size": "^0.7.0",
"in-app-purchase": "^1.11.3",
"intro.js": "^2.9.3",
"jquery": ">=3.0.0",
"js2xmlparser": "^3.0.0",
@@ -64,13 +64,13 @@
"method-override": "^3.0.0",
"moment": "^2.22.1",
"moment-recur": "^1.0.7",
"mongoose": "^5.4.11",
"mongoose": "^5.4.19",
"morgan": "^1.7.0",
"nconf": "^0.10.0",
"node-gcm": "^1.0.2",
"node-sass": "^4.9.0",
"nodemailer": "^5.0.0",
"ora": "^3.0.0",
"nodemailer": "^6.0.0",
"ora": "^3.2.0",
"pageres": "^4.1.1",
"passport": "^0.4.0",
"passport-facebook": "^2.0.0",
@@ -85,12 +85,12 @@
"sass-loader": "^7.0.3",
"shelljs": "^0.8.2",
"short-uuid": "^3.0.0",
"smartbanner.js": "^1.9.1",
"smartbanner.js": "^1.11.0",
"stripe": "^5.9.0",
"superagent": "^4.0.0",
"superagent": "^5.0.2",
"svg-inline-loader": "^0.8.0",
"svg-url-loader": "^2.3.2",
"svgo": "^1.0.5",
"svgo": "^1.2.0",
"svgo-loader": "^2.1.0",
"universal-analytics": "^0.4.17",
"update": "^0.7.4",
@@ -100,13 +100,13 @@
"uuid": "^3.0.1",
"validator": "^10.5.0",
"vinyl-buffer": "^1.0.1",
"vue": "^2.6.4",
"vue": "^2.6.10",
"vue-loader": "^14.2.2",
"vue-mugen-scroll": "^0.2.1",
"vue-router": "^3.0.0",
"vue-style-loader": "^4.1.0",
"vue-template-compiler": "^2.6.4",
"vuedraggable": "^2.15.0",
"vue-template-compiler": "^2.6.10",
"vuedraggable": "^2.20.0",
"vuejs-datepicker": "git://github.com/habitrpg/vuejs-datepicker.git#5d237615463a84a23dd6f3f77c6ab577d68593ec",
"webpack": "^3.12.0",
"webpack-merge": "^4.1.3",
@@ -154,7 +154,7 @@
"chalk": "^2.4.1",
"chromedriver": "^2.40.0",
"connect-history-api-fallback": "^1.1.0",
"coveralls": "^3.0.1",
"coveralls": "^3.0.3",
"cross-spawn": "^6.0.5",
"eslint": "^4.19.1",
"eslint-config-habitrpg": "^4.0.0",
@@ -166,7 +166,7 @@
"expect.js": "^0.3.1",
"http-proxy-middleware": "^0.19.0",
"istanbul": "^1.1.0-alpha.1",
"karma": "^3.1.3",
"karma": "^4.0.1",
"karma-babel-preprocessor": "^7.0.0",
"karma-chai-plugins": "^0.9.0",
"karma-chrome-launcher": "^2.2.0",
@@ -181,11 +181,11 @@
"lcov-result-merger": "^3.0.0",
"mocha": "^5.1.1",
"monk": "^6.0.6",
"nightwatch": "^0.9.21",
"puppeteer": "^1.5.0",
"nightwatch": "^1.0.16",
"puppeteer": "^1.14.0",
"require-again": "^2.0.0",
"selenium-server": "^3.12.0",
"sinon": "^6.3.5",
"sinon": "^7.2.4",
"sinon-chai": "^3.0.0",
"sinon-stub-promise": "^4.0.0",
"webpack-bundle-analyzer": "^2.12.0",
+1 -1
View File
@@ -53,7 +53,7 @@ async function _deleteHabiticaData (user, email) {
if (response) {
console.log(`${response.status} ${response.statusText}`);
if (response.status === 200) console.log(`${user._id} removed. Last login: ${user.auth.timestamps.loggedin}`);
if (response.status === 200) console.log(`${user._id} (${email}) removed. Last login: ${user.auth.timestamps.loggedin}`);
}
}
+3 -4
View File
@@ -335,14 +335,13 @@ describe('analyticsService', () => {
let data, itemSpy;
beforeEach(() => {
Visitor.prototype.event.yields();
itemSpy = sandbox.stub().returnsThis();
Visitor.prototype.event.returns({
send: sandbox.stub(),
});
Visitor.prototype.transaction.returns({
item: itemSpy,
send: sandbox.stub().returnsThis(),
send: sandbox.stub().yields(),
});
data = {
+67
View File
@@ -0,0 +1,67 @@
/* eslint-disable camelcase */
import {
validateItemPath,
getDefaultOwnedGear,
} from '../../../../../website/server/libs/items/utils';
describe('Items Utils', () => {
describe('getDefaultOwnedGear', () => {
it('clones the result object', () => {
const res1 = getDefaultOwnedGear();
res1.extraProperty = true;
const res2 = getDefaultOwnedGear();
expect(res2).not.to.have.property('extraProperty');
});
});
describe('validateItemPath', () => {
it('returns false if not an item path', () => {
expect(validateItemPath('notitems.gear.owned.item')).to.equal(false);
});
it('returns true if a valid schema path', () => {
expect(validateItemPath('items.gear.equipped.weapon')).to.equal(true);
expect(validateItemPath('items.currentPet')).to.equal(true);
expect(validateItemPath('items.special.snowball')).to.equal(true);
});
it('works with owned gear paths', () => {
expect(validateItemPath('items.gear.owned.head_armoire_crownOfHearts')).to.equal(true);
expect(validateItemPath('items.gear.owned.head_invalid')).to.equal(false);
});
it('works with pets paths', () => {
expect(validateItemPath('items.pets.Wolf-CottonCandyPink')).to.equal(true);
expect(validateItemPath('items.pets.Wolf-Invalid')).to.equal(false);
});
it('works with eggs paths', () => {
expect(validateItemPath('items.eggs.LionCub')).to.equal(true);
expect(validateItemPath('items.eggs.Armadillo')).to.equal(true);
expect(validateItemPath('items.eggs.NotAnArmadillo')).to.equal(false);
});
it('works with hatching potions paths', () => {
expect(validateItemPath('items.hatchingPotions.Base')).to.equal(true);
expect(validateItemPath('items.hatchingPotions.StarryNight')).to.equal(true);
expect(validateItemPath('items.hatchingPotions.Invalid')).to.equal(false);
});
it('works with food paths', () => {
expect(validateItemPath('items.food.Cake_Base')).to.equal(true);
expect(validateItemPath('items.food.Cake_Invalid')).to.equal(false);
});
it('works with mounts paths', () => {
expect(validateItemPath('items.mounts.Cactus-Base')).to.equal(true);
expect(validateItemPath('items.mounts.Aether-Invisible')).to.equal(true);
expect(validateItemPath('items.mounts.Aether-Invalid')).to.equal(false);
});
it('works with quests paths', () => {
expect(validateItemPath('items.quests.atom3')).to.equal(true);
expect(validateItemPath('items.quests.invalid')).to.equal(false);
});
});
});
@@ -67,4 +67,10 @@ describe('GET /heroes/:heroId', () => {
expect(heroRes.auth.local).not.to.have.keys(['salt', 'hashed_password']);
expect(heroRes.profile).to.have.all.keys(['name']);
});
it('returns correct hero using search with difference case', async () => {
await generateUser({}, { username: 'TestUpperCaseName123' });
let heroRes = await user.get('/hall/heroes/TestuPPerCasEName123');
expect(heroRes.auth.local.username).to.equal('TestUpperCaseName123');
});
});
@@ -27,8 +27,6 @@ describe('GET /inbox/messages', () => {
toUserId: user.id,
message: 'fourth',
});
await user.sync();
});
it('returns the user inbox messages as an array of ordered messages (from most to least recent)', async () => {
@@ -45,4 +43,21 @@ describe('GET /inbox/messages', () => {
expect(messages[2].text).to.equal('second');
expect(messages[3].text).to.equal('first');
});
it('returns four messages when using page-query ', async () => {
const promises = [];
for (let i = 0; i < 10; i++) {
promises.push(user.post('/members/send-private-message', {
toUserId: user.id,
message: 'fourth',
}));
}
await Promise.all(promises);
const messages = await user.get('/inbox/messages?page=1');
expect(messages.length).to.equal(4);
});
});
@@ -110,4 +110,22 @@ describe('POST /user/auth/local/login', () => {
let isValidPassword = await bcryptCompare(textPassword, user.auth.local.hashed_password);
expect(isValidPassword).to.equal(true);
});
it('user uses social authentication and has no password', async () => {
await user.unset({
'auth.local.hashed_password': 1,
});
await user.sync();
expect(user.auth.local.hashed_password).to.be.undefined;
await expect(api.post(endpoint, {
username: user.auth.local.username,
password: 'any-password',
})).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('invalidLoginCredentialsLong'),
});
});
});
+12
View File
@@ -62,6 +62,18 @@ describe('inAppRewards', () => {
expect(result[9].path).to.eql('potion');
});
it('ignores null/undefined entries', () => {
user.pinnedItems = testPinnedItems;
user.pinnedItems.push(null);
user.pinnedItems.push(undefined);
user.pinnedItemsOrder = testPinnedItemsOrder;
let result = inAppRewards(user);
expect(result[2].path).to.eql('armoire');
expect(result[9].path).to.eql('potion');
});
it('does not return seasonal items which have been unpinned', () => {
if (officialPinnedItems.length === 0) {
return; // if no seasonal items, this test is not applicable
+5 -1
View File
@@ -9,6 +9,7 @@ import {
import i18n from '../../../../website/common/script/i18n';
import content from '../../../../website/common/script/content/index';
import errorMessage from '../../../../website/common/script/libs/errorMessage';
import { defaultsDeep } from 'lodash';
describe('shared.ops.buy', () => {
let user;
@@ -16,6 +17,10 @@ describe('shared.ops.buy', () => {
beforeEach(() => {
user = generateUser({
stats: { gp: 200 },
});
defaultsDeep(user, {
items: {
gear: {
owned: {
@@ -26,7 +31,6 @@ describe('shared.ops.buy', () => {
},
},
},
stats: { gp: 200 },
});
sinon.stub(analytics, 'track');
+5 -1
View File
@@ -11,6 +11,7 @@ import {
} from '../../../../website/common/script/libs/errors';
import i18n from '../../../../website/common/script/i18n';
import errorMessage from '../../../../website/common/script/libs/errorMessage';
import { defaultsDeep } from 'lodash';
function buyGear (user, req, analytics) {
let buyOp = new BuyMarketGearOperation(user, req, analytics);
@@ -24,6 +25,10 @@ describe('shared.ops.buyMarketGear', () => {
beforeEach(() => {
user = generateUser({
stats: { gp: 200 },
});
defaultsDeep(user, {
items: {
gear: {
owned: {
@@ -34,7 +39,6 @@ describe('shared.ops.buyMarketGear', () => {
},
},
},
stats: { gp: 200 },
});
sinon.stub(shared, 'randomVal');
+18
View File
@@ -0,0 +1,18 @@
import {
generateUser,
} from '../../helpers/common.helper';
import {addPinnedGear} from '../../../website/common/script/ops/pinnedGearUtils';
describe('shared.ops.pinnedGearUtils.addPinnedGear', () => {
let user;
beforeEach(() => {
user = generateUser();
});
it('not adds an item with empty properties to pinnedItems', () => {
addPinnedGear(user, undefined, undefined);
expect(user.pinnedItems.length).to.be.eql(0);
});
});
@@ -4,6 +4,7 @@ import { requester } from './requester';
import {
getDocument as getDocumentFromMongo,
updateDocument as updateDocumentInMongo,
unsetDocument as unsetDocumentInMongo,
} from '../mongo';
import {
assign,
@@ -29,6 +30,18 @@ class ApiObject {
return this;
}
async unset (options) {
if (isEmpty(options)) {
return;
}
await unsetDocumentInMongo(this._docType, this, options);
_updateLocalParameters((this, options));
return this;
}
async sync () {
let updatedDoc = await getDocumentFromMongo(this._docType, this);
@@ -13,10 +13,16 @@ import * as Tasks from '../../../../website/server/models/task';
// parameter, such as the number of wolf eggs the user has,
// , you can do so by passing in the full path as a string:
// { 'items.eggs.Wolf': 10 }
export async function generateUser (update = {}) {
let username = (Date.now() + generateUUID()).substring(0, 20);
let password = 'password';
let email = `${username}@example.com`;
//
// To manually set a username, email or password pass it in as
// an object for the second parameter. Only overrides need to be
// added. Items that don't exist will be autogenerated.
// Example: generateUser({}, { username: 'TestName' }) adds user
// with the 'TestName' username.
export async function generateUser (update = {}, overrides = {}) {
let username = overrides.username || (Date.now() + generateUUID()).substring(0, 20);
let password = overrides.password || 'password';
let email = overrides.email || `${username}@example.com`;
let user = await requester().post('/user/auth/local/register', {
username,
+1
View File
@@ -9,6 +9,7 @@ import {
} from '../../website/server/models/task';
export {translate} from './translate';
export function generateUser (options = {}) {
let user = new User(options).toObject();
+13
View File
@@ -98,6 +98,19 @@ export async function updateDocument (collectionName, doc, update) {
});
}
// Unset a property in the database.
// Useful for testing.
export async function unsetDocument (collectionName, doc, update) {
let collection = mongoose.connection.db.collection(collectionName);
return new Promise((resolve) => {
collection.updateOne({ _id: doc._id }, { $unset: update }, (updateErr) => {
if (updateErr) throw new Error(`Error updating ${collectionName}: ${updateErr}`);
resolve();
});
});
}
export async function getDocument (collectionName, doc) {
let collection = mongoose.connection.db.collection(collectionName);
@@ -1,42 +1,60 @@
.promo_armoire_backgrounds_201903 {
.promo_april_fools_2019 {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: 0px -220px;
background-position: -445px -163px;
width: 423px;
height: 147px;
}
.promo_mystery_201902 {
.promo_armoire_backgrounds_201904 {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -424px -220px;
width: 240px;
background-position: 0px -337px;
width: 423px;
height: 147px;
}
.promo_mythical_marvels_bundle {
.promo_celestial_rainbow_potions {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: 0px -368px;
background-position: -424px -337px;
width: 423px;
height: 147px;
}
.promo_classes_spring2019 {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -445px 0px;
width: 432px;
height: 162px;
}
.promo_egg_hunt {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: 0px -485px;
width: 354px;
height: 147px;
}
.promo_mystery_201903 {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -355px -485px;
width: 351px;
height: 147px;
}
.promo_seasonalshop_spring {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -707px -485px;
width: 162px;
height: 138px;
}
.promo_shiny_seeds {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: 0px -633px;
width: 351px;
height: 147px;
}
.promo_take_this {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -424px -368px;
background-position: -352px -633px;
width: 96px;
height: 69px;
}
.promo_valentines_potions {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: 0px -516px;
width: 420px;
height: 147px;
}
.scene_achievement {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -397px 0px;
width: 339px;
height: 210px;
}
.scene_cooking {
.scene_hat_guild {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: 0px 0px;
width: 396px;
height: 219px;
width: 444px;
height: 336px;
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 915 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 557 KiB

After

Width:  |  Height:  |  Size: 556 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 562 KiB

After

Width:  |  Height:  |  Size: 570 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 KiB

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 354 KiB

After

Width:  |  Height:  |  Size: 344 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 307 KiB

After

Width:  |  Height:  |  Size: 322 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 159 KiB

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 143 KiB

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 KiB

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 KiB

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 144 KiB

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 149 KiB

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 153 KiB

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 KiB

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 183 KiB

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 159 KiB

After

Width:  |  Height:  |  Size: 179 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 165 KiB

After

Width:  |  Height:  |  Size: 161 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 123 KiB

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 123 KiB

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 144 KiB

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 115 KiB

After

Width:  |  Height:  |  Size: 116 KiB

@@ -0,0 +1,26 @@
.vdp-datepicker .vdp-datepicker__calendar {
.cell:not(.blank):not(.disabled).day:hover {
border-radius: 2px;
border: 1px solid $purple-400;
}
.cell.selected,
.cell.selected.highlighted,
.cell.selected:hover {
color: $white;
background: $purple-300;
}
.cell.highlighted {
background: rgba($purple-400, 0.24);
color: $purple-200;
}
.cell.highlighted,
.cell.selected {
border-radius: 2px;
font-weight: bold;
}
}
+1 -1
View File
@@ -159,7 +159,7 @@ $bg-disabled-control: #34303a;
width: 18px;
height: 18px;
background-image: url(~client/assets/svg/for-css/checkbox-white.svg);
background-size: 75% 75%;
background-size: 13px 10px;
}
&:active~.custom-control-label::before {
+2
View File
@@ -36,3 +36,5 @@
@import './animals';
@import './iconalert';
@import './tiers';
@import './payments';
@import './datepicker.scss';
+44
View File
@@ -0,0 +1,44 @@
.payments-column {
display: flex;
flex-direction: column;
width: 296px;
justify-content: center;
&.payments-disabled {
opacity: 0.64;
.btn, .btn:hover, .btn:active {
box-shadow: none;
}
.payment-item > *{
cursor: default !important;
}
}
.payment-item {
margin-bottom: 12px;
display: flex;
&.payment-button {
display: flex;
justify-content: center;
align-items: center;
.credit-card-icon {
width: 21.3px;
height: 16px;
margin-right: 8.7px;
}
&.paypal-checkout {
background: #009cde;
img {
width: 157px;
height: 21px;
}
}
}
}
}
+5 -5
View File
@@ -2,8 +2,8 @@
// possible values are: normal, fall, habitoween, thanksgiving, winter, nye, birthday, valentines, spring, summer
// more to be added on future seasons
$npc_market_flavor: 'normal';
$npc_quests_flavor: 'normal';
$npc_seasonal_flavor: 'normal';
$npc_timetravelers_flavor: 'normal';
$npc_tavern_flavor: 'normal';
$npc_market_flavor: 'spring';
$npc_quests_flavor: 'spring';
$npc_seasonal_flavor: 'spring';
$npc_timetravelers_flavor: 'spring';
$npc_tavern_flavor: 'spring';
@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="16" viewBox="0 0 22 16">
<path fill="#FFF" fill-rule="nonzero" d="M0 13.872V5.333h21.333v8.539c0 1.176-.747 2.128-1.67 2.128H1.67C.747 16 0 15.047 0 13.872zM19.664 0c.922 0 1.67.918 1.67 2.053v.614H0v-.614C0 .918.747 0 1.67 0h17.994z"/>
</svg>

After

Width:  |  Height:  |  Size: 307 B

@@ -1,3 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill="#E1E0E3" fill-rule="evenodd" d="M10.667 10.667L16 8l-5.333-2.667L8 0 5.333 5.333 0 8l5.333 2.667L8 16z"/>
<path class="star-empty" fill="#E1E0E3" fill-rule="evenodd" d="M10.667 10.667L16 8l-5.333-2.667L8 0 5.333 5.333 0 8l5.333 2.667L8 16z"/>
</svg>

Before

Width:  |  Height:  |  Size: 213 B

After

Width:  |  Height:  |  Size: 232 B

@@ -1,6 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd">
<path fill="#E1E0E3" d="M10.667 10.667L16 8l-5.333-2.667L8 0 5.333 5.333 0 8l5.333 2.667L8 16z"/>
<path fill="#FFB445" d="M8 0L5.333 5.333 0 8l5.333 2.667L8 16z"/>
<path class="star-empty" fill="#E1E0E3" d="M10.667 10.667L16 8l-5.333-2.667L8 0 5.333 5.333 0 8l5.333 2.667L8 16z"/>
<path class="star" fill="#FFB445" d="M8 0L5.333 5.333 0 8l5.333 2.667L8 16z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 320 B

After

Width:  |  Height:  |  Size: 352 B

@@ -1,3 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill="#FFB445" fill-rule="evenodd" d="M10.667 10.667L16 8l-5.333-2.667L8 0 5.333 5.333 0 8l5.333 2.667L8 16z"/>
<path class="star" fill="#FFB445" fill-rule="evenodd" d="M10.667 10.667L16 8l-5.333-2.667L8 0 5.333 5.333 0 8l5.333 2.667L8 16z"/>
</svg>

Before

Width:  |  Height:  |  Size: 213 B

After

Width:  |  Height:  |  Size: 226 B

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