Compare commits

...

56 Commits

Author SHA1 Message Date
Phillip Thelen 192d649ffa fix giving gear to contributors 2025-01-23 17:30:31 +01:00
Phillip Thelen e7aae55eca Give contributors gear immediately 2025-01-21 11:10:29 +01:00
Phillip Thelen 36b03613e1 adjust contributor tests 2025-01-21 11:10:16 +01:00
Phillip Thelen 2de9a16a2c adjust gems per tier 2025-01-21 11:02:19 +01:00
negue 895241b7fa show date tooltip above system / skill messages 2025-01-20 21:08:55 +01:00
negue 2535fd7095 Combined Message Pages/Redesign (#15310)
* split component prepare new views / states

* extract empty and disabled state as components

* fix empty state mail icon

* first logic switching between modes, move page to /private-messages/index.vue

* extract autoCompleteHelper.js

* style header + start new message input

* style plus button + focus input

* state logic, types for sanity

* WIP PM new Message started

* add /members/username test

* first design changes to messageCard

* delete private message or chat - based on the mode

* copy as todo

* mention links to modal

* report chat or private message

* WIP likeButton

* likeButton styling

* hide like on private message cards

* fix unit test

* replace copy as todo - to just a copy to clipboard

* style changes

* menu position + like button width

* dropdown items background + like font

* fix like button padding

* move api endpoints and tests around to group inbox methods  + like for inbox private messages

* restyle system messages

* Dropdown Radius and Padding

* WIP system messages

* fix lint

* copy delta commit of allowing liking own private messages

* enable liking private messages

* fix menu non hovered item icon color

* fix import path

* ignore background on system messages

* requested changes + migration

* update migration to update the unique id to some messages and delete the duplicates

* migration based on users pagination

* fix(migration): use Promise.all

* change to bulkWrites per User, and all messages in one run (of a user)

* check for array

* use rest operator ...

* skip sorting to get the users

* remove migration, disable like for private messages without uniqueMessageId

* lean+bulkWrite for likes, add time checks for like and auth for further debugging

* add a limit 2 get the messages by uniqueId

* Adding a simple server start script

* remove pinned nodemon dep

* fix inbox controller/tests

* fix / requested style changes

* fix empty state padding /

* hide avatar weapons on messages - fix avatar spacing on messages

* Hourglass Simplification (#15323)

* begin removing obsolete tests

* begin refactoring

* update cron tests

* cleanup

* finish basic implementation of new logic

* add more subscription tests

* subscription test improvements

* return nextHourglassDate again

* fix gem limit

* fix(test): short circuit this.

* fix(admin): correct logic and style for shrimple subs

* WIP(frontend): draft of main subs page view

* fix hourglass count

* Fix hourglass logic for upgrades

* fix admin panel display

* WIP(subs): extant Stripe state

* fix admin panel strings

* fix missing transaction type

* add new field for cumulative subscription count

* show date for hourglass bonus if it was received

* fix test

* feat(subscription): max Gems progress readout

* fix(css): correct and refactor heights and selection states

* fix(subs): correct border-radius and redirect

* fix(stripe): correct redirect after success

* Admin panel display fixes

* don’t give additional HG for new sub if they already got one this month

* fix issue with promo hourglasses

* fix(subscription): update layout when gifting

* fix(subscriptions): more gift layout revisions

* fix(subscriptions): minor visual updates

* fix(subs): pass autoRenews through Stripe

* fix(subs): gifts DON't renew

* fix(lint): unnecessary ternary

* fix(lint): do negate object ig

* fix(subs): try again on gifts

* fix(subs): unhovery and un-12-monthy

* fix bug with incorrectly giving HG bonus

* remove only

* fix test

* fix test

* fix(subs): also redirect to subs after gift sub

* fix(subs): fix typeError

* fix(g1g1): don't try to find Gems promo during bogo

---------

Co-authored-by: Phillip Thelen <phillip@habitica.com>
Co-authored-by: Kalista Payne <sabe@habitica.com>

* chore(sprites): update subproject

* fix(layout): tighten cancellation note

* fix(subs): Google wording and HG escape

* chore(testing): fake g1g1 dates

* fix(subs): don't hide HG preview entirely

* fix(subs): center next hourglass message

* working validatedTextInput.vue within start-new-conversation-input-header.vue 🎉

* fix(git): remove changes from old develop

* Revert "fix(git): remove changes from old develop"

This reverts commit 0e30f7df00.

* fix(git): no actually just this file i guesss

* adding an empty loading state, hiding

* fought the avatar arch nemesis again

* fix chatMessages (party chat) message spacing

* move disabled text back to above the input area - re-enable input area

* show disabled private messages top panel

* fix font color

* fixing uiStates - removing disabled - moving the own user check to the last

* fix(lint): add missing prop defaults

* fix(lint): object default should be fn

* fix(chat): correct grammar in error

---------

Co-authored-by: SabreCat <sabe@habitica.com>
Co-authored-by: Kalista Payne <sabrecat@gmail.com>
Co-authored-by: Phillip Thelen <phillip@habitica.com>
2025-01-16 16:52:24 -06:00
Kalista Payne 30f1820a49 5.32.5 2025-01-09 09:02:14 -06:00
Weblate 3bb6c391af Translated using Weblate (German)
Currently translated at 98.0% (3190 of 3255 strings)

Translated using Weblate (German)

Currently translated at 97.8% (3185 of 3255 strings)

Translated using Weblate (German)

Currently translated at 97.7% (3181 of 3255 strings)

Translated using Weblate (German)

Currently translated at 100.0% (261 of 261 strings)

Translated using Weblate (German)

Currently translated at 97.5% (3176 of 3255 strings)

Co-authored-by: Katharina <katharinaanna.wilding@gmail.com>
Co-authored-by: Toro Mor <thomas.bizer@gmx.de>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.habitica.com/projects/habitica/gear/de/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/de/
Translation: Habitica/Gear
Translation: Habitica/Subscriber
2025-01-09 14:46:54 +01:00
Kalista Payne a0383c785a Squashed commit of the following:
commit 5d3713008dc3041f63b23b22196e1ed79fab45bd
Author: Kalista Payne <sabrecat@gmail.com>
Date:   Wed Jan 8 14:39:27 2025 -0600

    fix(text): pet Pet

commit 3ff5d7afeb517ae3d0933d8e18045b24575bb90b
Author: Kalista Payne <sabrecat@gmail.com>
Date:   Wed Jan 8 14:34:02 2025 -0600

    fix(links): remove unnecessary style and icon

commit 5023dd9258aa0f9416daa212ed1249db2e5d5fe4
Author: Kalista Payne <sabrecat@gmail.com>
Date:   Wed Jan 8 09:43:17 2025 -0600

    fix(links): update task modal markdown help

commit 81ebb279cd881d1c560668c3cb03600d85b9f5b9
Author: Kalista Payne <sabrecat@gmail.com>
Date:   Wed Jan 8 09:26:11 2025 -0600

    fix(misc): clean up some layout and one more link

commit 2fd216f01531052aa769738f8fe1956ca6943822
Author: Kalista Payne <sabrecat@gmail.com>
Date:   Tue Jan 7 16:09:28 2025 -0600

    fix(links): remove/revise some outdated wiki links
2025-01-08 15:18:06 -06:00
Kalista Payne 99790c05f4 5.32.4 2025-01-06 16:22:26 -06:00
Weblate fc5fec9bfe Merge branch 'origin/develop' into Weblate. 2025-01-06 23:18:24 +01:00
Phillip Thelen 9db5d4116d Fix availability of december background (#15378) 2025-01-06 15:57:57 -06:00
Weblate 6676e94ef6 Translated using Weblate (Spanish (Latin America))
Currently translated at 100.0% (140 of 140 strings)

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (140 of 140 strings)

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (140 of 140 strings)

Translated using Weblate (Spanish (Latin America))

Currently translated at 95.7% (134 of 140 strings)

Translated using Weblate (Spanish (Latin America))

Currently translated at 100.0% (8 of 8 strings)

Translated using Weblate (Italian)

Currently translated at 9.4% (23 of 243 strings)

Translated using Weblate (Italian)

Currently translated at 99.3% (887 of 893 strings)

Translated using Weblate (Italian)

Currently translated at 99.3% (887 of 893 strings)

Translated using Weblate (Russian)

Currently translated at 91.4% (2978 of 3255 strings)

Translated using Weblate (Portuguese)

Currently translated at 97.2% (177 of 182 strings)

Translated using Weblate (French)

Currently translated at 100.0% (261 of 261 strings)

Translated using Weblate (French)

Currently translated at 99.2% (259 of 261 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (261 of 261 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (134 of 134 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (3255 of 3255 strings)

Co-authored-by: Chase7-Diaphragm0-Jeeringly7-Smartly2-Drainer5 <linguists-commonwealth@silkylegs.aleeas.com>
Co-authored-by: Gabrielle Renoir <cococherierenoir@gmail.com>
Co-authored-by: Jaime Martí <jaumemarti77@icloud.com>
Co-authored-by: Kesabirria <kebsebastian@gmail.com>
Co-authored-by: Oscar Rodríguez Díaz <alexoscarcrd@gmail.com>
Co-authored-by: Raquel Pantojo de Souza Bachour <raquel.pantojo@gmail.com>
Co-authored-by: Sophie LE MASLE <sophiesuff@gmail.com>
Co-authored-by: Val <3qes0hnzh@mozmail.com>
Co-authored-by: Vitaliia Reinberg <vitalia.reynberg@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/it/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/it/
Translate-URL: https://translate.habitica.com/projects/habitica/front/pt/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/es/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/es/
Translate-URL: https://translate.habitica.com/projects/habitica/overview/es_419/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/es/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/es_419/
Translation: Habitica/Backgrounds
Translation: Habitica/Faq
Translation: Habitica/Front
Translation: Habitica/Gear
Translation: Habitica/Npc
Translation: Habitica/Overview
Translation: Habitica/Subscriber
Translation: Habitica/Tasks
2025-01-06 22:52:42 +01:00
Kalista Payne 723adceb25 chore(migrations): cute default and updateOne 2025-01-06 15:43:07 -06:00
Kalista Payne 440d06da4a 5.32.3 2025-01-03 12:51:57 -06:00
Weblate 0ea84668a8 Merge branch 'origin/develop' into Weblate. 2025-01-03 19:49:25 +01:00
Kalista Payne 5893d8b9bb fix(subs): revise benefit strings for clarity 2025-01-03 12:22:51 -06:00
Weblate 2c799b9c07 Translated using Weblate (Spanish)
Currently translated at 100.0% (3255 of 3255 strings)

Translated using Weblate (German)

Currently translated at 97.1% (3161 of 3255 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (893 of 893 strings)

Co-authored-by: Anna Tunger <anna.tunger@icloud.com>
Co-authored-by: Diego Alejandro Rios Vasquez <diegovasquezcolombia@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/es/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/de/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/es/
Translation: Habitica/Backgrounds
Translation: Habitica/Gear
2025-01-03 04:41:47 +01:00
Kalista Payne 1550d9b4ee 5.32.2 2025-01-02 11:22:51 -06:00
Weblate ade812b86d Merge branch 'origin/develop' into Weblate. 2025-01-02 18:19:49 +01:00
Phillip Thelen 62e6fbef61 Fix content end date if already in new year (#15376)
* Fix content end date if already in new year

* fix test
2025-01-02 11:15:04 -06:00
Weblate 67a0f8b65a Translated using Weblate (Korean)
Currently translated at 70.4% (629 of 893 strings)

Translated using Weblate (Korean)

Currently translated at 91.6% (153 of 167 strings)

Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: widesky8 <widesky20@naver.com>
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/ko/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/ko/
Translation: Habitica/Achievements
Translation: Habitica/Backgrounds
2025-01-01 03:17:52 +01:00
Kalista Payne aa432022d3 fix(script): replace deprecated update function 2024-12-30 14:58:52 -06:00
Kalista Payne 86fb3c1fd1 5.32.1 2024-12-30 09:23:08 -06:00
Weblate ff2b4add8b Translated using Weblate (German)
Currently translated at 96.1% (3130 of 3255 strings)

Translated using Weblate (Slovak)

Currently translated at 100.0% (60 of 60 strings)

Translated using Weblate (Korean)

Currently translated at 96.4% (110 of 114 strings)

Translated using Weblate (Korean)

Currently translated at 49.4% (90 of 182 strings)

Translated using Weblate (Korean)

Currently translated at 91.0% (152 of 167 strings)

Translated using Weblate (Korean)

Currently translated at 54.8% (1784 of 3255 strings)

Translated using Weblate (Korean)

Currently translated at 65.3% (170 of 260 strings)

Translated using Weblate (Chinese (Traditional))

Currently translated at 100.0% (13 of 13 strings)

Translated using Weblate (Chinese (Traditional))

Currently translated at 100.0% (8 of 8 strings)

Translated using Weblate (Chinese (Traditional))

Currently translated at 100.0% (47 of 47 strings)

Translated using Weblate (Chinese (Traditional))

Currently translated at 100.0% (167 of 167 strings)

Translated using Weblate (German)

Currently translated at 95.8% (3119 of 3255 strings)

Translated using Weblate (Slovak)

Currently translated at 100.0% (114 of 114 strings)

Translated using Weblate (Slovak)

Currently translated at 100.0% (240 of 240 strings)

Translated using Weblate (Slovak)

Currently translated at 71.0% (577 of 812 strings)

Translated using Weblate (Slovak)

Currently translated at 100.0% (394 of 394 strings)

Translated using Weblate (Chinese (Traditional))

Currently translated at 100.0% (140 of 140 strings)

Translated using Weblate (Chinese (Traditional))

Currently translated at 79.3% (207 of 261 strings)

Translated using Weblate (Chinese (Traditional))

Currently translated at 100.0% (94 of 94 strings)

Translated using Weblate (Chinese (Traditional))

Currently translated at 92.1% (398 of 432 strings)

Translated using Weblate (Chinese (Traditional))

Currently translated at 4.9% (12 of 243 strings)

Translated using Weblate (Chinese (Traditional))

Currently translated at 94.3% (182 of 193 strings)

Translated using Weblate (Chinese (Traditional))

Currently translated at 95.4% (105 of 110 strings)

Translated using Weblate (Chinese (Traditional))

Currently translated at 86.5% (773 of 893 strings)

Translated using Weblate (Russian)

Currently translated at 36.6% (89 of 243 strings)

Translated using Weblate (Russian)

Currently translated at 36.6% (89 of 243 strings)

Translated using Weblate (German)

Currently translated at 95.6% (3115 of 3255 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 77.7% (189 of 243 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (893 of 893 strings)

Translated using Weblate (German)

Currently translated at 100.0% (134 of 134 strings)

Translated using Weblate (German)

Currently translated at 95.1% (3096 of 3255 strings)

Translated using Weblate (French)

Currently translated at 100.0% (261 of 261 strings)

Translated using Weblate (German)

Currently translated at 100.0% (261 of 261 strings)

Translated using Weblate (French)

Currently translated at 100.0% (134 of 134 strings)

Translated using Weblate (German)

Currently translated at 100.0% (134 of 134 strings)

Translated using Weblate (French)

Currently translated at 100.0% (3255 of 3255 strings)

Translated using Weblate (German)

Currently translated at 93.8% (3056 of 3255 strings)

Translated using Weblate (French)

Currently translated at 100.0% (893 of 893 strings)

Translated using Weblate (German)

Currently translated at 100.0% (893 of 893 strings)

Co-authored-by: Boni hahaha <chanrouber@gmail.com>
Co-authored-by: Filip Betko <filipbetko@gmail.com>
Co-authored-by: Hikari <sss840127@gmail.com>
Co-authored-by: Irina  Shcherbinina <cat3dcat007@gmail.com>
Co-authored-by: Katharina <katharinaanna.wilding@gmail.com>
Co-authored-by: Lancelot Liu <me@lancy.dev>
Co-authored-by: Sophie LE MASLE <sophiesuff@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: Wyatt <1697570085@qq.com>
Co-authored-by: razil <boss.razmarin@gmail.com>
Co-authored-by: 리슈레이 <rishyurei@gmail.com>
Co-authored-by: 횬 <gkfpxldk0424@gmail.com>
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/ko/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/zh_Hant/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/de/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/zh_Hant/
Translate-URL: https://translate.habitica.com/projects/habitica/challenge/zh_Hant/
Translate-URL: https://translate.habitica.com/projects/habitica/character/zh_Hant/
Translate-URL: https://translate.habitica.com/projects/habitica/content/sk/
Translate-URL: https://translate.habitica.com/projects/habitica/contrib/zh_Hant/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/zh_Hant/
Translate-URL: https://translate.habitica.com/projects/habitica/front/ko/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/de/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/ko/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/sk/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/zh_Hant/
Translate-URL: https://translate.habitica.com/projects/habitica/messages/sk/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/de/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/overview/zh_Hant/
Translate-URL: https://translate.habitica.com/projects/habitica/pets/ko/
Translate-URL: https://translate.habitica.com/projects/habitica/pets/sk/
Translate-URL: https://translate.habitica.com/projects/habitica/quests/zh_Hant/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/sk/
Translate-URL: https://translate.habitica.com/projects/habitica/rebirth/zh_Hant/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/ko/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/de/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/zh_Hant/
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/zh_Hant/
Translation: Habitica/Achievements
Translation: Habitica/Backgrounds
Translation: Habitica/Challenge
Translation: Habitica/Character
Translation: Habitica/Content
Translation: Habitica/Contrib
Translation: Habitica/Faq
Translation: Habitica/Front
Translation: Habitica/Gear
Translation: Habitica/Generic
Translation: Habitica/Groups
Translation: Habitica/Messages
Translation: Habitica/Npc
Translation: Habitica/Overview
Translation: Habitica/Pets
Translation: Habitica/Quests
Translation: Habitica/Questscontent
Translation: Habitica/Rebirth
Translation: Habitica/Settings
Translation: Habitica/Subscriber
Translation: Habitica/Tasks
2024-12-30 16:06:20 +01:00
Kalista Payne 4ba73dfbec fix(notifications): don't error on same page 2024-12-19 15:33:23 -06:00
dependabot[bot] e675ea9bd1 Bump send and express in /website/client (#15324)
Bumps [send](https://github.com/pillarjs/send) and [express](https://github.com/expressjs/express). These dependencies needed to be updated together.

Updates `send` from 0.18.0 to 0.19.0
- [Release notes](https://github.com/pillarjs/send/releases)
- [Changelog](https://github.com/pillarjs/send/blob/master/HISTORY.md)
- [Commits](https://github.com/pillarjs/send/compare/0.18.0...0.19.0)

Updates `express` from 4.19.2 to 4.21.0
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/4.21.0/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.19.2...4.21.0)

---
updated-dependencies:
- dependency-name: send
  dependency-type: indirect
- dependency-name: express
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Natalie <78037386+CuriousMagpie@users.noreply.github.com>
2024-12-19 14:19:16 -05:00
dependabot[bot] 9c27d86ced Bump body-parser and express (#15319)
Bumps [body-parser](https://github.com/expressjs/body-parser) and [express](https://github.com/expressjs/express). These dependencies needed to be updated together.

Updates `body-parser` from 1.20.2 to 1.20.3
- [Release notes](https://github.com/expressjs/body-parser/releases)
- [Changelog](https://github.com/expressjs/body-parser/blob/master/HISTORY.md)
- [Commits](https://github.com/expressjs/body-parser/compare/1.20.2...1.20.3)

Updates `express` from 4.19.2 to 4.20.0
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/master/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.19.2...4.20.0)

---
updated-dependencies:
- dependency-name: body-parser
  dependency-type: direct:production
- dependency-name: express
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Natalie <78037386+CuriousMagpie@users.noreply.github.com>
2024-12-19 14:19:04 -05:00
dependabot[bot] 58ee81adfc Bump serve-static and express (#15318)
Bumps [serve-static](https://github.com/expressjs/serve-static) to 1.16.0 and updates ancestor dependency [express](https://github.com/expressjs/express). These dependencies need to be updated together.


Updates `serve-static` from 1.15.0 to 1.16.0
- [Release notes](https://github.com/expressjs/serve-static/releases)
- [Changelog](https://github.com/expressjs/serve-static/blob/master/HISTORY.md)
- [Commits](https://github.com/expressjs/serve-static/compare/v1.15.0...1.16.0)

Updates `express` from 4.19.2 to 4.20.0
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/master/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.19.2...4.20.0)

---
updated-dependencies:
- dependency-name: serve-static
  dependency-type: indirect
- dependency-name: express
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Natalie <78037386+CuriousMagpie@users.noreply.github.com>
2024-12-19 14:18:51 -05:00
dependabot[bot] 32c9904a6e Bump cookie and express (#15338)
Bumps [cookie](https://github.com/jshttp/cookie) to 0.7.1 and updates ancestor dependency [express](https://github.com/expressjs/express). These dependencies need to be updated together.


Updates `cookie` from 0.6.0 to 0.7.1
- [Release notes](https://github.com/jshttp/cookie/releases)
- [Commits](https://github.com/jshttp/cookie/compare/v0.6.0...v0.7.1)

Updates `express` from 4.19.2 to 4.21.1
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/4.21.1/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.19.2...4.21.1)

---
updated-dependencies:
- dependency-name: cookie
  dependency-type: indirect
- dependency-name: express
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-19 13:43:21 -05:00
dependabot[bot] b86e0a1549 Bump send and express (#15339)
Bumps [send](https://github.com/pillarjs/send) to 0.19.0 and updates ancestor dependency [express](https://github.com/expressjs/express). These dependencies need to be updated together.


Updates `send` from 0.18.0 to 0.19.0
- [Release notes](https://github.com/pillarjs/send/releases)
- [Changelog](https://github.com/pillarjs/send/blob/master/HISTORY.md)
- [Commits](https://github.com/pillarjs/send/compare/0.18.0...0.19.0)

Updates `express` from 4.19.2 to 4.21.1
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/4.21.1/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.19.2...4.21.1)

---
updated-dependencies:
- dependency-name: send
  dependency-type: indirect
- dependency-name: express
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-19 13:42:48 -05:00
dependabot[bot] 154ac9bb38 chore(deps): bump mongoose from 7.6.8 to 7.8.3 (#15374)
Bumps [mongoose](https://github.com/Automattic/mongoose) from 7.6.8 to 7.8.3.
- [Release notes](https://github.com/Automattic/mongoose/releases)
- [Changelog](https://github.com/Automattic/mongoose/blob/7.8.3/CHANGELOG.md)
- [Commits](https://github.com/Automattic/mongoose/compare/7.6.8...7.8.3)

---
updated-dependencies:
- dependency-name: mongoose
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-19 13:28:20 -05:00
dependabot[bot] a97060445a chore(deps): bump cookie and express in /website/client (#15375)
Bumps [cookie](https://github.com/jshttp/cookie) and [express](https://github.com/expressjs/express). These dependencies needed to be updated together.

Updates `cookie` from 0.6.0 to 0.7.1
- [Release notes](https://github.com/jshttp/cookie/releases)
- [Commits](https://github.com/jshttp/cookie/compare/v0.6.0...v0.7.1)

Updates `express` from 4.19.2 to 4.21.2
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/4.21.2/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.19.2...4.21.2)

---
updated-dependencies:
- dependency-name: cookie
  dependency-type: indirect
- dependency-name: express
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-19 13:28:01 -05:00
Kalista Payne 26b59de1de feat(migration): revised NYE script 2024-12-18 18:01:16 -06:00
Kalista Payne 21c8b00ef6 chore(subproj): update habitica-images 2024-12-18 17:33:34 -06:00
Kalista Payne c25b7293bb 5.32.0 2024-12-17 15:00:55 -06:00
Weblate 15e078cb34 Translated using Weblate (German)
Currently translated at 100.0% (272 of 272 strings)

Translated using Weblate (Polish)

Currently translated at 22.2% (54 of 243 strings)

Translated using Weblate (Polish)

Currently translated at 72.6% (189 of 260 strings)

Translated using Weblate (Bulgarian)

Currently translated at 64.0% (107 of 167 strings)

Co-authored-by: Jan Hesko-Kołodziński <janheski@gmail.com>
Co-authored-by: Matthieu <matthieu-ds@hotmail.de>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: Дмитрий <dimaprohor570@gmail.com>
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/bg/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/pl/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/de/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/pl/
Translation: Habitica/Achievements
Translation: Habitica/Faq
Translation: Habitica/Limited
Translation: Habitica/Settings
2024-12-17 18:09:20 +01:00
Natalie f7bb17202b January 2025 Content Build (#15371)
* chore: add spritesheet

* chore: update spritesheet

* chore: add January subscriber set

* chore: add January subscriber items

* chore: add January background and enchanted armoire gear

* chore: fixing dumb typos

* chore: fix another typo

* chore: and another dumb typo

* chore: fix release date for armoire items

* fix(grammar): articles

---------

Co-authored-by: Kalista Payne <sabrecat@gmail.com>
2024-12-16 11:54:09 -06:00
Kalista Payne 213b7696c5 5.31.2 2024-12-16 11:25:58 -06:00
Weblate fe5c95316b Translated using Weblate (Turkish)
Currently translated at 100.0% (240 of 240 strings)

Translated using Weblate (Slovak)

Currently translated at 100.0% (240 of 240 strings)

Translated using Weblate (German)

Currently translated at 94.0% (3054 of 3247 strings)

Translated using Weblate (German)

Currently translated at 93.6% (3041 of 3247 strings)

Translated using Weblate (German)

Currently translated at 93.6% (3041 of 3247 strings)

Translated using Weblate (German)

Currently translated at 93.4% (3034 of 3247 strings)

Translated using Weblate (German)

Currently translated at 93.3% (3032 of 3247 strings)

Translated using Weblate (German)

Currently translated at 100.0% (812 of 812 strings)

Translated using Weblate (German)

Currently translated at 93.3% (3030 of 3247 strings)

Translated using Weblate (German)

Currently translated at 98.8% (803 of 812 strings)

Translated using Weblate (German)

Currently translated at 93.2% (3028 of 3247 strings)

Translated using Weblate (Slovak)

Currently translated at 100.0% (240 of 240 strings)

Translated using Weblate (Slovak)

Currently translated at 100.0% (394 of 394 strings)

Translated using Weblate (German)

Currently translated at 93.1% (3026 of 3247 strings)

Translated using Weblate (German)

Currently translated at 93.1% (3024 of 3247 strings)

Translated using Weblate (German)

Currently translated at 92.9% (3019 of 3247 strings)

Translated using Weblate (German)

Currently translated at 92.9% (3019 of 3247 strings)

Translated using Weblate (German)

Currently translated at 97.7% (794 of 812 strings)

Translated using Weblate (Portuguese)

Currently translated at 98.2% (387 of 394 strings)

Translated using Weblate (Portuguese)

Currently translated at 68.8% (179 of 260 strings)

Translated using Weblate (German)

Currently translated at 100.0% (260 of 260 strings)

Translated using Weblate (German)

Currently translated at 100.0% (114 of 114 strings)

Translated using Weblate (German)

Currently translated at 97.2% (790 of 812 strings)

Translated using Weblate (Polish)

Currently translated at 58.2% (53 of 91 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (167 of 167 strings)

Translated using Weblate (German)

Currently translated at 99.2% (258 of 260 strings)

Translated using Weblate (Turkish)

Currently translated at 59.8% (533 of 890 strings)

Translated using Weblate (Slovak)

Currently translated at 100.0% (240 of 240 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 94.7% (3077 of 3247 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (193 of 193 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (140 of 140 strings)

Translated using Weblate (German)

Currently translated at 99.1% (113 of 114 strings)

Translated using Weblate (German)

Currently translated at 100.0% (432 of 432 strings)

Translated using Weblate (German)

Currently translated at 92.6% (3009 of 3247 strings)

Translated using Weblate (German)

Currently translated at 98.8% (257 of 260 strings)

Translated using Weblate (German)

Currently translated at 98.6% (426 of 432 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (3247 of 3247 strings)

Translated using Weblate (German)

Currently translated at 92.4% (3003 of 3247 strings)

Translated using Weblate (Hebrew)

Currently translated at 75.8% (182 of 240 strings)

Translated using Weblate (Dutch)

Currently translated at 66.1% (172 of 260 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (260 of 260 strings)

Translated using Weblate (German)

Currently translated at 98.4% (256 of 260 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (260 of 260 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (272 of 272 strings)

Translated using Weblate (Spanish)

Currently translated at 99.7% (3239 of 3247 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (394 of 394 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (890 of 890 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (260 of 260 strings)

Translated using Weblate (Spanish)

Currently translated at 97.6% (254 of 260 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (272 of 272 strings)

Translated using Weblate (French)

Currently translated at 100.0% (3247 of 3247 strings)

Translated using Weblate (Turkish)

Currently translated at 96.2% (231 of 240 strings)

Translated using Weblate (German)

Currently translated at 92.2% (2996 of 3247 strings)

Translated using Weblate (Dutch)

Currently translated at 22.2% (54 of 243 strings)

Translated using Weblate (Dutch)

Currently translated at 53.8% (49 of 91 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (394 of 394 strings)

Translated using Weblate (Spanish)

Currently translated at 89.6% (233 of 260 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (243 of 243 strings)

Translated using Weblate (Spanish)

Currently translated at 99.6% (259 of 260 strings)

Translated using Weblate (Spanish)

Currently translated at 88.0% (229 of 260 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (133 of 133 strings)

Translated using Weblate (Russian)

Currently translated at 35.8% (87 of 243 strings)

Translated using Weblate (Russian)

Currently translated at 35.8% (87 of 243 strings)

Translated using Weblate (Russian)

Currently translated at 99.7% (393 of 394 strings)

Translated using Weblate (Ukrainian)

Currently translated at 97.4% (188 of 193 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (110 of 110 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (890 of 890 strings)

Translated using Weblate (Hebrew)

Currently translated at 74.5% (179 of 240 strings)

Translated using Weblate (German)

Currently translated at 100.0% (260 of 260 strings)

Translated using Weblate (German)

Currently translated at 100.0% (13 of 13 strings)

Translated using Weblate (German)

Currently translated at 98.2% (112 of 114 strings)

Translated using Weblate (German)

Currently translated at 92.0% (2989 of 3247 strings)

Translated using Weblate (German)

Currently translated at 100.0% (133 of 133 strings)

Translated using Weblate (German)

Currently translated at 100.0% (272 of 272 strings)

Translated using Weblate (Hebrew)

Currently translated at 75.4% (181 of 240 strings)

Translated using Weblate (French)

Currently translated at 99.9% (3246 of 3247 strings)

Translated using Weblate (French)

Currently translated at 100.0% (260 of 260 strings)

Translated using Weblate (French)

Currently translated at 100.0% (272 of 272 strings)

Translated using Weblate (French)

Currently translated at 99.3% (3225 of 3247 strings)

Translated using Weblate (French)

Currently translated at 100.0% (260 of 260 strings)

Translated using Weblate (French)

Currently translated at 100.0% (243 of 243 strings)

Translated using Weblate (French)

Currently translated at 100.0% (394 of 394 strings)

Translated using Weblate (Turkish)

Currently translated at 53.0% (138 of 260 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (8 of 8 strings)

Translated using Weblate (Turkish)

Currently translated at 68.5% (296 of 432 strings)

Translated using Weblate (Turkish)

Currently translated at 52.9% (1720 of 3247 strings)

Translated using Weblate (Turkish)

Currently translated at 83.3% (200 of 240 strings)

Translated using Weblate (Turkish)

Currently translated at 69.3% (563 of 812 strings)

Translated using Weblate (Turkish)

Currently translated at 65.9% (60 of 91 strings)

Translated using Weblate (Turkish)

Currently translated at 59.5% (530 of 890 strings)

Translated using Weblate (Turkish)

Currently translated at 79.2% (206 of 260 strings)

Translated using Weblate (German)

Currently translated at 91.7% (2980 of 3247 strings)

Translated using Weblate (Russian)

Currently translated at 29.2% (71 of 243 strings)

Translated using Weblate (German)

Currently translated at 100.0% (394 of 394 strings)

Translated using Weblate (Russian)

Currently translated at 99.4% (885 of 890 strings)

Translated using Weblate (German)

Currently translated at 100.0% (890 of 890 strings)

Translated using Weblate (German)

Currently translated at 91.7% (2979 of 3247 strings)

Translated using Weblate (German)

Currently translated at 100.0% (243 of 243 strings)

Translated using Weblate (German)

Currently translated at 100.0% (890 of 890 strings)

Translated using Weblate (German)

Currently translated at 100.0% (890 of 890 strings)

Translated using Weblate (Slovak)

Currently translated at 83.3% (95 of 114 strings)

Translated using Weblate (Slovak)

Currently translated at 99.7% (393 of 394 strings)

Translated using Weblate (Slovak)

Currently translated at 43.7% (73 of 167 strings)

Translated using Weblate (Spanish)

Currently translated at 87.6% (228 of 260 strings)

Co-authored-by: Alison Alex <spamkari@hotmail.com>
Co-authored-by: Antje Schubert <antje.schubert96@web.de>
Co-authored-by: Elizaveta <lizka4231@gmail.com>
Co-authored-by: Filip Betko <filipbetko@gmail.com>
Co-authored-by: Irina  Shcherbinina <cat3dcat007@gmail.com>
Co-authored-by: Jaime Martí <jaumemarti77@icloud.com>
Co-authored-by: João Santos Reis <joaosreis@outlook.pt>
Co-authored-by: Julia Bacik <bacikjulia@gmail.com>
Co-authored-by: Kasper van der Linden <kasper.van.der.linden@gmail.com>
Co-authored-by: Katharina <katharinaanna.wilding@gmail.com>
Co-authored-by: Kenvinn <kevinsavio514@gmail.com>
Co-authored-by: Marie Blosse--Gilbin <mbgil@hotmail.fr>
Co-authored-by: Maya <mayabaciu1@gmail.com>
Co-authored-by: Maya B <mayabaciu1@gmail.com>
Co-authored-by: Sand <weblate@sandhydraulik.de>
Co-authored-by: Sophie LE MASLE <sophiesuff@gmail.com>
Co-authored-by: Tetiana <merekka13@gmail.com>
Co-authored-by: Toro Mor <thomas.bizer@gmx.de>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: Yaşar Efe Çelik <yasar.123.sevda@gmail.com>
Co-authored-by: YuyingLiang <standingfish.malina@gmail.com>
Co-authored-by: razil <boss.razmarin@gmail.com>
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/pl/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/sk/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/de/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/es/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/tr/
Translate-URL: https://translate.habitica.com/projects/habitica/challenge/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/character/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/character/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/nl/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/pl/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/tr/
Translate-URL: https://translate.habitica.com/projects/habitica/content/de/
Translate-URL: https://translate.habitica.com/projects/habitica/content/es/
Translate-URL: https://translate.habitica.com/projects/habitica/content/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/content/pt/
Translate-URL: https://translate.habitica.com/projects/habitica/content/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/content/sk/
Translate-URL: https://translate.habitica.com/projects/habitica/content/tr/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/de/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/es/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/nl/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/de/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/es/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/tr/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/he/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/sk/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/tr/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/de/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/tr/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/de/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/es/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/de/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/overview/tr/
Translate-URL: https://translate.habitica.com/projects/habitica/pets/de/
Translate-URL: https://translate.habitica.com/projects/habitica/pets/sk/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/de/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/tr/
Translate-URL: https://translate.habitica.com/projects/habitica/rebirth/de/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/de/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/es/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/nl/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/pt/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/tr/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/de/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/es/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/tr/
Translate-URL: https://translate.habitica.com/projects/habitica/tasks/zh_Hans/
Translation: Habitica/Achievements
Translation: Habitica/Backgrounds
Translation: Habitica/Challenge
Translation: Habitica/Character
Translation: Habitica/Communityguidelines
Translation: Habitica/Content
Translation: Habitica/Faq
Translation: Habitica/Gear
Translation: Habitica/Generic
Translation: Habitica/Groups
Translation: Habitica/Limited
Translation: Habitica/Npc
Translation: Habitica/Overview
Translation: Habitica/Pets
Translation: Habitica/Questscontent
Translation: Habitica/Rebirth
Translation: Habitica/Settings
Translation: Habitica/Subscriber
Translation: Habitica/Tasks
2024-12-15 18:52:35 +01:00
Kalista Payne 54617f8583 Squashed commit of the following:
commit a1f44b855cff2b54992cdca81b9dd2f67c5de20a
Author: Kalista Payne <sabrecat@gmail.com>
Date:   Wed Dec 4 15:28:54 2024 -0600

    fix(g1g1): pass promo data thru profile flow

commit a9923f882f3294ba22e1dff9497e6f74b0d12eab
Merge: 05793922b2 75c9731ca4
Author: Kalista Payne <sabrecat@gmail.com>
Date:   Tue Dec 3 13:53:28 2024 -0600

    Merge branch 'develop' into sabrecat/g1g1-success

commit 05793922b2a3c0f9dd206b61beefb927b00859e4
Merge: b0bbc10457 d6c47e7e81
Author: Kalista Payne <sabrecat@gmail.com>
Date:   Tue Nov 19 12:21:42 2024 -0600

    Merge branch 'develop' into sabrecat/g1g1-success

commit b0bbc10457b0558faeaf02305210c8b0d5ed5839
Author: Kalista Payne <sabrecat@gmail.com>
Date:   Mon Nov 4 16:26:30 2024 -0600

    feat(gifts): add dynamic G1G1 success text
    also clean out some more Amazon code
2024-12-12 12:45:14 -06:00
Phillip Thelen 75c9731ca4 filter stripe webhooks for correct server (#15320)
Co-authored-by: Kalista Payne <sabrecat@gmail.com>
2024-11-26 12:24:23 -06:00
Kalista Payne 31afc45744 5.31.1 2024-11-22 09:20:27 -06:00
Kalista Payne f6466b161b Squashed commit of the following:
commit ea8512bc2eeda30c4d983fb43bfcb33ea39093e9
Merge: 2bb7683cfd a36114e904
Author: Kalista Payne <sabrecat@gmail.com>
Date:   Thu Nov 21 12:47:11 2024 -0600

    Merge branch 'develop' into ui-drawer-fix

commit 2bb7683cfd
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Tue Nov 12 15:46:55 2024 -0500

    fix food centering and error centering at very small widths

commit fcabf03978
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Fri Nov 1 14:44:16 2024 -0400

    grid size update

commit 47a531c1aa
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Thu Oct 31 16:17:22 2024 -0400

    centered error messages on pet drawer

commit 14d2872392
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Thu Oct 24 15:47:46 2024 -0400

    center no food/no saddle messages in drawer

commit 49d1d10a4f
Merge: 6a805bdc45 f1993db0fa
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Thu Oct 24 14:04:16 2024 -0400

    Merge branch 'develop' into ui-drawer-fix

commit 6a805bdc45
Author: Alex <alex.kliger@gmail.com>
Date:   Sat Nov 19 09:41:21 2022 -0500

    fix(ui): correct crowding in title of drawer component that causes drawer toggle icon to become obstructed
2024-11-21 12:55:00 -06:00
Kalista Payne a36114e904 Squashed commit of the following:
commit 4d88df1c381c4136cfe4780b6b5464d9c984bb31
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Wed Oct 30 14:24:53 2024 -0400

    fixing active/focus states

commit 630f74db6365625af210de81d577d43945f62df4
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Wed Oct 23 13:25:14 2024 -0400

    sign-up/login/debug menu updates

commit f85ef1c58e367219923c46aeebe77d1aa846b6f3
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Tue Oct 15 13:56:36 2024 -0400

    more color standardization

commit cd2ee3350fc51016cc75fb799debeefa0b1d9b64
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Tue Oct 15 13:39:02 2024 -0400

    updates per comments

commit e91371522bb9a6dae5c6d02eb6f16f0b632f7a24
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Fri Oct 4 14:25:45 2024 -0400

    class selection active state

commit 4fcdca1eb07eb67aacd84feb1c9357d52fd6f23f
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Thu Oct 3 14:31:00 2024 -0400

    fixing a few more buttons

commit 475e21aae7733cfa072f828c559cc0930f0ad878
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Wed Oct 2 15:57:25 2024 -0400

    line-heights converted to unitless multipliers

commit c5dca257274a60b02e1f12e3c6daf103cec53096
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Fri Sep 27 13:48:20 2024 -0400

    second pass

commit 685f4d4d64b8b234afbb702d1b8a52d4670d3825
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Thu Sep 26 16:58:59 2024 -0400

    first pass
2024-11-21 12:40:05 -06:00
dependabot[bot] 529f856ab9 Bump cross-spawn from 7.0.3 to 7.0.5 (#15365)
Bumps [cross-spawn](https://github.com/moxystudio/node-cross-spawn) from 7.0.3 to 7.0.5.
- [Changelog](https://github.com/moxystudio/node-cross-spawn/blob/master/CHANGELOG.md)
- [Commits](https://github.com/moxystudio/node-cross-spawn/compare/v7.0.3...v7.0.5)

---
updated-dependencies:
- dependency-name: cross-spawn
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-21 13:31:49 -05:00
Kalista Payne 9077e66973 fix(notifications): adjust z-index by @CuriousMagpie 2024-11-21 12:22:45 -06:00
Kalista Payne a47a96b70d Squashed commit of the following:
commit 44583e224c771bab4b75758372e8b051a5346f72
Merge: 1436d8d5ef d6c47e7e81
Author: Kalista Payne <sabrecat@gmail.com>
Date:   Tue Nov 19 12:33:34 2024 -0600

    Merge branch 'develop' into sabrecat/hourglass-afterward

commit 1436d8d5ef5b672425513e9c5886ca533594134f
Author: Kalista Payne <sabrecat@gmail.com>
Date:   Tue Nov 19 10:44:53 2024 -0600

    fix(faq): update Hourglass explainer
2024-11-21 12:17:58 -06:00
Kalista Payne 8a94e88786 fix(migrations): correct linting errors 2024-11-21 12:07:51 -06:00
Kalista Payne b3aa236d3d 5.31.0 2024-11-21 11:52:48 -06:00
Kalista Payne 4dd58ad89e fix(event): turkey migration update 2024-11-21 11:52:11 -06:00
Weblate 317f7ab598 Translated using Weblate (French)
Currently translated at 100.0% (890 of 890 strings)

Translated using Weblate (German)

Currently translated at 92.5% (2971 of 3211 strings)

Translated using Weblate (German)

Currently translated at 97.1% (789 of 812 strings)

Translated using Weblate (German)

Currently translated at 100.0% (887 of 887 strings)

Co-authored-by: Marie Blosse--Gilbin <mbgil@hotmail.fr>
Co-authored-by: Sand <weblate@sandhydraulik.de>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/de/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/fr/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/de/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/de/
Translation: Habitica/Backgrounds
Translation: Habitica/Gear
Translation: Habitica/Questscontent
2024-11-21 15:59:10 +01:00
Kalista Payne d6c47e7e81 Squashed commit of the following:
commit 7de39d868b547848f8e2990a65ddca90b48f6823
Author: CuriousMagpie <eilatan@gmail.com>
Date:   Mon Oct 14 13:05:03 2024 -0400

    gem text clickable
2024-11-19 12:09:39 -06:00
Kalista Payne 1ed61a3d3d December 2024 and Winter Wonderland 2025 build (#15358)
* feat(content): Winter 2025 build by @CuriousMagpie

* fix(content): add more WW

* fix(content): add more WW

* chore(subproj): update habitica-images

* fix(gala): December 2024 is Winter 2025

* fix(content): lint, background typo, 0 index month

* fix(content): add missing mystery set name

* fix(content): roll back erroneous month indexing

* fix(tests): no 13th month, consider releases in schedule test

* update gear strings

* fix(seasonal): show quest modal

* fix(seasonal): use category-item component

* chore(subproj): update habitica-images

---------

Co-authored-by: CuriousMagpie <eilatan@gmail.com>
2024-11-19 11:44:22 -06:00
Kalista Payne 5c734cfa00 chore(subproj): update images 2024-11-19 09:42:23 -06:00
Kalista Payne 07f485a654 chore(migrations): add subs migration 2024-11-19 09:38:05 -06:00
202 changed files with 5682 additions and 2423 deletions
+1 -1
View File
@@ -47,5 +47,5 @@ webpack.webstorm.config
# mongodb replica set for local dev
mongodb-*.tgz
/mongodb-data
/mongodb-data*
/.nyc_output
@@ -0,0 +1,115 @@
/* eslint-disable no-console */
const MIGRATION_NAME = '20241119_gem_caps_hourglasses';
import { model as User } from '../../../website/server/models/user';
const progressCount = 1000;
let count = 0;
async function updateUser (user) {
count += 1;
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
const { consecutive, customerId, dateTerminated, planId } = user.purchased.plan;
const isRecurring = customerId !== 'Gift' && !dateTerminated;
const updateOp = {
$set: {
migration: MIGRATION_NAME,
'purchased.plan.consecutive.gemCapExtra': Math.max(2 * Math.ceil((consecutive.gemCapExtra + 1) / 2, 26)),
},
$inc: {},
};
let hourglassBonus = 0;
if (isRecurring) {
await user.updateBalance(
5,
'admin_update_balance',
'',
'Subscription Reward Migration',
);
updateOp.$inc.balance = 5;
switch (planId) {
case 'basic':
case 'basic_earned':
case 'group_plan_auto':
hourglassBonus = 2;
break;
case 'basic_3mo':
case 'basic_6mo':
case 'google_6mo':
hourglassBonus = 4;
break;
case 'basic_12mo':
hourglassBonus = 12;
updateOp.$set['purchased.plan.hourglassPromoReceived'] = new Date();
break;
default:
hourglassBonus = 0;
}
if (hourglassBonus) {
updateOp.$inc['purchased.plan.consecutive.trinkets'] = hourglassBonus;
await user.updateHourglasses(
hourglassBonus,
'admin_update_balance',
'',
'Subscription Reward Migration',
);
}
updateOp.$push = {
notifications: {
type: 'ITEM_RECEIVED',
data: {
icon: 'notif_subscriber_reward',
title: 'Thanks for being a subscriber!',
text: 'Enjoy these extra Mystic Hourglasses and Gems to celebrate our new benefits.',
},
seen: false,
},
};
}
return await User.updateOne(
{ _id: user._id },
updateOp,
).exec();
}
export default async function processUsers () {
let query = {
migration: { $ne: MIGRATION_NAME },
'purchased.plan.customerId': { $exists: true },
$or: [
{ 'purchased.plan.dateTerminated': { $exists: false } },
{ 'purchased.plan.dateTerminated': null },
{ 'purchased.plan.dateTerminated': { $gt: new Date() } },
],
};
const fields = {
_id: 1,
purchased: 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)
.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
}
};
+1 -1
View File
@@ -26,7 +26,7 @@ async function updateUser (user) {
[{ name: 'BASE_URL', content: BASE_URL }], // Add variables from template
);
return User.update({ _id: user._id }, { $set: { migration: MIGRATION_NAME } }).exec();
return User.updateOne({ _id: user._id }, { $set: { migration: MIGRATION_NAME } }).exec();
}
export default async function processUsers () {
+2 -2
View File
@@ -27,13 +27,13 @@ async function updateUser (user) {
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
return User.update({ _id: user._id }, { $set: set }).exec();
return User.updateOne({ _id: user._id }, { $set: set }).exec();
}
export default async function processUsers () {
const query = {
migration: { $ne: MIGRATION_NAME },
'auth.local.lowerCaseUsername': 'olson1',
'auth.local.username': 'ExampleHabitican',
};
const fields = {
+1 -1
View File
@@ -57,7 +57,7 @@ async function updateUser (user) {
export default async function processUsers () {
const query = {
migration: { $ne: MIGRATION_NAME },
'auth.local.username': 'SabreTest',
'auth.local.username': 'ExampleHabitican',
};
const fields = {
@@ -2,16 +2,15 @@
* Award Habitoween ladder items to participants in this month's Habitoween festivities
*/
/* eslint-disable no-console */
import { model as User } from '../../website/server/models/user';
const MIGRATION_NAME = '20241030_habitoween_ladder'; // Update when running in future years
import { model as User } from '../../../website/server/models/user';
const progressCount = 1000;
let count = 0;
async function updateUser (user) {
count++;
count += 1;
const set = { migration: MIGRATION_NAME };
const inc = {
@@ -26,7 +25,7 @@ async function updateUser (user) {
'items.food.Candy_Desert': 1,
'items.food.Candy_Red': 1,
};
let push = { notifications: { $each: [] }};
const push = { notifications: { $each: [] } };
if (user && user.items && user.items.mounts && user.items.mounts['JackOLantern-RoyalPurple']) {
push.notifications.$each.push({
@@ -138,13 +137,13 @@ async function updateUser (user) {
}
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
return await User.updateOne({_id: user._id}, {$inc: inc, $push: push, $set: set}).exec();
return User.updateOne({ _id: user._id }, { $inc: inc, $push: push, $set: set }).exec();
}
export default async function processUsers () {
let query = {
migration: {$ne: MIGRATION_NAME},
'auth.timestamps.loggedin': {$gt: new Date('2024-10-01')},
const query = {
migration: { $ne: MIGRATION_NAME },
'auth.timestamps.loggedin': { $gt: new Date('2024-10-01') },
};
const fields = {
@@ -156,7 +155,7 @@ export default async function processUsers () {
const users = await User // eslint-disable-line no-await-in-loop
.find(query)
.limit(250)
.sort({_id: 1})
.sort({ _id: 1 })
.select(fields)
.lean()
.exec();
@@ -173,4 +172,4 @@ export default async function processUsers () {
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
}
};
}
+167
View File
@@ -0,0 +1,167 @@
/* eslint-disable no-console */
import { model as User } from '../../website/server/models/user';
const MIGRATION_NAME = '20241120_harvest_feast';
const progressCount = 1000;
let count = 0;
async function updateUser (user) {
count += 1;
const updateOp = {
$set: { migration: MIGRATION_NAME },
};
if (typeof user.items.gear.owned.head_special_turkeyHelmGilded !== 'undefined') {
updateOp.$inc = {
'items.food.Pie_Base': 1,
'items.food.Pie_CottonCandyBlue': 1,
'items.food.Pie_CottonCandyPink': 1,
'items.food.Pie_Desert': 1,
'items.food.Pie_Golden': 1,
'items.food.Pie_Red': 1,
'items.food.Pie_Shade': 1,
'items.food.Pie_Skeleton': 1,
'items.food.Pie_Zombie': 1,
'items.food.Pie_White': 1,
};
updateOp.$push = {
notifications: {
type: 'ITEM_RECEIVED',
data: {
icon: 'notif_harvestfeast_pie',
title: 'Happy Harvest Feast!',
text: 'Gobble gobble, you\'ve received an assortment of pie for your Pets!',
destination: '/inventory/stable',
},
seen: false,
},
};
} else if (typeof user.items.gear.owned.armor_special_turkeyArmorBase !== 'undefined') {
updateOp.$set['items.gear.owned.head_special_turkeyHelmGilded'] = true;
updateOp.$set['items.gear.owned.armor_special_turkeyArmorGilded'] = true;
updateOp.$set['items.gear.owned.back_special_turkeyTailGilded'] = true;
updateOp.$push = {
notifications: {
type: 'ITEM_RECEIVED',
data: {
icon: 'notif_harvestfeast_gilded_set',
title: 'Happy Harvest Feast!',
text: 'Gobble gobble, you\'ve received the Gilded Turkey Armor, Helm, and Tail!',
destination: '/inventory/equipment',
},
seen: false,
},
};
} else if (user.items && user.items.mounts && user.items.mounts['Turkey-Gilded']) {
updateOp.$set['items.gear.owned.head_special_turkeyHelmBase'] = true;
updateOp.$set['items.gear.owned.armor_special_turkeyArmorBase'] = true;
updateOp.$set['items.gear.owned.back_special_turkeyTailBase'] = true;
updateOp.$push = {
notifications: {
type: 'ITEM_RECEIVED',
data: {
icon: 'notif_harvestfeast_base_set',
title: 'Happy Harvest Feast!',
text: 'Gobble gobble, you\'ve received the Turkey Armor, Helm, and Tail!',
destination: '/inventory/equipment',
},
seen: false,
},
};
} else if (user.items && user.items.pets && user.items.pets['Turkey-Gilded']) {
updateOp.$set['items.mounts.Turkey-Gilded'] = true;
updateOp.$push = {
notifications: {
type: 'ITEM_RECEIVED',
data: {
icon: 'notif_harvestfeast_gilded_mount',
title: 'Happy Harvest Feast!',
text: 'Gobble gobble, you\'ve received the Gilded Turkey Mount!',
destination: '/inventory/stable',
},
seen: false,
},
};
} else if (user.items && user.items.mounts && user.items.mounts['Turkey-Base']) {
updateOp.$set['items.pets.Turkey-Gilded'] = 5;
updateOp.$push = {
notifications: {
type: 'ITEM_RECEIVED',
data: {
icon: 'notif_harvestfeast_gilded_pet',
title: 'Happy Harvest Feast!',
text: 'Gobble gobble, you\'ve received the Gilded Turkey Pet!',
destination: '/inventory/stable',
},
seen: false,
},
};
} else if (user.items && user.items.pets && user.items.pets['Turkey-Base']) {
updateOp.$set['items.mounts.Turkey-Base'] = true;
updateOp.$push = {
notifications: {
type: 'ITEM_RECEIVED',
data: {
icon: 'notif_harvestfeast_base_mount',
title: 'Happy Harvest Feast!',
text: 'Gobble gobble, you\'ve received the Turkey Mount!',
destination: '/inventory/stable',
},
seen: false,
},
};
} else {
updateOp.$set['items.pets.Turkey-Base'] = 5;
updateOp.$push = {
notifications: {
type: 'ITEM_RECEIVED',
data: {
icon: 'notif_harvestfeast_base_pet',
title: 'Happy Harvest Feast!',
text: 'Gobble gobble, you\'ve received the Turkey Pet!',
destination: '/inventory/stable',
},
seen: false,
},
};
}
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
return User.updateOne({ _id: user._id }, updateOp).exec();
}
export default async function processUsers () {
const query = {
migration: { $ne: MIGRATION_NAME },
'auth.timestamps.loggedin': { $gt: new Date('2024-10-20') },
};
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
}
}
+125
View File
@@ -0,0 +1,125 @@
/* eslint-disable no-console */
import { model as User } from '../../website/server/models/user';
const MIGRATION_NAME = '20231228_nye';
const progressCount = 1000;
let count = 0;
async function updateUser (user) {
count += 1;
const updateOp = {
$set: { migration: MIGRATION_NAME },
$push: { },
};
const data = {
title: 'Happy New Year!',
destination: '/inventory/equipment',
};
if (typeof user.items.gear.owned.head_special_nye2023 !== 'undefined') {
updateOp.$inc = {
'items.food.Candy_Skeleton': 1,
'items.food.Candy_Base': 1,
'items.food.Candy_CottonCandyBlue': 1,
'items.food.Candy_CottonCandyPink': 1,
'items.food.Candy_Shade': 1,
'items.food.Candy_White': 1,
'items.food.Candy_Golden': 1,
'items.food.Candy_Zombie': 1,
'items.food.Candy_Desert': 1,
'items.food.Candy_Red': 1,
};
data.icon = 'notif_candy_nye';
data.text = 'Youve received an assortment of candy to celebrate with your Pets!';
data.destination = '/inventory/stable';
} else if (typeof user.items.gear.owned.head_special_nye2022 !== 'undefined') {
updateOp.$set['items.gear.owned.head_special_nye2023'] = true;
data.icon = 'notif_2023hat_nye';
data.text = 'Take on your resolutions with style in this Ludicrous Party Hat!';
} else if (typeof user.items.gear.owned.head_special_nye2021 !== 'undefined') {
updateOp.$set['items.gear.owned.head_special_nye2022'] = true;
data.icon = 'notif_2022hat_nye';
data.text = 'Take on your resolutions with style in this Fabulous Party Hat!';
} else if (typeof user.items.gear.owned.head_special_nye2020 !== 'undefined') {
updateOp.$set['items.gear.owned.head_special_nye2021'] = true;
data.icon = 'notif_2021hat_nye';
data.text = 'Take on your resolutions with style in this Preposterous Party Hat!';
} else if (typeof user.items.gear.owned.head_special_nye2019 !== 'undefined') {
updateOp.$set['items.gear.owned.head_special_nye2020'] = true;
data.icon = 'notif_2020hat_nye';
data.text = 'Take on your resolutions with style in this Extravagant Party Hat!';
} else if (typeof user.items.gear.owned.head_special_nye2018 !== 'undefined') {
updateOp.$set['items.gear.owned.head_special_nye2019'] = true;
data.icon = 'notif_2019hat_nye';
data.text = 'Take on your resolutions with style in this Outrageous Party Hat!';
} else if (typeof user.items.gear.owned.head_special_nye2017 !== 'undefined') {
updateOp.$set['items.gear.owned.head_special_nye2018'] = true;
data.icon = 'notif_2018hat_nye';
data.text = 'Take on your resolutions with style in this Outlandish Party Hat!';
} else if (typeof user.items.gear.owned.head_special_nye2016 !== 'undefined') {
updateOp.$set['items.gear.owned.head_special_nye2017'] = true;
data.icon = 'notif_2017hat_nye';
data.text = 'Take on your resolutions with style in this Fanciful Party Hat!';
} else if (typeof user.items.gear.owned.head_special_nye2015 !== 'undefined') {
updateOp.$set['items.gear.owned.head_special_nye2016'] = true;
data.icon = 'notif_2016hat_nye';
data.text = 'Take on your resolutions with style in this Whimsical Party Hat!';
} else if (typeof user.items.gear.owned.head_special_nye2014 !== 'undefined') {
updateOp.$set['items.gear.owned.head_special_nye2015'] = true;
data.icon = 'notif_2015hat_nye';
data.text = 'Take on your resolutions with style in this Ridiculous Party Hat!';
} else if (typeof user.items.gear.owned.head_special_nye !== 'undefined') {
updateOp.$set['items.gear.owned.head_special_nye2014'] = true;
data.icon = 'notif_2014hat_nye';
data.text = 'Take on your resolutions with style in this Silly Party Hat!';
} else {
updateOp.$set['items.gear.owned.head_special_nye'] = true;
data.icon = 'notif_2013hat_nye';
data.text = 'Take on your resolutions with style in this Absurd Party Hat!';
}
updateOp.$push.notifications = {
type: 'ITEM_RECEIVED',
data,
seen: false,
};
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
return User.updateOne({ _id: user._id }, updateOp).exec();
}
export default async function processUsers () {
const query = {
'auth.timestamps.loggedin': { $gt: new Date('2023-12-01') },
migration: { $ne: MIGRATION_NAME },
};
const fields = {
_id: 1,
items: 1,
};
while (true) { // eslint-disable-line no-constant-condition
const users = await User // eslint-disable-line no-await-in-loop
.find(query)
.limit(250)
.sort({ _id: 1 })
.select(fields)
.lean()
.exec();
if (users.length === 0) {
console.warn('All appropriate users found and modified.');
console.warn(`\n${count} users processed\n`);
break;
} else {
query._id = {
$gt: users[users.length - 1],
};
}
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
}
}
+125 -85
View File
@@ -1,12 +1,12 @@
{
"name": "habitica",
"version": "5.30.0",
"version": "5.32.5",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "habitica",
"version": "5.30.0",
"version": "5.32.5",
"hasInstallScript": true,
"dependencies": {
"@babel/core": "^7.22.10",
@@ -22,7 +22,7 @@
"apple-auth": "^1.0.9",
"babel-preset-env": "^1.7.0",
"bcrypt": "^5.1.1",
"body-parser": "^1.20.2",
"body-parser": "^1.20.3",
"bootstrap": "^4.6.2",
"compression": "^1.7.4",
"cookie-session": "^2.0.0",
@@ -33,7 +33,7 @@
"eslint": "^8.55.0",
"eslint-config-habitrpg": "^6.2.3",
"eslint-plugin-mocha": "^5.0.0",
"express": "^4.19.2",
"express": "^4.21.1",
"express-basic-auth": "^1.2.1",
"express-validator": "^5.2.0",
"firebase-admin": "^12.1.1",
@@ -56,7 +56,7 @@
"method-override": "^3.0.0",
"moment": "^2.29.4",
"moment-recur": "^1.0.7",
"mongoose": "^7.6.3",
"mongoose": "^7.8.3",
"morgan": "^1.10.0",
"nconf": "^0.12.1",
"node-gcm": "^1.0.5",
@@ -92,7 +92,7 @@
"chai-as-promised": "^7.1.1",
"chai-moment": "^0.1.0",
"chalk": "^5.3.0",
"cross-spawn": "^7.0.3",
"cross-spawn": "^7.0.5",
"mocha": "^5.1.1",
"monk": "^7.3.4",
"nyc": "^15.1.0",
@@ -3044,9 +3044,9 @@
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
},
"node_modules/@mongodb-js/saslprep": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.4.tgz",
"integrity": "sha512-8zJ8N1x51xo9hwPh6AWnKdLGEC5N3lDa6kms1YHmFBoRhTpJR6HG8wWk0td1MVCu9cD4YBrvjZEtd5Obw0Fbnw==",
"version": "1.1.9",
"resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.9.tgz",
"integrity": "sha512-tVkljjeEaAhCqTzajSdgbQ6gE6f3oneVwa3iXR6csiEwXXOFsiC6Uh9iAjAhXPtqa/XMDHWjjeNH/77m/Yq2dw==",
"optional": true,
"dependencies": {
"sparse-bitfield": "^3.0.3"
@@ -6244,9 +6244,9 @@
"dev": true
},
"node_modules/body-parser": {
"version": "1.20.2",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
"integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
"version": "1.20.3",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
"integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
"dependencies": {
"bytes": "3.1.2",
"content-type": "~1.0.5",
@@ -6256,7 +6256,7 @@
"http-errors": "2.0.0",
"iconv-lite": "0.4.24",
"on-finished": "2.4.1",
"qs": "6.11.0",
"qs": "6.13.0",
"raw-body": "2.5.2",
"type-is": "~1.6.18",
"unpipe": "1.0.0"
@@ -6291,11 +6291,11 @@
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
"node_modules/body-parser/node_modules/qs": {
"version": "6.11.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
"integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
"version": "6.13.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
"integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
"dependencies": {
"side-channel": "^1.0.4"
"side-channel": "^1.0.6"
},
"engines": {
"node": ">=0.6"
@@ -6577,14 +6577,15 @@
}
},
"node_modules/call-bind": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.6.tgz",
"integrity": "sha512-Mj50FLHtlsoVfRfnHaZvyrooHcrlceNZdL/QBvJJVd9Ta55qCQK0gs4ss2oZDeV9zFCs6ewzYgVE5yfVmfFpVg==",
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
"integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
"dependencies": {
"es-define-property": "^1.0.0",
"es-errors": "^1.3.0",
"function-bind": "^1.1.2",
"get-intrinsic": "^1.2.3",
"set-function-length": "^1.2.0"
"get-intrinsic": "^1.2.4",
"set-function-length": "^1.2.1"
},
"engines": {
"node": ">= 0.4"
@@ -7369,9 +7370,9 @@
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="
},
"node_modules/cookie": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
"integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz",
"integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==",
"engines": {
"node": ">= 0.6"
}
@@ -7500,9 +7501,9 @@
}
},
"node_modules/cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
"version": "7.0.5",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.5.tgz",
"integrity": "sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==",
"dependencies": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
@@ -8376,9 +8377,9 @@
"integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ=="
},
"node_modules/encodeurl": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
"integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
"integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
"engines": {
"node": ">= 0.8"
}
@@ -8497,6 +8498,17 @@
"resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz",
"integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA=="
},
"node_modules/es-define-property": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
"integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
"dependencies": {
"get-intrinsic": "^1.2.4"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-errors": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
@@ -9980,36 +9992,36 @@
}
},
"node_modules/express": {
"version": "4.19.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz",
"integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==",
"version": "4.21.1",
"resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz",
"integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==",
"dependencies": {
"accepts": "~1.3.8",
"array-flatten": "1.1.1",
"body-parser": "1.20.2",
"body-parser": "1.20.3",
"content-disposition": "0.5.4",
"content-type": "~1.0.4",
"cookie": "0.6.0",
"cookie": "0.7.1",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
"depd": "2.0.0",
"encodeurl": "~1.0.2",
"encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"finalhandler": "1.2.0",
"finalhandler": "1.3.1",
"fresh": "0.5.2",
"http-errors": "2.0.0",
"merge-descriptors": "1.0.1",
"merge-descriptors": "1.0.3",
"methods": "~1.1.2",
"on-finished": "2.4.1",
"parseurl": "~1.3.3",
"path-to-regexp": "0.1.7",
"path-to-regexp": "0.1.10",
"proxy-addr": "~2.0.7",
"qs": "6.11.0",
"qs": "6.13.0",
"range-parser": "~1.2.1",
"safe-buffer": "5.2.1",
"send": "0.18.0",
"serve-static": "1.15.0",
"send": "0.19.0",
"serve-static": "1.16.2",
"setprototypeof": "1.2.0",
"statuses": "2.0.1",
"type-is": "~1.6.18",
@@ -10062,11 +10074,11 @@
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
"node_modules/express/node_modules/qs": {
"version": "6.11.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
"integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
"version": "6.13.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
"integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
"dependencies": {
"side-channel": "^1.0.4"
"side-channel": "^1.0.6"
},
"engines": {
"node": ">=0.6"
@@ -10531,12 +10543,12 @@
}
},
"node_modules/finalhandler": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
"integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
"integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
"dependencies": {
"debug": "2.6.9",
"encodeurl": "~1.0.2",
"encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"on-finished": "2.4.1",
"parseurl": "~1.3.3",
@@ -13348,10 +13360,27 @@
"resolved": "https://registry.npmjs.org/iota-array/-/iota-array-1.0.0.tgz",
"integrity": "sha512-pZ2xT+LOHckCatGQ3DcG/a+QuEqvoxqkiL7tvE8nn3uuu+f6i1TtpB5/FtWFbxUuVr5PZCx8KskuGatbJDXOWA=="
},
"node_modules/ip": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz",
"integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ=="
"node_modules/ip-address": {
"version": "9.0.5",
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz",
"integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==",
"dependencies": {
"jsbn": "1.1.0",
"sprintf-js": "^1.1.3"
},
"engines": {
"node": ">= 12"
}
},
"node_modules/ip-address/node_modules/jsbn": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz",
"integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A=="
},
"node_modules/ip-address/node_modules/sprintf-js": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
"integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA=="
},
"node_modules/ipaddr.js": {
"version": "1.9.1",
@@ -14961,9 +14990,12 @@
}
},
"node_modules/merge-descriptors": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
"integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
"integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/merge-stream": {
"version": "2.0.0",
@@ -15564,13 +15596,13 @@
}
},
"node_modules/mongoose": {
"version": "7.6.8",
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-7.6.8.tgz",
"integrity": "sha512-q9zAySH+UtOK5yonWyNcLfq3PxrY6s4gdta4qNGKNOE2yTVoY9FP4hQtvWYnv4rkdk7T8QmQMC7bbhJjDxIunw==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-7.8.3.tgz",
"integrity": "sha512-eFnbkKgyVrICoHB6tVJ4uLanS7d5AIo/xHkEbQeOv6g2sD7gh/1biRwvFifsmbtkIddQVNr3ROqHik6gkknN3g==",
"dependencies": {
"bson": "^5.5.0",
"kareem": "2.5.1",
"mongodb": "5.9.1",
"mongodb": "5.9.2",
"mpath": "0.9.0",
"mquery": "5.0.0",
"ms": "2.1.3",
@@ -15593,9 +15625,9 @@
}
},
"node_modules/mongoose/node_modules/mongodb": {
"version": "5.9.1",
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.9.1.tgz",
"integrity": "sha512-NBGA8AfJxGPeB12F73xXwozt8ZpeIPmCUeWRwl9xejozTXFes/3zaep9zhzs1B/nKKsw4P3I4iPfXl3K7s6g+Q==",
"version": "5.9.2",
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.9.2.tgz",
"integrity": "sha512-H60HecKO4Bc+7dhOv4sJlgvenK4fQNqqUIlXxZYQNbfEWSALGAwGoyJd/0Qwk4TttFXUOHJ2ZJQe/52ScaUwtQ==",
"dependencies": {
"bson": "^5.5.0",
"mongodb-connection-string-url": "^2.6.0",
@@ -17592,9 +17624,9 @@
}
},
"node_modules/path-to-regexp": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
"integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
"version": "0.1.10",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz",
"integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w=="
},
"node_modules/path-type": {
"version": "1.1.0",
@@ -19337,9 +19369,9 @@
}
},
"node_modules/send": {
"version": "0.18.0",
"resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
"integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
"version": "0.19.0",
"resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
"integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
"dependencies": {
"debug": "2.6.9",
"depd": "2.0.0",
@@ -19372,6 +19404,14 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
"node_modules/send/node_modules/encodeurl": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
"integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/send/node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@@ -19386,14 +19426,14 @@
}
},
"node_modules/serve-static": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
"integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
"version": "1.16.2",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
"integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
"dependencies": {
"encodeurl": "~1.0.2",
"encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"parseurl": "~1.3.3",
"send": "0.18.0"
"send": "0.19.0"
},
"engines": {
"node": ">= 0.8.0"
@@ -19519,11 +19559,11 @@
}
},
"node_modules/side-channel": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.5.tgz",
"integrity": "sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==",
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
"integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
"dependencies": {
"call-bind": "^1.0.6",
"call-bind": "^1.0.7",
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.4",
"object-inspect": "^1.13.1"
@@ -19861,15 +19901,15 @@
}
},
"node_modules/socks": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz",
"integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==",
"version": "2.8.3",
"resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz",
"integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==",
"dependencies": {
"ip": "^2.0.0",
"ip-address": "^9.0.5",
"smart-buffer": "^4.2.0"
},
"engines": {
"node": ">= 10.13.0",
"node": ">= 10.0.0",
"npm": ">= 3.0.0"
}
},
+6 -5
View File
@@ -1,7 +1,7 @@
{
"name": "habitica",
"description": "A habit tracker app which treats your goals like a Role Playing Game.",
"version": "5.30.0",
"version": "5.32.5",
"main": "./website/server/index.js",
"dependencies": {
"@babel/core": "^7.22.10",
@@ -17,7 +17,7 @@
"apple-auth": "^1.0.9",
"babel-preset-env": "^1.7.0",
"bcrypt": "^5.1.1",
"body-parser": "^1.20.2",
"body-parser": "^1.20.3",
"bootstrap": "^4.6.2",
"compression": "^1.7.4",
"cookie-session": "^2.0.0",
@@ -28,7 +28,7 @@
"eslint": "^8.55.0",
"eslint-config-habitrpg": "^6.2.3",
"eslint-plugin-mocha": "^5.0.0",
"express": "^4.19.2",
"express": "^4.21.1",
"express-basic-auth": "^1.2.1",
"express-validator": "^5.2.0",
"firebase-admin": "^12.1.1",
@@ -51,7 +51,7 @@
"method-override": "^3.0.0",
"moment": "^2.29.4",
"moment-recur": "^1.0.7",
"mongoose": "^7.6.3",
"mongoose": "^7.8.3",
"morgan": "^1.10.0",
"nconf": "^0.12.1",
"node-gcm": "^1.0.5",
@@ -110,6 +110,7 @@
"start:simple": "node ./website/server/index.js",
"debug": "gulp nodemon --inspect",
"mongo:dev": "run-rs -v 5.0.23 -l ubuntu1804 --keep --dbpath mongodb-data --number 1 --quiet",
"mongo:test": "run-rs -v 5.0.23 -l ubuntu1804 --keep --dbpath mongodb-data-testing --number 1 --quiet",
"postinstall": "git config --global url.\"https://\".insteadOf git:// && gulp build && cd website/client && npm install",
"apidoc": "gulp apidoc",
"heroku-postbuild": ".heroku/report_deploy.sh"
@@ -120,7 +121,7 @@
"chai-as-promised": "^7.1.1",
"chai-moment": "^0.1.0",
"chalk": "^5.3.0",
"cross-spawn": "^7.0.3",
"cross-spawn": "^7.0.5",
"mocha": "^5.1.1",
"monk": "^7.3.4",
"nyc": "^15.1.0",
@@ -51,6 +51,7 @@ describe('Stripe - Checkout', () => {
gift: undefined,
sub: undefined,
gemsBlock: gemsBlockKey,
server_url: BASE_URL,
};
expect(gems.validateGiftMessage).to.not.be.called;
@@ -101,6 +102,7 @@ describe('Stripe - Checkout', () => {
gift: JSON.stringify(gift),
sub: undefined,
gemsBlock: undefined,
server_url: BASE_URL,
};
expect(gems.validateGiftMessage).to.be.calledOnce;
@@ -155,6 +157,7 @@ describe('Stripe - Checkout', () => {
gift: JSON.stringify(gift),
sub: undefined,
gemsBlock: undefined,
server_url: BASE_URL,
};
expect(oneTimePayments.getOneTimePaymentInfo).to.be.calledOnce;
@@ -192,6 +195,7 @@ describe('Stripe - Checkout', () => {
userId: user._id,
gift: undefined,
sub: JSON.stringify(sub),
server_url: BASE_URL,
};
expect(subscriptions.checkSubData).to.be.calledOnce;
@@ -258,6 +262,7 @@ describe('Stripe - Checkout', () => {
userId: user._id,
gift: undefined,
sub: JSON.stringify(sub),
server_url: BASE_URL,
groupId,
};
@@ -328,8 +333,9 @@ describe('Stripe - Checkout', () => {
user.purchased.plan.customerId = customerId;
const metadata = {
userId: user._id,
type: 'edit-card-user',
userId: user._id,
server_url: BASE_URL,
};
const res = await createEditCardCheckoutSession({ user }, stripe);
@@ -418,6 +424,7 @@ describe('Stripe - Checkout', () => {
const metadata = {
userId: user._id,
type: 'edit-card-group',
server_url: BASE_URL,
groupId,
};
@@ -455,6 +462,7 @@ describe('Stripe - Checkout', () => {
userId: anotherUser._id,
type: 'edit-card-group',
groupId,
server_url: BASE_URL,
};
const res = await createEditCardCheckoutSession({ user: anotherUser, groupId }, stripe);
@@ -16,6 +16,7 @@ import * as subscriptions from '../../../../../../website/server/libs/payments/s
const { i18n } = common;
describe('Stripe - Webhooks', () => {
const BASE_URL = nconf.get('BASE_URL');
const stripe = stripeModule('test');
const endpointSecret = nconf.get('STRIPE_WEBHOOKS_ENDPOINT_SECRET');
const headers = {};
@@ -284,7 +285,9 @@ describe('Stripe - Webhooks', () => {
const session = {};
beforeEach(() => {
session.metadata = {};
session.metadata = {
server_url: BASE_URL,
};
event = { type: eventType, data: { object: session } };
constructEventStub = sandbox.stub(stripe.webhooks, 'constructEvent');
constructEventStub.returns(event);
@@ -59,7 +59,7 @@ describe('POST /debug/jump-time', () => {
expect(resultDate.getDate()).to.eql(today.getDate());
expect(resultDate.getMonth()).to.eql(today.getMonth());
expect(resultDate.getFullYear()).to.eql(today.getFullYear());
const newResultDate = new Date((await user.post('/debug/jump-time', { offsetDays: 355 })).time);
const newResultDate = new Date((await user.post('/debug/jump-time', { offsetDays: 365 })).time);
expect(newResultDate.getFullYear()).to.eql(today.getFullYear() + 1);
});
@@ -60,12 +60,12 @@ describe('PUT /heroes/:heroId', () => {
expect(heroRes.profile).to.have.all.keys(['name']);
// test response values
expect(heroRes.balance).to.equal(3 + 0.75); // 3+0.75 for first contrib level
expect(heroRes.balance).to.equal(3 + 2.5); // 3+2.5 for first contrib level
expect(heroRes.contributor.level).to.equal(1);
expect(heroRes.purchased.ads).to.equal(true);
// test hero values
await hero.sync();
expect(hero.balance).to.equal(3 + 0.75); // 3+0.75 for first contrib level
expect(hero.balance).to.equal(3 + 2.5); // 3+2.5 for first contrib level
expect(hero.contributor.level).to.equal(1);
expect(hero.purchased.ads).to.equal(true);
expect(hero.auth.blocked).to.equal(prevBlockState);
@@ -136,12 +136,12 @@ describe('PUT /heroes/:heroId', () => {
expect(heroRes.profile).to.have.all.keys(['name']);
// test response values
expect(heroRes.balance).to.equal(1); // 0+1 for sixth contrib level
expect(heroRes.balance).to.equal(15); // 0+15 for sixth contrib level
expect(heroRes.contributor.level).to.equal(6);
expect(heroRes.items.pets['Dragon-Hydra']).to.equal(5);
// test hero values
await hero.sync();
expect(hero.balance).to.equal(1); // 0+1 for sixth contrib level
expect(hero.balance).to.equal(15); // 0+15 for sixth contrib level
expect(hero.contributor.level).to.equal(6);
expect(hero.items.pets['Dragon-Hydra']).to.equal(5);
});
@@ -0,0 +1,56 @@
import {
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
import common from '../../../../../website/common';
describe('GET /members/username/:username', () => {
let user;
before(async () => {
user = await generateUser();
});
it('validates req.params.username', async () => {
await expect(user.get('/members/username/')).to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: t('invalidReqParams'),
});
});
it('returns a member public data only', async () => {
// make sure user has all the fields that can be returned by the getMember call
const member = await generateUser({
contributor: { level: 1 },
backer: { tier: 3 },
preferences: {
costume: false,
background: 'volcano',
},
secret: {
text: 'Clark Kent',
},
});
const memberRes = await user.get(`/members/username/${member.auth.local.username}`);
expect(memberRes).to.have.all.keys([ // works as: object has all and only these keys
'_id', 'id', 'preferences', 'profile', 'stats', 'achievements', 'party',
'backer', 'contributor', 'auth', 'items', 'inbox', 'loginIncentives', 'flags',
]);
expect(Object.keys(memberRes.auth)).to.eql(['local', 'timestamps']);
expect(Object.keys(memberRes.preferences).sort()).to.eql([
'size', 'hair', 'skin', 'shirt',
'chair', 'costume', 'sleep', 'background', 'tasks', 'disableClasses',
].sort());
expect(memberRes.stats.maxMP).to.exist;
expect(memberRes.stats.maxHealth).to.equal(common.maxHealth);
expect(memberRes.stats.toNextLevel).to.equal(common.tnl(memberRes.stats.lvl));
expect(memberRes.inbox.optOut).to.exist;
expect(memberRes.inbox.canReceive).to.exist;
expect(memberRes.inbox.messages).to.not.exist;
expect(memberRes.secret).to.not.exist;
expect(memberRes.blocks).to.not.exist;
});
});
@@ -0,0 +1,104 @@
import find from 'lodash/find';
import {
generateUser,
translate as t,
} from '../../../helpers/api-integration/v4';
/**
* Checks the messages array if the uniqueMessageId has the like flag
* @param {InboxMessage[]} messages
* @param {String} uniqueMessageId
* @param {String} userId
* @param {Boolean} likeStatus
*/
function expectMessagesLikeStatus (messages, uniqueMessageId, userId, likeStatus) {
const messageToCheck = find(messages, { uniqueMessageId });
expect(messageToCheck.likes[userId]).to.equal(likeStatus);
}
// eslint-disable-next-line mocha/no-exclusive-tests
describe('POST /inbox/like-private-message/:messageId', () => {
let userToSendMessage;
const getLikeUrl = messageId => `/inbox/like-private-message/${messageId}`;
before(async () => {
userToSendMessage = await generateUser();
});
it('Returns an error when private message is not found', async () => {
await expect(userToSendMessage.post(getLikeUrl('some-unknown-id')))
.to.eventually.be.rejected.and.eql({
code: 404,
error: 'NotFound',
message: t('messageGroupChatNotFound'),
});
});
it('Likes a message', async () => {
const receiver = await generateUser();
const sentMessageResult = await userToSendMessage.post('/members/send-private-message', {
message: 'some message :)',
toUserId: receiver._id,
});
const { uniqueMessageId } = sentMessageResult.message;
const likeResult = await receiver.post(getLikeUrl(uniqueMessageId));
expect(likeResult.likes[receiver._id]).to.equal(true);
const senderMessages = await userToSendMessage.get('/inbox/messages');
expectMessagesLikeStatus(senderMessages, uniqueMessageId, receiver._id, true);
const receiversMessages = await receiver.get('/inbox/messages');
expectMessagesLikeStatus(receiversMessages, uniqueMessageId, receiver._id, true);
});
it('Allows to likes their own private message', async () => {
const receiver = await generateUser();
const sentMessageResult = await userToSendMessage.post('/members/send-private-message', {
message: 'some message :)',
toUserId: receiver._id,
});
const { uniqueMessageId } = sentMessageResult.message;
const likeResult = await userToSendMessage.post(getLikeUrl(uniqueMessageId));
expect(likeResult.likes[userToSendMessage._id]).to.equal(true);
const messages = await userToSendMessage.get('/inbox/messages');
expectMessagesLikeStatus(messages, uniqueMessageId, userToSendMessage._id, true);
const receiversMessages = await receiver.get('/inbox/messages');
expectMessagesLikeStatus(receiversMessages, uniqueMessageId, userToSendMessage._id, true);
});
it('Unlikes a message', async () => {
const receiver = await generateUser();
const sentMessageResult = await userToSendMessage.post('/members/send-private-message', {
message: 'some message :)',
toUserId: receiver._id,
});
const { uniqueMessageId } = sentMessageResult.message;
const likeResult = await receiver.post(getLikeUrl(uniqueMessageId));
expect(likeResult.likes[receiver._id]).to.equal(true);
const unlikeResult = await receiver.post(getLikeUrl(uniqueMessageId));
expect(unlikeResult.likes[receiver._id]).to.equal(false);
const messages = await userToSendMessage.get('/inbox/messages');
const messageToCheck = find(messages, { id: sentMessageResult.message.id });
expect(messageToCheck.likes[receiver._id]).to.equal(false);
});
});
+6 -6
View File
@@ -19,8 +19,8 @@ describe('releaseDates', () => {
});
describe('armoire', () => {
it('should only contain valid armoire names', () => {
const lastReleaseDate = maxBy(Object.values(ARMOIRE_RELEASE_DATES), value => new Date(`${value.year}-${value.month + 1}-20`));
clock = sinon.useFakeTimers(new Date(`${lastReleaseDate.year}-${lastReleaseDate.month + 1}-20`));
const lastReleaseDate = maxBy(Object.values(ARMOIRE_RELEASE_DATES), value => new Date(`${value.year}-${value.month}-22`));
clock = sinon.useFakeTimers(new Date(`${lastReleaseDate.year}-${lastReleaseDate.month}-22`));
Object.keys(ARMOIRE_RELEASE_DATES).forEach(key => {
expect(find(armoire.all, { set: key }), `${key} is not a valid armoire set`).to.exist;
});
@@ -40,8 +40,8 @@ describe('releaseDates', () => {
describe('eggs', () => {
it('should only contain valid egg names', () => {
const lastReleaseDate = maxBy(Object.values(EGGS_RELEASE_DATES), value => new Date(`${value.year}-${value.month + 1}-${value.day}`));
clock = sinon.useFakeTimers(new Date(`${lastReleaseDate.year}-${lastReleaseDate.month + 1}-${lastReleaseDate.day}`));
const lastReleaseDate = maxBy(Object.values(EGGS_RELEASE_DATES), value => new Date(`${value.year}-${value.month}-${value.day}`));
clock = sinon.useFakeTimers(new Date(`${lastReleaseDate.year}-${lastReleaseDate.month}-${lastReleaseDate.day + 1}`));
Object.keys(EGGS_RELEASE_DATES).forEach(key => {
expect(eggs.all[key], `${key} is not a valid egg name`).to.exist;
});
@@ -61,8 +61,8 @@ describe('releaseDates', () => {
describe('hatchingPotions', () => {
it('should only contain valid potion names', () => {
const lastReleaseDate = maxBy(Object.values(HATCHING_POTIONS_RELEASE_DATES), value => new Date(`${value.year}-${value.month + 1}-${value.day}`));
clock = sinon.useFakeTimers(new Date(`${lastReleaseDate.year}-${lastReleaseDate.month + 1}-${lastReleaseDate.day}`));
const lastReleaseDate = maxBy(Object.values(HATCHING_POTIONS_RELEASE_DATES), value => new Date(`${value.year}-${value.month}-${value.day}`));
clock = sinon.useFakeTimers(new Date(`${lastReleaseDate.year}-${lastReleaseDate.month}-${lastReleaseDate.day + 1}`));
Object.keys(HATCHING_POTIONS_RELEASE_DATES).forEach(key => {
expect(hatchingPotions.all[key], `${key} is not a valid potion name`).to.exist;
});
+34 -2
View File
@@ -1,4 +1,5 @@
// eslint-disable-next-line max-len
import maxBy from 'lodash/maxBy';
import moment from 'moment';
import nconf from 'nconf';
import {
@@ -10,6 +11,7 @@ import QUEST_BUNDLES from '../../website/common/script/content/bundles';
import potions from '../../website/common/script/content/hatching-potions';
import SPELLS from '../../website/common/script/content/spells';
import QUEST_SEASONAL from '../../website/common/script/content/quests/seasonal';
import { HATCHING_POTIONS_RELEASE_DATES } from '../../website/common/script/content/constants/releaseDates';
function validateMatcher (matcher, checkedDate) {
expect(matcher.end).to.be.a('date');
@@ -142,6 +144,12 @@ describe('Content Schedule', () => {
expect(matchers.seasonalGear.end).to.eql(moment.utc(`2025-03-21T${String(switchoverTime).padStart(2, '0')}:00:00.000Z`).toDate());
});
it('sets the end date in new year for a winter gala', () => {
const date = new Date('2025-01-04');
const matchers = getAllScheduleMatchingGroups(date);
expect(matchers.seasonalGear.end).to.eql(moment.utc(`2025-03-21T${String(switchoverTime).padStart(2, '0')}:00:00.000Z`).toDate());
});
it('uses correct date for first hours of the month', () => {
// if the date is checked before CONTENT_SWITCHOVER_TIME_OFFSET,
// it should be considered the previous month
@@ -222,6 +230,8 @@ describe('Content Schedule', () => {
});
it('premium hatching potions', () => {
const lastReleaseDate = maxBy(Object.values(HATCHING_POTIONS_RELEASE_DATES), value => new Date(`${value.year}-${value.month}-${value.day}`));
clock = sinon.useFakeTimers(new Date(`${lastReleaseDate.year}-${lastReleaseDate.month}-${lastReleaseDate.day + 1}`));
const potionKeys = Object.keys(potions.premium);
Object.keys(MONTHLY_SCHEDULE).forEach(key => {
const monthlyPotions = MONTHLY_SCHEDULE[key][21].find(item => item.type === 'premiumHatchingPotions');
@@ -262,6 +272,21 @@ describe('Content Schedule', () => {
expect(matcher.match('backgroundkey072024')).to.be.true;
});
it('allows background matching the month for new backgrounds from multiple years', () => {
const date = new Date('2026-07-08');
const matcher = getAllScheduleMatchingGroups(date).backgrounds;
expect(matcher.match('backgroundkey072024')).to.be.true;
expect(matcher.match('backgroundkey072025')).to.be.true;
expect(matcher.match('backgroundkey072026')).to.be.true;
});
it('allows background matching the previous month in the first week for new backgrounds', () => {
const date = new Date('2024-09-02');
const matcher = getAllScheduleMatchingGroups(date).backgrounds;
expect(matcher.match('backgroundkey082024')).to.be.true;
expect(matcher.match('backgroundkey092024')).to.be.false;
});
it('disallows background in the future', () => {
const date = new Date('2024-07-08');
const matcher = getAllScheduleMatchingGroups(date).backgrounds;
@@ -281,19 +306,26 @@ describe('Content Schedule', () => {
expect(matcher.match('backgroundkey022021')).to.be.true;
});
it('allows background even yeared backgrounds in first half of year', () => {
it('allows even yeared backgrounds in first half of year', () => {
const date = new Date('2025-02-08');
const matcher = getAllScheduleMatchingGroups(date).backgrounds;
expect(matcher.match('backgroundkey022024')).to.be.true;
expect(matcher.match('backgroundkey082022')).to.be.true;
});
it('allows background odd yeared backgrounds in second half of year', () => {
it('allows odd yeared backgrounds in second half of year', () => {
const date = new Date('2024-08-08');
const matcher = getAllScheduleMatchingGroups(date).backgrounds;
expect(matcher.match('backgroundkey022023')).to.be.true;
expect(matcher.match('backgroundkey082021')).to.be.true;
});
it('allows odd yeared backgrounds in beginning of january', () => {
const date = new Date('2025-01-06');
const matcher = getAllScheduleMatchingGroups(date).backgrounds;
expect(matcher.match('backgroundkey122024'), 'backgroundkey122024').to.be.true;
expect(matcher.match('backgroundkey062023'), 'backgroundkey062022').to.be.true;
});
});
describe('timeTravelers matcher', () => {
+1 -1
View File
@@ -7,7 +7,7 @@ module.exports = {
extends: [
'habitrpg/lib/vue',
],
ignorePatterns: ['dist/', 'node_modules/'],
ignorePatterns: ['dist/', 'node_modules/', '*.d.ts'],
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
+210 -76
View File
@@ -3934,9 +3934,9 @@
"integrity": "sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w=="
},
"node_modules/body-parser": {
"version": "1.20.2",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
"integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
"version": "1.20.3",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
"integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
"dependencies": {
"bytes": "3.1.2",
"content-type": "~1.0.5",
@@ -3946,7 +3946,7 @@
"http-errors": "2.0.0",
"iconv-lite": "0.4.24",
"on-finished": "2.4.1",
"qs": "6.11.0",
"qs": "6.13.0",
"raw-body": "2.5.2",
"type-is": "~1.6.18",
"unpipe": "1.0.0"
@@ -4140,6 +4140,33 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/call-bind-apply-helpers": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz",
"integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==",
"dependencies": {
"es-errors": "^1.3.0",
"function-bind": "^1.1.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/call-bound": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz",
"integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==",
"dependencies": {
"call-bind-apply-helpers": "^1.0.1",
"get-intrinsic": "^1.2.6"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/callsites": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
@@ -4616,9 +4643,9 @@
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="
},
"node_modules/cookie": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
"integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz",
"integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==",
"engines": {
"node": ">= 0.6"
}
@@ -5422,6 +5449,19 @@
"resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz",
"integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA=="
},
"node_modules/dunder-proto": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.0.tgz",
"integrity": "sha512-9+Sj30DIu+4KvHqMfLUGLFYL2PkURSYMVXJyXe92nFRvlYq5hBjLEhblKB+vkd/WVlUYMWigiY07T91Fkk0+4A==",
"dependencies": {
"call-bind-apply-helpers": "^1.0.0",
"es-errors": "^1.3.0",
"gopd": "^1.2.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/duplexer": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
@@ -5464,9 +5504,9 @@
}
},
"node_modules/encodeurl": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
"integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
"integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
"engines": {
"node": ">= 0.8"
}
@@ -5588,12 +5628,9 @@
}
},
"node_modules/es-define-property": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
"integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
"dependencies": {
"get-intrinsic": "^1.2.4"
},
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
"engines": {
"node": ">= 0.4"
}
@@ -5611,6 +5648,17 @@
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz",
"integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w=="
},
"node_modules/es-object-atoms": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz",
"integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==",
"dependencies": {
"es-errors": "^1.3.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-set-tostringtag": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz",
@@ -6695,36 +6743,36 @@
}
},
"node_modules/express": {
"version": "4.19.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz",
"integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==",
"version": "4.21.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
"integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
"dependencies": {
"accepts": "~1.3.8",
"array-flatten": "1.1.1",
"body-parser": "1.20.2",
"body-parser": "1.20.3",
"content-disposition": "0.5.4",
"content-type": "~1.0.4",
"cookie": "0.6.0",
"cookie": "0.7.1",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
"depd": "2.0.0",
"encodeurl": "~1.0.2",
"encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"finalhandler": "1.2.0",
"finalhandler": "1.3.1",
"fresh": "0.5.2",
"http-errors": "2.0.0",
"merge-descriptors": "1.0.1",
"merge-descriptors": "1.0.3",
"methods": "~1.1.2",
"on-finished": "2.4.1",
"parseurl": "~1.3.3",
"path-to-regexp": "0.1.7",
"path-to-regexp": "0.1.12",
"proxy-addr": "~2.0.7",
"qs": "6.11.0",
"qs": "6.13.0",
"range-parser": "~1.2.1",
"safe-buffer": "5.2.1",
"send": "0.18.0",
"serve-static": "1.15.0",
"send": "0.19.0",
"serve-static": "1.16.2",
"setprototypeof": "1.2.0",
"statuses": "2.0.1",
"type-is": "~1.6.18",
@@ -6733,6 +6781,10 @@
},
"engines": {
"node": ">= 0.10.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/express/node_modules/array-flatten": {
@@ -6877,12 +6929,12 @@
}
},
"node_modules/finalhandler": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
"integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
"integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
"dependencies": {
"debug": "2.6.9",
"encodeurl": "~1.0.2",
"encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"on-finished": "2.4.1",
"parseurl": "~1.3.3",
@@ -7125,15 +7177,20 @@
}
},
"node_modules/get-intrinsic": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
"integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.6.tgz",
"integrity": "sha512-qxsEs+9A+u85HhllWJJFicJfPDhRmjzoYdl64aMWW9yRIJmSyxdn8IEkuIM530/7T+lv0TIHd8L6Q/ra0tEoeA==",
"dependencies": {
"call-bind-apply-helpers": "^1.0.1",
"dunder-proto": "^1.0.0",
"es-define-property": "^1.0.1",
"es-errors": "^1.3.0",
"es-object-atoms": "^1.0.0",
"function-bind": "^1.1.2",
"has-proto": "^1.0.1",
"has-symbols": "^1.0.3",
"hasown": "^2.0.0"
"gopd": "^1.2.0",
"has-symbols": "^1.1.0",
"hasown": "^2.0.2",
"math-intrinsics": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
@@ -7253,11 +7310,11 @@
}
},
"node_modules/gopd": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
"integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
"dependencies": {
"get-intrinsic": "^1.1.3"
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
@@ -7353,9 +7410,9 @@
}
},
"node_modules/has-symbols": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
"engines": {
"node": ">= 0.4"
},
@@ -7383,9 +7440,9 @@
"integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg=="
},
"node_modules/hasown": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz",
"integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==",
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
"dependencies": {
"function-bind": "^1.1.2"
},
@@ -8919,6 +8976,14 @@
"markdown-it": "bin/markdown-it.js"
}
},
"node_modules/math-intrinsics": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.0.0.tgz",
"integrity": "sha512-4MqMiKP90ybymYvsut0CH2g4XWbfLtmlCkXmtmdcDCxNB+mQcu1w/1+L/VD7vi/PSv7X2JYV7SCcR+jiPXnQtA==",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/mdn-data": {
"version": "2.0.14",
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
@@ -8958,9 +9023,12 @@
}
},
"node_modules/merge-descriptors": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
"integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
"integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/merge-source-map": {
"version": "1.1.0",
@@ -9862,9 +9930,12 @@
}
},
"node_modules/object-inspect": {
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz",
"integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==",
"version": "1.13.3",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz",
"integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
@@ -10310,9 +10381,9 @@
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
},
"node_modules/path-to-regexp": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
"integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
"version": "0.1.12",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
"integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ=="
},
"node_modules/path-type": {
"version": "4.0.0",
@@ -11129,11 +11200,11 @@
}
},
"node_modules/qs": {
"version": "6.11.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
"integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
"version": "6.13.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
"integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
"dependencies": {
"side-channel": "^1.0.4"
"side-channel": "^1.0.6"
},
"engines": {
"node": ">=0.6"
@@ -11736,9 +11807,9 @@
"dev": true
},
"node_modules/send": {
"version": "0.18.0",
"resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
"integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
"version": "0.19.0",
"resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
"integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
"dependencies": {
"debug": "2.6.9",
"depd": "2.0.0",
@@ -11771,6 +11842,14 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
"node_modules/send/node_modules/encodeurl": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
"integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/send/node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@@ -11855,14 +11934,14 @@
}
},
"node_modules/serve-static": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
"integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
"version": "1.16.2",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
"integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
"dependencies": {
"encodeurl": "~1.0.2",
"encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"parseurl": "~1.3.3",
"send": "0.18.0"
"send": "0.19.0"
},
"engines": {
"node": ">= 0.8.0"
@@ -11951,13 +12030,68 @@
}
},
"node_modules/side-channel": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
"integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
"integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
"dependencies": {
"call-bind": "^1.0.0",
"get-intrinsic": "^1.0.2",
"object-inspect": "^1.9.0"
"es-errors": "^1.3.0",
"object-inspect": "^1.13.3",
"side-channel-list": "^1.0.0",
"side-channel-map": "^1.0.1",
"side-channel-weakmap": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/side-channel-list": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
"integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
"dependencies": {
"es-errors": "^1.3.0",
"object-inspect": "^1.13.3"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/side-channel-map": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
"integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
"dependencies": {
"call-bound": "^1.0.2",
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.5",
"object-inspect": "^1.13.3"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/side-channel-weakmap": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
"integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
"dependencies": {
"call-bound": "^1.0.2",
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.5",
"object-inspect": "^1.13.3",
"side-channel-map": "^1.0.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
@@ -1085,6 +1085,11 @@
width: 141px;
height: 147px;
}
.background_first_snow_forest {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_first_snow_forest.png');
width: 141px;
height: 147px;
}
.background_floating_islands {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_floating_islands.png');
width: 141px;
@@ -2391,6 +2396,11 @@
width: 141px;
height: 147px;
}
.background_winter_landscape_with_cabin {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_winter_landscape_with_cabin.png');
width: 141px;
height: 147px;
}
.background_winter_mountain_range {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_winter_mountain_range.png');
width: 141px;
@@ -29624,6 +29634,11 @@
width: 90px;
height: 90px;
}
.broad_armor_armoire_festiveHelperOveralls {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_armoire_festiveHelperOveralls.png');
width: 114px;
height: 90px;
}
.broad_armor_armoire_fiddlersCoat {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_armoire_fiddlersCoat.png');
width: 114px;
@@ -29894,6 +29909,11 @@
width: 114px;
height: 90px;
}
.broad_armor_armoire_snowyFluffTrimmedCoat {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_armoire_snowyFluffTrimmedCoat.png');
width: 114px;
height: 90px;
}
.broad_armor_armoire_softBlackSuit {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_armoire_softBlackSuit.png');
width: 114px;
@@ -30199,6 +30219,11 @@
width: 114px;
height: 90px;
}
.head_armoire_festiveHelperHat {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_armoire_festiveHelperHat.png');
width: 114px;
height: 90px;
}
.head_armoire_fiddlersCap {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_armoire_fiddlersCap.png');
width: 114px;
@@ -30454,6 +30479,11 @@
width: 117px;
height: 120px;
}
.head_armoire_snowyTrapperHat {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_armoire_snowyTrapperHat.png');
width: 114px;
height: 90px;
}
.head_armoire_stormKnightHelm {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_armoire_stormKnightHelm.png');
width: 114px;
@@ -31099,6 +31129,11 @@
width: 90px;
height: 90px;
}
.slim_armor_armoire_festiveHelperOveralls {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_armoire_festiveHelperOveralls.png');
width: 114px;
height: 90px;
}
.slim_armor_armoire_fiddlersCoat {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_armoire_fiddlersCoat.png');
width: 114px;
@@ -31369,6 +31404,11 @@
width: 114px;
height: 90px;
}
.slim_armor_armoire_snowyFluffTrimmedCoat {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_armoire_snowyFluffTrimmedCoat.png');
width: 114px;
height: 90px;
}
.slim_armor_armoire_softBlackSuit {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_armoire_softBlackSuit.png');
width: 114px;
@@ -33679,6 +33719,16 @@
width: 90px;
height: 90px;
}
.head_mystery_202501 {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_mystery_202501.png');
width: 114px;
height: 90px;
}
.shield_mystery_202501 {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_mystery_202501.png');
width: 114px;
height: 90px;
}
.back_mystery_201402 {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/back_mystery_201402.png');
width: 90px;
@@ -35339,6 +35389,21 @@
width: 114px;
height: 90px;
}
.broad_armor_mystery_202412 {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_mystery_202412.png');
width: 114px;
height: 90px;
}
.head_mystery_202412 {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_mystery_202412.png');
width: 114px;
height: 90px;
}
.slim_armor_mystery_202412 {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_mystery_202412.png');
width: 114px;
height: 90px;
}
.broad_armor_mystery_301404 {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_mystery_301404.png');
width: 90px;
@@ -37904,6 +37969,26 @@
width: 114px;
height: 90px;
}
.broad_armor_special_winter2025Healer {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_special_winter2025Healer.png');
width: 114px;
height: 90px;
}
.broad_armor_special_winter2025Mage {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_special_winter2025Mage.png');
width: 114px;
height: 90px;
}
.broad_armor_special_winter2025Rogue {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_special_winter2025Rogue.png');
width: 114px;
height: 90px;
}
.broad_armor_special_winter2025Warrior {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_special_winter2025Warrior.png');
width: 114px;
height: 90px;
}
.broad_armor_special_yeti {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_special_yeti.png');
width: 90px;
@@ -38179,6 +38264,26 @@
width: 114px;
height: 90px;
}
.head_special_winter2025Healer {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_special_winter2025Healer.png');
width: 114px;
height: 90px;
}
.head_special_winter2025Mage {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_special_winter2025Mage.png');
width: 114px;
height: 90px;
}
.head_special_winter2025Rogue {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_special_winter2025Rogue.png');
width: 114px;
height: 90px;
}
.head_special_winter2025Warrior {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_special_winter2025Warrior.png');
width: 114px;
height: 90px;
}
.head_special_yeti {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_special_yeti.png');
width: 90px;
@@ -38344,6 +38449,21 @@
width: 114px;
height: 90px;
}
.shield_special_winter2025Healer {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_special_winter2025Healer.png');
width: 114px;
height: 90px;
}
.shield_special_winter2025Rogue {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_special_winter2025Rogue.png');
width: 114px;
height: 90px;
}
.shield_special_winter2025Warrior {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_special_winter2025Warrior.png');
width: 114px;
height: 90px;
}
.shield_special_yeti {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_special_yeti.png');
width: 90px;
@@ -38564,6 +38684,26 @@
width: 114px;
height: 90px;
}
.slim_armor_special_winter2025Healer {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_special_winter2025Healer.png');
width: 114px;
height: 90px;
}
.slim_armor_special_winter2025Mage {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_special_winter2025Mage.png');
width: 114px;
height: 90px;
}
.slim_armor_special_winter2025Rogue {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_special_winter2025Rogue.png');
width: 114px;
height: 90px;
}
.slim_armor_special_winter2025Warrior {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_special_winter2025Warrior.png');
width: 114px;
height: 90px;
}
.slim_armor_special_yeti {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_special_yeti.png');
width: 90px;
@@ -38784,6 +38924,26 @@
width: 114px;
height: 90px;
}
.weapon_special_winter2025Healer {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_special_winter2025Healer.png');
width: 114px;
height: 90px;
}
.weapon_special_winter2025Mage {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_special_winter2025Mage.png');
width: 114px;
height: 90px;
}
.weapon_special_winter2025Rogue {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_special_winter2025Rogue.png');
width: 114px;
height: 90px;
}
.weapon_special_winter2025Warrior {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_special_winter2025Warrior.png');
width: 114px;
height: 90px;
}
.weapon_special_yeti {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_special_yeti.png');
width: 90px;
@@ -39937,6 +40097,66 @@
width: 28px;
height: 28px;
}
.notif_2013hat_nye {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/notif_2013hat_nye.png');
width: 28px;
height: 28px;
}
.notif_2014hat_nye {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/notif_2014hat_nye.png');
width: 28px;
height: 28px;
}
.notif_2015hat_nye {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/notif_2015hat_nye.png');
width: 28px;
height: 28px;
}
.notif_2016hat_nye {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/notif_2016hat_nye.png');
width: 28px;
height: 28px;
}
.notif_2017hat_nye {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/notif_2017hat_nye.png');
width: 28px;
height: 28px;
}
.notif_2018hat_nye {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/notif_2018hat_nye.png');
width: 28px;
height: 28px;
}
.notif_2019hat_nye {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/notif_2019hat_nye.png');
width: 28px;
height: 28px;
}
.notif_2020hat_nye {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/notif_2020hat_nye.png');
width: 28px;
height: 28px;
}
.notif_2021hat_nye {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/notif_2021hat_nye.png');
width: 28px;
height: 28px;
}
.notif_2022hat_nye {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/notif_2022hat_nye.png');
width: 28px;
height: 28px;
}
.notif_2023hat_nye {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/notif_2023hat_nye.png');
width: 28px;
height: 28px;
}
.notif_candy_nye {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/notif_candy_nye.png');
width: 28px;
height: 28px;
}
.notif_habitoween_base_mount {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/notif_habitoween_base_mount.png');
width: 28px;
@@ -39982,6 +40202,41 @@
width: 28px;
height: 28px;
}
.notif_harvestfeast_base_mount {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/notif_harvestfeast_base_mount.png');
width: 28px;
height: 28px;
}
.notif_harvestfeast_base_pet {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/notif_harvestfeast_base_pet.png');
width: 28px;
height: 28px;
}
.notif_harvestfeast_base_set {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/notif_harvestfeast_base_set.png');
width: 28px;
height: 28px;
}
.notif_harvestfeast_gilded_mount {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/notif_harvestfeast_gilded_mount.png');
width: 28px;
height: 28px;
}
.notif_harvestfeast_gilded_pet {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/notif_harvestfeast_gilded_pet.png');
width: 28px;
height: 28px;
}
.notif_harvestfeast_gilded_set {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/notif_harvestfeast_gilded_set.png');
width: 28px;
height: 28px;
}
.notif_harvestfeast_pie {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/notif_harvestfeast_pie.png');
width: 28px;
height: 28px;
}
.notif_head_special_nye {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/notif_head_special_nye.png');
width: 28px;
@@ -40127,6 +40382,11 @@
width: 28px;
height: 28px;
}
.notif_subscriber_reward {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/notif_subscriber_reward.png');
width: 28px;
height: 28px;
}
.npc_bailey {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/npc_bailey.png');
width: 60px;
@@ -41997,6 +42257,11 @@
width: 105px;
height: 105px;
}
.Mount_Body_BearCub-Gingerbread {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_BearCub-Gingerbread.png');
width: 105px;
height: 105px;
}
.Mount_Body_BearCub-Glass {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_BearCub-Glass.png');
width: 105px;
@@ -42437,6 +42702,11 @@
width: 105px;
height: 105px;
}
.Mount_Body_Cactus-Gingerbread {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_Cactus-Gingerbread.png');
width: 105px;
height: 105px;
}
.Mount_Body_Cactus-Glass {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_Cactus-Glass.png');
width: 105px;
@@ -43122,6 +43392,11 @@
width: 105px;
height: 105px;
}
.Mount_Body_Dragon-Gingerbread {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_Dragon-Gingerbread.png');
width: 105px;
height: 105px;
}
.Mount_Body_Dragon-Glass {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_Dragon-Glass.png');
width: 105px;
@@ -43557,6 +43832,11 @@
width: 105px;
height: 105px;
}
.Mount_Body_FlyingPig-Gingerbread {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_FlyingPig-Gingerbread.png');
width: 105px;
height: 105px;
}
.Mount_Body_FlyingPig-Glass {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_FlyingPig-Glass.png');
width: 105px;
@@ -43842,6 +44122,11 @@
width: 105px;
height: 105px;
}
.Mount_Body_Fox-Gingerbread {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_Fox-Gingerbread.png');
width: 105px;
height: 105px;
}
.Mount_Body_Fox-Glass {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_Fox-Glass.png');
width: 105px;
@@ -44567,6 +44852,11 @@
width: 105px;
height: 105px;
}
.Mount_Body_LionCub-Gingerbread {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_LionCub-Gingerbread.png');
width: 105px;
height: 105px;
}
.Mount_Body_LionCub-Glass {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_LionCub-Glass.png');
width: 105px;
@@ -45072,6 +45362,11 @@
width: 105px;
height: 105px;
}
.Mount_Body_PandaCub-Gingerbread {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_PandaCub-Gingerbread.png');
width: 105px;
height: 105px;
}
.Mount_Body_PandaCub-Glass {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_PandaCub-Glass.png');
width: 105px;
@@ -46362,6 +46657,11 @@
width: 105px;
height: 105px;
}
.Mount_Body_TigerCub-Gingerbread {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_TigerCub-Gingerbread.png');
width: 105px;
height: 105px;
}
.Mount_Body_TigerCub-Glass {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_TigerCub-Glass.png');
width: 105px;
@@ -46957,6 +47257,11 @@
width: 135px;
height: 135px;
}
.Mount_Body_Wolf-Gingerbread {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_Wolf-Gingerbread.png');
width: 135px;
height: 135px;
}
.Mount_Body_Wolf-Glass {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_Wolf-Glass.png');
width: 135px;
@@ -47492,6 +47797,11 @@
width: 105px;
height: 105px;
}
.Mount_Head_BearCub-Gingerbread {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_BearCub-Gingerbread.png');
width: 105px;
height: 105px;
}
.Mount_Head_BearCub-Glass {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_BearCub-Glass.png');
width: 105px;
@@ -47932,6 +48242,11 @@
width: 105px;
height: 105px;
}
.Mount_Head_Cactus-Gingerbread {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_Cactus-Gingerbread.png');
width: 105px;
height: 105px;
}
.Mount_Head_Cactus-Glass {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_Cactus-Glass.png');
width: 105px;
@@ -48617,6 +48932,11 @@
width: 105px;
height: 105px;
}
.Mount_Head_Dragon-Gingerbread {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_Dragon-Gingerbread.png');
width: 105px;
height: 105px;
}
.Mount_Head_Dragon-Glass {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_Dragon-Glass.png');
width: 105px;
@@ -49052,6 +49372,11 @@
width: 105px;
height: 105px;
}
.Mount_Head_FlyingPig-Gingerbread {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_FlyingPig-Gingerbread.png');
width: 105px;
height: 105px;
}
.Mount_Head_FlyingPig-Glass {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_FlyingPig-Glass.png');
width: 105px;
@@ -49337,6 +49662,11 @@
width: 105px;
height: 105px;
}
.Mount_Head_Fox-Gingerbread {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_Fox-Gingerbread.png');
width: 105px;
height: 105px;
}
.Mount_Head_Fox-Glass {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_Fox-Glass.png');
width: 105px;
@@ -50062,6 +50392,11 @@
width: 105px;
height: 105px;
}
.Mount_Head_LionCub-Gingerbread {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_LionCub-Gingerbread.png');
width: 105px;
height: 105px;
}
.Mount_Head_LionCub-Glass {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_LionCub-Glass.png');
width: 105px;
@@ -50567,6 +50902,11 @@
width: 105px;
height: 105px;
}
.Mount_Head_PandaCub-Gingerbread {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_PandaCub-Gingerbread.png');
width: 105px;
height: 105px;
}
.Mount_Head_PandaCub-Glass {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_PandaCub-Glass.png');
width: 105px;
@@ -51857,6 +52197,11 @@
width: 105px;
height: 105px;
}
.Mount_Head_TigerCub-Gingerbread {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_TigerCub-Gingerbread.png');
width: 105px;
height: 105px;
}
.Mount_Head_TigerCub-Glass {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_TigerCub-Glass.png');
width: 105px;
@@ -52452,6 +52797,11 @@
width: 135px;
height: 135px;
}
.Mount_Head_Wolf-Gingerbread {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_Wolf-Gingerbread.png');
width: 135px;
height: 135px;
}
.Mount_Head_Wolf-Glass {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_Wolf-Glass.png');
width: 135px;
@@ -53002,6 +53352,11 @@
width: 81px;
height: 99px;
}
.Pet-BearCub-Gingerbread {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-BearCub-Gingerbread.png');
width: 78px;
height: 96px;
}
.Pet-BearCub-Glass {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-BearCub-Glass.png');
width: 81px;
@@ -53467,6 +53822,11 @@
width: 81px;
height: 99px;
}
.Pet-Cactus-Gingerbread {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-Cactus-Gingerbread.png');
width: 78px;
height: 96px;
}
.Pet-Cactus-Glass {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-Cactus-Glass.png');
width: 81px;
@@ -54182,6 +54542,11 @@
width: 81px;
height: 99px;
}
.Pet-Dragon-Gingerbread {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-Dragon-Gingerbread.png');
width: 78px;
height: 96px;
}
.Pet-Dragon-Glass {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-Dragon-Glass.png');
width: 81px;
@@ -54652,6 +55017,11 @@
width: 81px;
height: 99px;
}
.Pet-FlyingPig-Gingerbread {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-FlyingPig-Gingerbread.png');
width: 78px;
height: 96px;
}
.Pet-FlyingPig-Glass {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-FlyingPig-Glass.png');
width: 81px;
@@ -54962,6 +55332,11 @@
width: 81px;
height: 99px;
}
.Pet-Fox-Gingerbread {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-Fox-Gingerbread.png');
width: 78px;
height: 96px;
}
.Pet-Fox-Glass {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-Fox-Glass.png');
width: 81px;
@@ -55717,6 +56092,11 @@
width: 81px;
height: 99px;
}
.Pet-LionCub-Gingerbread {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-LionCub-Gingerbread.png');
width: 78px;
height: 96px;
}
.Pet-LionCub-Glass {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-LionCub-Glass.png');
width: 81px;
@@ -56247,6 +56627,11 @@
width: 81px;
height: 99px;
}
.Pet-PandaCub-Gingerbread {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-PandaCub-Gingerbread.png');
width: 78px;
height: 96px;
}
.Pet-PandaCub-Glass {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-PandaCub-Glass.png');
width: 81px;
@@ -57567,6 +57952,11 @@
width: 81px;
height: 99px;
}
.Pet-TigerCub-Gingerbread {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-TigerCub-Gingerbread.png');
width: 78px;
height: 96px;
}
.Pet-TigerCub-Glass {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-TigerCub-Glass.png');
width: 81px;
@@ -58187,6 +58577,11 @@
width: 81px;
height: 99px;
}
.Pet-Wolf-Gingerbread {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-Wolf-Gingerbread.png');
width: 78px;
height: 96px;
}
.Pet-Wolf-Glass {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-Wolf-Glass.png');
width: 81px;
+89 -44
View File
@@ -3,9 +3,9 @@
font-family: 'Roboto', sans-serif;
font-size: 14px;
font-weight: bold;
line-height: 1.71;
border: 1px solid transparent;
padding: 4px 12px;
line-height: 1.714;
border: 2px solid transparent;
padding: 2px 12px;
border-radius: 4px;
box-shadow: 0 1px 3px 0 rgba($black, 0.12), 0 1px 2px 0 rgba($black, 0.24);
color: $white;
@@ -19,7 +19,7 @@
}
&:focus {
border-color: $purple-400;
box-shadow: 0 3px 6px 0 rgba($black, 0.16), 0 3px 6px 0 rgba($black, 0.24);
}
&:active, &.active:not(.btn-flat) {
@@ -30,9 +30,9 @@
cursor: default;
color: $gray-50;
opacity: 0.75;
box-shadow: 0 1px 3px 0 rgba(26, 24, 29, 0.12), 0 1px 2px 0 rgba(26, 24, 29, 0.24);
box-shadow: none;
background-color: $gray-700;
border: 1px solid transparent;
border: 2px solid transparent;
.svg {
color: $gray-300;
@@ -40,7 +40,7 @@
}
&.with-icon {
height: 2rem; // otherwise would something set the height to 33px
height: 32px; // otherwise would something set the height to 33px
display: flex;
flex-direction: row;
align-items: center;
@@ -48,40 +48,47 @@
}
.btn-front {
border: none !important;
font-size: 16px;
line-height: 1.5;
padding: 7.5px 15.5px;
padding: 2px 17px;
&:hover {
border: none !important;
}
}
.btn-primary {
background: $purple-200;
border: 1px solid transparent;
border: 2px solid transparent;
line-height: 1.714;
--icon-color: #{$purple-500};
&:focus {
background: $purple-200;
border-color: $purple-400;
border: 2px solid $purple-400;
box-shadow: 0 3px 6px 0 rgba($black, 0.16), 0 3px 6px 0 rgba($black, 0.24);
--icon-color: #{$white};
}
&:not(:disabled):not(.disabled) {
&:hover {
background: #5d3b9c;
border: 1px solid transparent;
background: $purple-200;
border: 2px solid transparent;
--icon-color: #{$white};
}
&:active, &.active {
background: $purple-200;
border: 1px solid transparent;
border: 2px solid transparent;
box-shadow: none;
--icon-color: #{$white};
}
&:active:focus, &.active:focus {
box-shadow: none;
border-color: $purple-400;
border: 2px solid $purple-400;
}
}
@@ -94,42 +101,45 @@
.btn-secondary,
.dropdown > .btn-secondary.dropdown-toggle:not(.btn-success),
.show > .btn-secondary.dropdown-toggle:not(.btn-success)
{
.show > .btn-secondary.dropdown-toggle:not(.btn-success) {
background: $white;
border: 1px solid transparent;
border: 2px solid transparent;
color: $gray-50;
--icon-color: #{$gray-200};
&:focus, &:active {
color: $gray-50;
background: $white;
border-color: $purple-400;
border: 2px solid $purple-400;
color: $gray-50;
--icon-color: #{$purple-300};
}
&:not(:disabled):not(.disabled) {
&:active, &.active {
background: $white;
border: 2px solid $purple-400;
color: $purple-300;
--icon-color: #{$purple-300};
&:focus {
color: $purple-300;
box-shadow: none;
border-color: $purple-400;
border: 2px solid $purple-400;
box-shadow: 0 3px 6px 0 rgba($black, 0.16), 0 3px 6px 0 rgba($black, 0.24);
}
&:active {
box-shadow: none;
}
background: $white;
border: 1px solid transparent;
}
&:hover {
color: $purple-300;
background: $white !important;
border: 1px solid transparent;
border: 2px solid transparent;
--icon-color: #{$purple-300};
.svg {
@@ -151,91 +161,116 @@
.btn-danger {
background: $maroon-100;
border: 1px solid transparent;
border: 2px solid transparent;
box-shadow: 0 1px 3px 0 rgba($black, 0.16), 0 1px 3px 0 rgba($black, 0.24);
&:hover:not(:disabled):not(.disabled) {
background: #e14e4e;
border: 1px solid transparent;
background: $maroon-100;
border: 2px solid transparent;
box-shadow: 0 3px 6px 0 rgba($black, 0.16), 0 3px 6px 0 rgba($black, 0.24);
}
&:focus {
background: $maroon-100;
border-color: $purple-400;
border: 2px solid $purple-400;
}
&:not(:disabled):not(.disabled):active:focus, &:not(:disabled):not(.disabled).active:focus {
box-shadow: none;
border-color: $purple-400;
border: 2px solid $purple-400;
}
&:not(:disabled):not(.disabled):active, &:not(:disabled):not(.disabled).active {
background: $maroon-100;
border: 1px solid transparent;
border: 2px solid $purple-400;
}
}
.btn-warning {
background: $orange-10;
box-shadow: 0 1px 3px 0 rgba($black, 0.16), 0 1px 3px 0 rgba($black, 0.24);
color: $white !important;
&:hover:not(:disabled):not(.disabled) {
background: $orange-100;
background: $orange-10;
color: $white;
}
&:focus {
background: $orange-10;
border-color: $purple-400;
border: 2px solid $purple-400;
}
&:not(:disabled):not(.disabled):active:focus, &:not(:disabled):not(.disabled).active:focus {
border: 2px solid $purple-400;
box-shadow: none;
border-color: $purple-400;
}
&:not(:disabled):not(.disabled):active, &:not(:disabled):not(.disabled).active {
background: $orange-10;
box-shadow: none;
}
}
.btn-success {
background: $green-50;
border: 1px solid transparent;
border: 2px solid transparent;
&:hover:not(:disabled):not(.disabled) {
background: #32bd8a;
border: 1px solid transparent;
background: $green-50;
border: 2px solid transparent;
box-shadow: 0 3px 6px 0 rgba($black, 0.16), 0 3px 6px 0 rgba($black, 0.24);
}
&:focus {
background: $green-50;
border-color: $purple-400;
border: 2px solid $purple-400;
box-shadow: 0 3px 6px 0 rgba($black, 0.16), 0 3px 6px 0 rgba($black, 0.24);
}
&:not(:disabled):not(.disabled):active:focus, &:not(:disabled):not(.disabled).active:focus {
border: 2px solid $purple-400;
box-shadow: none;
border-color: $purple-400;
}
&:not(:disabled):not(.disabled):active, &:not(:disabled):not(.disabled).active {
background: $green-50;
border: 1px solid transparent;
border: 2px solid $purple-400;
box-shadow: none;
}
}
.btn-info {
background: $blue-50;
border: 2px solid transparent;
box-shadow: 0 1px 3px 0 rgba($black, 0.16), 0 1px 3px 0 rgba($black, 0.24);
&:disabled {
background: $blue-50;
box-shadow: none;
}
&:hover {
border: 2px solid transparent;
box-shadow: 0 3px 6px 0 rgba($black, 0.16), 0 3px 6px 0 rgba($black, 0.24);
}
&:focus {
background: $blue-100;
border: 2px solid $purple-400;
box-shadow: 0 3px 6px 0 rgba($black, 0.16), 0 3px 6px 0 rgba($black, 0.24);
}
&:hover:not(:disabled):not(.disabled) {
background-color: $blue-100;
box-shadow: 0 3px 6px 0 rgba($black, 0.16), 0 3px 6px 0 rgba($black, 0.24);
}
&:active:not(:disabled):not(.disabled), &.active:not(:disabled):not(.disabled) {
background: $blue-50;
background: $blue-100;
border: 2px solid $purple-400;
box-shadow: 0 3px 6px 0 rgba($black, 0.16), 0 3px 6px 0 rgba($black, 0.24);
}
}
@@ -244,7 +279,7 @@
width: 100%;
padding: 8px;
font-size: 14px;
line-height: 1.43;
line-height: 1.714;
font-weight: bold;
text-align: center;
background: $gray-500;
@@ -262,12 +297,22 @@
box-shadow: none;
}
.btn-flat,
.dropdown > .btn-flat.dropdown-toggle:not(.btn-success),
.show > .btn-flat.dropdown-toggle:not(.btn-success) {
&.with-icon {
.svg-icon.color {
color: var(--icon-color);
}
}
}
.btn-cancel {
color: $blue-10;
}
.btn-small {
font-size: 12px;
line-height: 1.33;
padding: 4px 8px;
line-height: 2;
padding: 2px 2px;
}
+18 -7
View File
@@ -1,8 +1,9 @@
.dropdown > .btn {
padding: 0.219rem 0.75rem;
font-family: 'Roboto', sans-serif;
font-size: 14px;
font-weight: normal;
line-height: 1.714;
padding: 2px 12px;
}
.dropdown-toggle:hover {
@@ -33,11 +34,16 @@
}
.dropdown-menu {
padding: 0px;
border: none;
border: transparent;
border-radius: 2px;
box-shadow: 0 3px 6px 0 rgba(26, 24, 29, 0.16), 0 3px 6px 0 rgba(26, 24, 29, 0.24);
box-shadow: 0 3px 6px 0 rgba($black, 0.16), 0 3px 6px 0 rgba($black, 0.24);
padding: 0;
}
.no-min-width {
.dropdown-menu {
min-width: 0 !important;
}
}
// shared dropdown-item styles
@@ -53,6 +59,8 @@
color: $gray-50 !important;
cursor: pointer;
--dropdown-item-hover-icon-color: #{$gray-200};
&:focus {
outline: none;
background-color: inherit;
@@ -87,7 +95,7 @@
&:not(:hover) {
.with-icon .svg-icon {
color: $gray-200;
color: var(dropdown-item-hover-icon-color);
}
}
}
@@ -113,6 +121,10 @@
}
.dropdown-icon-item {
line-height: 1;
padding-top: 2px !important;
padding-bottom: 2px !important;
.svg-icon {
margin: 0px 16px 0px 0px;
vertical-align: middle;
@@ -128,7 +140,6 @@
.dropdown-toggle {
width: 100% !important;
height: 32px;
text-align: left;
}
@@ -147,7 +158,7 @@
// selectList.vue items sizing
.selectListItem .dropdown-item {
padding: 0.25rem 0.75rem;
padding: 0.25rem 1rem 0.25rem 0.75rem;
height: 32px;
&:active, &:hover, &:focus, &.active {
@@ -105,6 +105,11 @@
<style lang="scss" scoped>
@import '~@/assets/scss/colors.scss';
.btn-primary:active {
border: 2px solid $purple-400 !important;
box-shadow: none !important;
}
.class-badge {
$badge-size: 32px;
@@ -7,7 +7,7 @@
:class="{'open': expand}"
@click="expand = !expand"
>
Priviliges, Gem Balance
Privileges, Gem Balance
</h3>
</div>
<div
+57 -34
View File
@@ -131,13 +131,6 @@
>{{ $t('requestFeature') }}
</a>
</li>
<li>
<a
href="https://habitica.fandom.com/"
target="_blank"
>{{ $t('wiki') }}
</a>
</li>
</ul>
</div>
<!-- Developers -->
@@ -186,7 +179,7 @@
</div>
<div class="donate-button">
<button
class="button btn-contribute"
class="btn button btn-secondary btn-contribute"
@click="donate()"
>
<div class="text">
@@ -309,7 +302,7 @@
<div class="my-2">
Time Traveling! It is {{ new Date().toLocaleDateString() }}
<a
class="btn btn-warning btn-small"
class="btn btn-small"
@click="resetTime()"
>
Reset
@@ -341,7 +334,7 @@
</button>
<div
v-if="debugMenuShown"
class="debug-toggle debug-group"
class="btn debug-toggle debug-group"
>
<div class="debug-pop">
<a
@@ -512,7 +505,14 @@ li {
grid-area: debug-pop;
}
.time-travel { grid-area: time-travel;}
.time-travel {
grid-area: time-travel;
a:hover {
text-decoration: none !important;
}
}
footer {
background-color: $gray-500;
@@ -584,42 +584,65 @@ h3 {
}
.debug {
margin-top: 16px;
border: 2px solid transparent;
box-shadow: 0 1px 3px 0 rgba($black, 0.12), 0 1px 2px 0 rgba($black, 0.24);
display: flex;
justify-content: center;
margin-top: 16px;
padding: 2px 12px;
&:hover {
box-shadow: 0 3px 6px 0 rgba($black, 0.12), 0 3px 6px 0 rgba($black, 0.24);
}
&:focus {
border: 2px solid $purple-400 !important;
box-shadow: 0 3px 6px 0 rgba($black, 0.12), 0 3px 6px 0 rgba($black, 0.24);
}
:active {
border: 2px solid $purple-600 !important;
box-shadow: none;
}
}
.debug-group {
border-radius: 4px;
padding: 16px;
box-shadow: 0 1px 3px 0 rgba(26, 24, 29, 0.12), 0 1px 2px 0 rgba(26, 24, 29, 0.24);
font-weight: 700;
background-color: $gray-600;
border: 2px solid transparent;
border-radius: 4px;
box-shadow: 0 1px 3px 0 rgba($black, 0.12), 0 1px 2px 0 rgba($black, 0.24);
font-weight: 700;
padding: 8px 16px;
.btn {
margin: 2px;
}
a:hover {
border: 2px solid transparent;
box-shadow: 0 1px 3px 0 rgba($black, 0.12), 0 1px 2px 0 rgba($black, 0.24);
text-decoration: none !important;
}
}
.btn-small {
background-color: $maroon-100;
border: 2px solid transparent;
color: $white !important;
line-height: 18px;
&:hover {
background-color: $maroon-100;
text-decoration: none !important;
border: 2px solid $maroon-100;
}
}
.btn-secondary {
padding: 2px 12px;
}
.btn-secondary a:hover {
text-decoration: none !important;
}
.btn-contribute {
background: $white;
border-radius: 2px;
width: 175px;
height: 32px;
color: $gray-50;
text-align: center;
vertical-align: middle;
padding: 0;
margin: 0;
&:hover {
color:$purple-300;
box-shadow: 0 3px 6px 0 rgba(26, 24, 29, 0.16), 0 3px 6px 0 rgba(26, 24, 29, 0.24);
&:active:not(:disabled) {
color:$purple-300;
border: 1px solid $purple-400;
box-shadow: 0 3px 6px 0 rgba(26, 24, 29, 0.16), 0 3px 6px 0 rgba(26, 24, 29, 0.24);
}
}
border: 2px solid transparent;
a {
display: flex;
+163 -86
View File
@@ -1,93 +1,100 @@
<template>
<div
v-if="member.preferences"
class="avatar"
:style="{width, height, paddingTop}"
:class="backgroundClass"
@click.prevent="castEnd()"
>
<div class="avatar-wrapper">
<div
class="character-sprites"
:style="{margin: spritesMargin}"
v-if="member.preferences"
class="avatar"
:style="{width, height, paddingTop}"
:class="topLevelClassList"
@click.prevent="castEnd()"
>
<template v-if="!avatarOnly">
<!-- Mount Body-->
<span
v-if="member.items.currentMount"
:class="'Mount_Body_' + member.items.currentMount"
></span>
</template>
<!-- Buffs that cause visual changes to avatar: Snowman, Ghost, Flower, etc-->
<template v-for="(klass, item) in visualBuffs">
<span
v-if="member.stats.buffs[item] && showVisualBuffs"
:key="item"
:class="klass"
></span>
</template>
<!-- Show flower ALL THE TIME!!!-->
<!-- See https://github.com/HabitRPG/habitica/issues/7133-->
<span :class="'hair_flower_' + member.preferences.hair.flower"></span>
<!-- Show avatar only if not currently affected by visual buff-->
<template v-if="showAvatar()">
<span :class="['chair_' + member.preferences.chair, specialMountClass]"></span>
<span :class="[getGearClass('back'), specialMountClass]"></span>
<span :class="[skinClass, specialMountClass]"></span>
<!-- eslint-disable max-len-->
<span
:class="[shirtClass, specialMountClass]"
></span>
<!-- eslint-enable max-len-->
<span :class="['head_0', specialMountClass]"></span>
<!-- eslint-disable max-len-->
<span :class="[member.preferences.size + '_' + getGearClass('armor'), specialMountClass]"></span>
<!-- eslint-enable max-len-->
<span :class="[getGearClass('back_collar'), specialMountClass]"></span>
<template
v-for="type in ['bangs', 'base', 'mustache', 'beard']"
>
<div
class="character-sprites"
:style="{margin: spritesMargin}"
>
<template v-if="!avatarOnly">
<!-- Mount Body-->
<span
:key="type"
:class="[hairClass(type), specialMountClass]"
v-if="member.items.currentMount"
:class="'Mount_Body_' + member.items.currentMount"
></span>
</template>
<span :class="[getGearClass('body'), specialMountClass]"></span>
<span :class="[getGearClass('eyewear'), specialMountClass]"></span>
<span :class="[getGearClass('head'), specialMountClass]"></span>
<span :class="[getGearClass('headAccessory'), specialMountClass]"></span>
<span :class="['hair_flower_' + member.preferences.hair.flower, specialMountClass]"></span>
<!-- Buffs that cause visual changes to avatar: Snowman, Ghost, Flower, etc-->
<template v-for="(klass, item) in visualBuffs">
<span
v-if="member.stats.buffs[item] && showVisualBuffs"
:key="item"
:class="klass"
></span>
</template>
<!-- Show flower ALL THE TIME!!!-->
<!-- See https://github.com/HabitRPG/habitica/issues/7133-->
<span :class="'hair_flower_' + member.preferences.hair.flower"></span>
<!-- Show avatar only if not currently affected by visual buff-->
<template v-if="showAvatar()">
<span :class="['chair_' + member.preferences.chair, specialMountClass]"></span>
<span :class="[getGearClass('back'), specialMountClass]"></span>
<span :class="[skinClass, specialMountClass]"></span>
<!-- eslint-disable max-len-->
<span
:class="[shirtClass, specialMountClass]"
></span>
<!-- eslint-enable max-len-->
<span :class="['head_0', specialMountClass]"></span>
<!-- eslint-disable max-len-->
<span :class="[member.preferences.size + '_' + getGearClass('armor'), specialMountClass]"></span>
<!-- eslint-enable max-len-->
<span :class="[getGearClass('back_collar'), specialMountClass]"></span>
<template
v-for="type in ['bangs', 'base', 'mustache', 'beard']"
>
<span
:key="type"
:class="[hairClass(type), specialMountClass]"
></span>
</template>
<span :class="[getGearClass('body'), specialMountClass]"></span>
<span :class="[getGearClass('eyewear'), specialMountClass]"></span>
<span :class="[getGearClass('head'), specialMountClass]"></span>
<span :class="[getGearClass('headAccessory'), specialMountClass]"></span>
<span
:class="[
'hair_flower_' + member.preferences.hair.flower, specialMountClass
]"
></span>
<span
v-if="!hideGear('shield')"
:class="[getGearClass('shield'), specialMountClass]"
></span>
<span
v-if="!hideGear('weapon')"
:class="[getGearClass('weapon'), specialMountClass]"
class="weapon"
></span>
</template>
<!-- Resting-->
<span
v-if="!hideGear('shield')"
:class="[getGearClass('shield'), specialMountClass]"
v-if="member.preferences.sleep"
class="zzz"
></span>
<span
v-if="!hideGear('weapon')"
:class="[getGearClass('weapon'), specialMountClass]"
></span>
</template>
<!-- Resting-->
<span
v-if="member.preferences.sleep"
class="zzz"
></span>
<template v-if="!avatarOnly">
<!-- Mount Head-->
<span
v-if="member.items.currentMount"
:class="'Mount_Head_' + member.items.currentMount"
></span>
<!-- Pet-->
<span
class="current-pet"
:class="petClass"
></span>
</template>
<template v-if="!avatarOnly">
<!-- Mount Head-->
<span
v-if="member.items.currentMount"
:class="'Mount_Head_' + member.items.currentMount"
></span>
<!-- Pet-->
<span
class="current-pet"
:class="petClass"
></span>
</template>
</div>
<class-badge
v-if="hasClass && !hideClassBadge"
class="under-avatar"
:member-class="member.stats.class"
/>
</div>
<class-badge
v-if="hasClass && !hideClassBadge"
class="under-avatar"
:member-class="member.stats.class"
/>
</div>
</template>
@@ -96,15 +103,23 @@
.avatar {
width: 141px;
height: 147px;
image-rendering: pixelated;
position: relative;
cursor: pointer;
&.centered-avatar {
margin: 0 auto;
}
// resetting the additional padding
margin-bottom: -0.5rem !important;
}
.character-sprites {
width: 90px;
height: 90px;
display: inline-flex;
}
.character-sprites span {
@@ -123,6 +138,27 @@
.invert {
filter: invert(100%);
}
.weapon {
// the only one that is relative so that it fits into the parent div
position: relative !important;
}
.debug {
border: 1px solid red;
.character-sprites {
border: 1px solid blue;
}
.weapon {
border: 1px solid green;
}
span {
border: 1px solid yellow;
}
}
</style>
<script>
@@ -133,12 +169,24 @@ import foolPet from '../mixins/foolPet';
import ClassBadge from '@/components/members/classBadge';
/**
* TODO replace avatarOnly with multiple options like
* - showMount
* - showPet
* - showBackground
* - showWeapons
*/
export default {
components: {
ClassBadge,
},
mixins: [foolPet],
props: {
debugMode: {
type: Boolean,
default: false,
},
member: {
type: Object,
required: true,
@@ -156,14 +204,21 @@ export default {
},
overrideAvatarGear: {
type: Object,
default (data) {
return data;
},
},
width: {
type: Number,
default: 140,
type: String,
default: '140px',
},
height: {
type: Number,
default: 147,
type: String,
default: undefined,
},
centerAvatar: {
type: Boolean,
default: false,
},
spritesMargin: {
type: String,
@@ -171,11 +226,16 @@ export default {
},
overrideTopPadding: {
type: String,
default: null,
},
showVisualBuffs: {
type: Boolean,
default: true,
},
showWeapon: {
type: Boolean,
default: true,
},
},
computed: {
...mapState({
@@ -204,6 +264,19 @@ export default {
return val;
},
topLevelClassList () {
const classes = [this.backgroundClass];
if (this.debugMode) {
classes.push('debug');
}
if (this.centerAvatar) {
classes.push('centered-avatar');
}
return classes.join(' ');
},
backgroundClass () {
if (this.member) {
const { background } = this.member.preferences;
@@ -290,6 +363,10 @@ export default {
},
hideGear (gearType) {
if (!this.member) return true;
if (!this.showWeapon) {
return true;
}
if (gearType === 'weapon') {
const equippedWeapon = this.member.items.gear[this.costumeClass][gearType];
@@ -25,9 +25,13 @@
</b-modal>
</template>
<style scoped>
<style scoped lang="scss">
.modal-body {
padding-bottom: 2em;
.btn {
margin: 0px 2px;
}
}
</style>
@@ -1,352 +0,0 @@
<template>
<div>
<div
v-if="isUserMentioned"
class="mentioned-icon"
></div>
<div
v-if="hasPermission(user, 'moderator') && msg.flagCount"
class="message-hidden"
>
{{ flagCountDescription }}
</div>
<div class="card-body">
<user-link
:user-id="msg.uuid"
:name="msg.user"
:backer="msg.backer"
:contributor="msg.contributor"
/>
<p class="time">
<span
v-if="msg.username"
class="mr-1"
>@{{ msg.username }}</span>
<span
v-if="msg.username"
class="mr-1"
></span>
<span
v-b-tooltip.hover="messageDate"
>{{ msg.timestamp | timeAgo }}&nbsp;</span>
<span v-if="msg.client && user.contributor.level >= 4">({{ msg.client }})</span>
</p>
<div
ref="markdownContainer"
class="text markdown"
dir="auto"
v-html="parseMarkdown(msg.text)"
></div>
<hr>
<div
v-if="msg.id"
class="d-flex"
>
<div
class="action d-flex align-items-center"
@click="copyAsTodo(msg)"
>
<div
class="svg-icon"
v-html="icons.copy"
></div>
<div>{{ $t('copyAsTodo') }}</div>
</div>
<div
v-if="(user.flags.communityGuidelinesAccepted && msg.uuid !== 'system')
&& (!isMessageReported || hasPermission(user, 'moderator'))"
class="action d-flex align-items-center"
@click="report(msg)"
>
<div
v-once
class="svg-icon"
v-html="icons.report"
></div>
<div v-once>
{{ $t('report') }}
</div>
</div>
<div
v-if="msg.uuid === user._id || hasPermission(user, 'moderator')"
class="action d-flex align-items-center"
@click="remove()"
>
<div
v-once
class="svg-icon"
v-html="icons.delete"
></div>
<div v-once>
{{ $t('delete') }}
</div>
</div>
<div
v-b-tooltip="{title: likeTooltip(msg.likes[user._id])}"
class="ml-auto d-flex"
>
<div
v-if="likeCount > 0"
class="action d-flex align-items-center mr-0"
:class="{activeLike: msg.likes[user._id]}"
@click="like()"
>
<div
class="svg-icon"
:title="$t('liked')"
v-html="icons.liked"
></div>
+{{ likeCount }}
</div>
<div
v-if="likeCount === 0"
class="action d-flex align-items-center mr-0"
:class="{activeLike: msg.likes[user._id]}"
@click="like()"
>
<div
class="svg-icon"
:title="$t('like')"
v-html="icons.like"
></div>
</div>
</div>
<span v-if="!msg.likes[user._id]">{{ $t('like') }}</span>
</div>
</div>
</div>
</template>
<style lang="scss">
.at-highlight {
background-color: rgba(213, 200, 255, 0.32);
padding: 0.1rem;
}
.at-text {
color: #6133b4;
}
</style>
<style lang="scss" scoped>
@import '~@/assets/scss/colors.scss';
.mentioned-icon {
width: 16px;
height: 16px;
border-radius: 50%;
background-color: #bda8ff;
box-shadow: 0 1px 1px 0 rgba(26, 24, 29, 0.12);
position: absolute;
right: -.5em;
top: -.5em;
}
.message-hidden {
margin-left: 1.5em;
margin-top: 1em;
color: red;
}
hr {
margin-bottom: 0.5rem;
margin-top: 0.5rem;
}
.card-body {
padding: 0.75rem 1.25rem 0.75rem 1.25rem;
.time {
font-size: 12px;
color: #878190;
margin-bottom: 0.5rem;
}
.text {
font-size: 14px;
color: #4e4a57;
text-align: initial;
min-height: 0rem;
}
}
.action {
display: inline-block;
color: #878190;
margin-right: 1em;
font-size: 12px;
:hover {
cursor: pointer;
}
.svg-icon {
color: #A5A1AC;
margin-right: .2em;
width: 16px;
}
}
.activeLike {
color: $purple-300;
.svg-icon {
color: $purple-400;
}
}
</style>
<script>
import moment from 'moment';
import cloneDeep from 'lodash/cloneDeep';
import escapeRegExp from 'lodash/escapeRegExp';
import { CHAT_FLAG_LIMIT_FOR_HIDING, CHAT_FLAG_FROM_SHADOW_MUTE } from '@/../../common/script/constants';
import renderWithMentions from '@/libs/renderWithMentions';
import { userStateMixin } from '../../mixins/userState';
import userLink from '../userLink';
import deleteIcon from '@/assets/svg/delete.svg';
import copyIcon from '@/assets/svg/copy.svg';
import likeIcon from '@/assets/svg/like.svg';
import likedIcon from '@/assets/svg/liked.svg';
import reportIcon from '@/assets/svg/report.svg';
export default {
components: { userLink },
filters: {
timeAgo (value) {
return moment(value).fromNow();
},
date (value) {
// @TODO: Vue doesn't support this so we cant user preference
return moment(value).toDate().toString();
},
},
mixins: [userStateMixin],
props: {
msg: {},
groupId: {},
},
data () {
return {
icons: Object.freeze({
like: likeIcon,
copy: copyIcon,
report: reportIcon,
delete: deleteIcon,
liked: likedIcon,
}),
reported: false,
};
},
computed: {
isUserMentioned () {
const message = this.msg;
if (message.highlight) return true;
const { user } = this;
const displayName = user.profile.name;
const { username } = user.auth.local;
const pattern = `@(${escapeRegExp(displayName)}|${escapeRegExp(username)})(\\b)`;
message.highlight = new RegExp(pattern, 'i').test(message.text);
return message.highlight;
},
likeCount () {
const message = this.msg;
if (!message.likes) return 0;
let likeCount = 0;
for (const key of Object.keys(message.likes)) {
const like = message.likes[key];
if (like) likeCount += 1;
}
return likeCount;
},
isMessageReported () {
return (this.msg.flags && this.msg.flags[this.user.id]) || this.reported;
},
flagCountDescription () {
if (!this.msg.flagCount) return '';
if (this.msg.flagCount < CHAT_FLAG_LIMIT_FOR_HIDING) return 'Message flagged once, not hidden';
if (this.msg.flagCount < CHAT_FLAG_FROM_SHADOW_MUTE) return 'Message hidden';
return 'Message hidden (shadow-muted)';
},
messageDate () {
const date = moment(this.msg.timestamp).toDate();
return date.toString();
},
},
mounted () {
const links = this.$refs.markdownContainer.getElementsByTagName('a');
for (let i = 0; i < links.length; i += 1) {
let link = links[i].pathname;
// Internet Explorer does not provide the leading slash character in the pathname
link = link.charAt(0) === '/' ? link : `/${link}`;
if (link.startsWith('/profile/')) {
links[i].onclick = ev => {
ev.preventDefault();
this.$router.push({ path: link });
};
}
}
this.CHAT_FLAG_LIMIT_FOR_HIDING = CHAT_FLAG_LIMIT_FOR_HIDING;
this.CHAT_FLAG_FROM_SHADOW_MUTE = CHAT_FLAG_FROM_SHADOW_MUTE;
this.$emit('chat-card-mounted', this.msg.id);
},
methods: {
async like () {
const message = cloneDeep(this.msg);
await this.$store.dispatch('chat:like', {
groupId: this.groupId,
chatId: message.id,
});
message.likes[this.user._id] = !message.likes[this.user._id];
this.$emit('message-liked', message);
this.$root.$emit('bv::hide::tooltip');
},
likeTooltip (likedStatus) {
if (!likedStatus) return this.$t('like');
return null;
},
copyAsTodo (message) {
this.$root.$emit('habitica::copy-as-todo', message);
},
report () {
this.$root.$on('habitica:report-result', data => {
if (data.ok) {
this.reported = true;
}
this.$root.$off('habitica:report-result');
});
this.$root.$emit('habitica::report-chat', {
message: this.msg,
groupId: this.groupId || 'privateMessage',
});
},
async remove () {
if (!window.confirm(this.$t('areYouSureDeleteMessage'))) return; // eslint-disable-line no-alert
const message = this.msg;
this.$emit('message-removed', message);
await this.$store.dispatch('chat:deleteChat', {
groupId: this.groupId,
chatId: message.id,
});
},
parseMarkdown (text) {
return renderWithMentions(text, this.user);
},
},
};
</script>
@@ -3,15 +3,6 @@
ref="container"
class="container-fluid"
>
<div class="row">
<div class="col-12">
<copy-as-todo-modal
:group-type="groupType"
:group-name="groupName"
:group-id="groupId"
/>
</div>
</div>
<div class="row loadmore">
<div v-if="canLoadMore">
<div class="loadmore-divider"></div>
@@ -33,6 +24,8 @@
<div
v-for="msg in messages.filter(m => chat && canViewFlag(m))"
:key="msg.id"
class="message-row"
:class="{ 'margin-right': user._id !== msg.uuid}"
>
<div class="d-flex">
<avatar
@@ -45,16 +38,14 @@
:override-top-padding="'14px'"
@click.native="showMemberModal(msg.uuid)"
/>
<div class="card">
<chat-card
:msg="msg"
:group-id="groupId"
@message-liked="messageLiked"
@message-removed="messageRemoved"
@show-member-modal="showMemberModal"
@chat-card-mounted="itemWasMounted"
/>
</div>
<message-card
:msg="msg"
:group-id="groupId"
:user-sent-message="user._id === msg.uuid"
@message-liked="messageLiked"
@message-removed="messageRemoved"
@message-card-mounted="itemWasMounted"
/>
<avatar
v-if="user._id === msg.uuid"
:class="{ invisible: avatarUnavailable(msg) }"
@@ -137,11 +128,27 @@
margin-bottom: .5em;
padding: 0rem;
width: 90%;
&.system-message {
width: 100%;
}
}
.message-scroll .d-flex {
min-width: 1px;
}
.message-row {
margin-left: 12px;
margin-right: 0;
margin-bottom: 1.2rem;
&:not(.margin-right) {
.d-flex {
justify-content: flex-end;
}
}
}
</style>
<script>
@@ -152,13 +159,13 @@ import findIndex from 'lodash/findIndex';
import { userStateMixin } from '../../mixins/userState';
import Avatar from '../avatar';
import copyAsTodoModal from './copyAsTodoModal';
import chatCard from './chatCard';
import MessageCard from '@/components/messages/messageCard.vue';
// TODO merge chatMessages.vue (party message list) with messageList.vue (private message list)
export default {
components: {
copyAsTodoModal,
chatCard,
MessageCard,
Avatar,
},
mixins: [userStateMixin],
@@ -1,105 +0,0 @@
<template>
<b-modal
id="copyAsTodo"
:title="$t('copyMessageAsToDo')"
:hide-footer="true"
size="md"
>
<div class="form-group">
<input
v-model="task.text"
class="form-control"
type="text"
>
</div>
<div class="form-group">
<textarea
v-model="task.notes"
class="form-control"
rows="5"
focus-element="true"
></textarea>
</div>
<hr>
<task
v-if="task._id"
:is-user="isUser"
:task="task"
/>
<div class="modal-footer">
<button
class="btn btn-secondary"
@click="close()"
>
{{ $t('close') }}
</button>
<button
class="btn btn-primary"
@click="saveTodo()"
>
{{ $t('submit') }}
</button>
</div>
</b-modal>
</template>
<script>
import taskDefaults from '@/../../common/script/libs/taskDefaults';
import { mapActions } from '@/libs/store';
import markdownDirective from '@/directives/markdown';
import notificationsMixin from '@/mixins/notifications';
import Task from '@/components/tasks/task';
const baseUrl = 'https://habitica.com';
export default {
directives: {
markdown: markdownDirective,
},
components: {
Task,
},
mixins: [notificationsMixin],
props: ['copyingMessage', 'groupType', 'groupName', 'groupId'],
data () {
return {
isUser: true,
task: {},
};
},
mounted () {
this.$root.$on('habitica::copy-as-todo', message => {
const notes = `${message.user || 'system message'}${message.user ? ' wrote' : ''} in [${this.groupName}](${this.groupPath()})`;
const newTask = {
text: message.text,
type: 'todo',
notes,
};
this.task = taskDefaults(newTask, this.$store.state.user.data);
this.$root.$emit('bv::show::modal', 'copyAsTodo');
});
},
beforeDestroy () {
this.$root.$off('habitica::copy-as-todo');
},
methods: {
...mapActions({
createTask: 'tasks:create',
}),
groupPath () {
if (this.groupType === 'party') {
return `${baseUrl}/party`;
}
return `${baseUrl}/groups/guild/${this.groupId}`;
},
close () {
this.$root.$emit('bv::hide::modal', 'copyAsTodo');
},
saveTodo () {
this.createTask(this.task);
this.text(this.$t('messageAddedAsToDo'));
this.$root.$emit('bv::hide::modal', 'copyAsTodo');
},
},
};
</script>
+14 -97
View File
@@ -22,13 +22,13 @@
:placeholder="placeholder"
:class="{'user-entry': newMessage}"
:maxlength="MAX_MESSAGE_LENGTH"
@keydown="updateCarretPosition"
@keydown="autoCompleteMixinUpdateCarretPosition"
@keyup.ctrl.enter="sendMessageShortcut()"
@keydown.tab="handleTab($event)"
@keydown.up="selectPreviousAutocomplete($event)"
@keydown.down="selectNextAutocomplete($event)"
@keypress.enter="selectAutocomplete($event)"
@keydown.esc="handleEscape($event)"
@keydown.tab="autoCompleteMixinHandleTab($event)"
@keydown.up="autoCompleteMixinSelectPreviousAutocomplete($event)"
@keydown.down="autoCompleteMixinSelectNextAutocomplete($event)"
@keypress.enter="autoCompleteMixinSelectAutocomplete($event)"
@keydown.esc="autoCompleteMixinHandleEscape($event)"
@paste="disableMessageSendShortcut()"
></textarea>
<span>{{ currentLength }} / {{ MAX_MESSAGE_LENGTH }}</span>
@@ -36,8 +36,8 @@
ref="autocomplete"
:text="newMessage"
:textbox="textbox"
:coords="coords"
:caret-position="caretPosition"
:coords="mixinData.autoComplete.coords"
:caret-position="mixinData.autoComplete.caretPosition"
:chat="group.chat"
@select="selectedAutocomplete"
/>
@@ -74,7 +74,7 @@
<slot name="additionRow"></slot>
<div class="row">
<div class="hr col-12"></div>
<chat-message
<chat-messages
:chat.sync="group.chat"
:group-type="group.type"
:group-id="group._id"
@@ -86,16 +86,15 @@
</template>
<script>
import debounce from 'lodash/debounce';
import { MAX_MESSAGE_LENGTH } from '@/../../common/script/constants';
import externalLinks from '../../mixins/externalLinks';
import autocomplete from '../chat/autoComplete';
import communityGuidelines from './communityGuidelines';
import chatMessage from '../chat/chatMessages';
import chatMessages from '../chat/chatMessages';
import { mapState } from '@/libs/store';
import markdownDirective from '@/directives/markdown';
import { autoCompleteHelperMixin } from '@/mixins/autoCompleteHelper';
export default {
directives: {
@@ -104,23 +103,18 @@ export default {
components: {
autocomplete,
communityGuidelines,
chatMessage,
chatMessages,
},
mixins: [externalLinks],
mixins: [externalLinks, autoCompleteHelperMixin],
props: ['label', 'group', 'placeholder'],
data () {
return {
newMessage: '',
sending: false,
caretPosition: 0,
chat: {
submitDisable: false,
submitTimeout: null,
},
coords: {
TOP: 0,
LEFT: 0,
},
textbox: null,
MAX_MESSAGE_LENGTH: MAX_MESSAGE_LENGTH.toString(),
};
@@ -142,35 +136,6 @@ export default {
this.handleExternalLinks();
},
methods: {
// https://medium.com/@_jh3y/how-to-where-s-the-caret-getting-the-xy-position-of-the-caret-a24ba372990a
getCoord (e, text) {
this.caretPosition = text.selectionEnd;
const div = document.createElement('div');
const span = document.createElement('span');
const copyStyle = getComputedStyle(text);
[].forEach.call(copyStyle, prop => {
div.style[prop] = copyStyle[prop];
});
div.style.position = 'absolute';
document.body.appendChild(div);
div.textContent = text.value.substr(0, this.caretPosition);
span.textContent = text.value.substr(this.caretPosition) || '.';
div.appendChild(span);
this.coords = {
TOP: span.offsetTop,
LEFT: span.offsetLeft,
};
document.body.removeChild(div);
},
updateCarretPosition: debounce(function updateCarretPosition (eventUpdate) {
this._updateCarretPosition(eventUpdate);
}, 250),
_updateCarretPosition (eventUpdate) {
const text = eventUpdate.target;
this.getCoord(eventUpdate, text);
},
async sendMessageShortcut () {
// If the user recently pasted in the text field, don't submit
if (!this.chat.submitDisable) {
@@ -221,50 +186,6 @@ export default {
}, 500);
},
handleTab (e) {
if (this.$refs.autocomplete.searchActive) {
e.preventDefault();
if (e.shiftKey) {
this.$refs.autocomplete.selectPrevious();
} else {
this.$refs.autocomplete.selectNext();
}
}
},
handleEscape (e) {
if (this.$refs.autocomplete.searchActive) {
e.preventDefault();
this.$refs.autocomplete.cancel();
}
},
selectNextAutocomplete (e) {
if (this.$refs.autocomplete.searchActive) {
e.preventDefault();
this.$refs.autocomplete.selectNext();
}
},
selectPreviousAutocomplete (e) {
if (this.$refs.autocomplete.searchActive) {
e.preventDefault();
this.$refs.autocomplete.selectPrevious();
}
},
selectAutocomplete (e) {
if (this.$refs.autocomplete.searchActive) {
if (this.$refs.autocomplete.selected !== null) {
e.preventDefault();
this.$refs.autocomplete.makeSelection();
} else {
// no autocomplete selected, newline instead
this.$refs.autocomplete.cancel();
}
}
},
selectedAutocomplete (newText, newCaret) {
this.newMessage = newText;
// Wait for v-modal to update
@@ -273,7 +194,6 @@ export default {
this.textbox.focus();
});
},
fetchRecentMessages () {
this.$emit('fetchRecentMessages');
},
@@ -284,10 +204,7 @@ export default {
beforeRouteUpdate (to, from, next) {
// Reset chat
this.newMessage = '';
this.coords = {
TOP: 0,
LEFT: 0,
};
this.autoCompleteMixinResetCoordsPosition();
next();
},
@@ -334,11 +334,6 @@
href="https://docs.google.com/forms/d/e/1FAIpQLScPhrwq_7P1C6PTrI3lbvTsvqGyTNnGzp1ugi1Ml0PFee_p5g/viewform?usp=sf_link"
target="_blank"
>{{ $t('requestFeature') }}</a>
<a
class="topbar-dropdown-item dropdown-item"
href="https://habitica.fandom.com/wiki/Habitica_Wiki"
target="_blank"
>{{ $t('wiki') }}</a>
</div>
</li>
</b-navbar-nav>
@@ -354,13 +349,15 @@
></div>
<span>{{ userHourglasses }}</span>
</div>
<div class="item-with-icon gem">
<div
class="item-with-icon gem"
@click.prevent="showBuyGemsModal()"
>
<a
v-b-tooltip.hover.bottom="$t('gems')"
class="top-menu-icon svg-icon gem mr-2"
:aria-label="$t('gems')"
href="#buy-gems"
@click.prevent="showBuyGemsModal()"
v-html="icons.gem"
></a>
<span>{{ userGems }}</span>
@@ -41,7 +41,8 @@ export default {
},
methods: {
action () {
if (!this.notification || !this.notification.data) {
if (!this.notification || !this.notification.data
|| this.notification.data.destination === this.$route.path) {
return;
}
if (this.notification.data.destination.indexOf('backgrounds') !== -1) {
@@ -106,7 +106,7 @@
</div>
<div slot="drawer-header">
<div class="drawer-tab-container">
<div class="clearfix">
<div class="clearfix mb-2">
<toggle-switch
class="float-right align-with-tab"
:label="$t(costumeMode ? 'useCostume' : 'autoEquipBattleGear')"
@@ -28,7 +28,6 @@
:name="member.profile.name"
:backer="member.backer"
:contributor="member.contributor"
:smaller-style="true"
/>
<inline-class-badge
v-if="member.stats"
@@ -0,0 +1,110 @@
<template>
<div
class="d-inline-flex like-button"
@click="like()"
>
<div
v-b-tooltip="{title: likeTooltip(likeCount)}"
class="d-flex"
>
<div
v-if="likeCount > 0"
class="action d-flex align-items-center mr-0"
:class="{isLiked: true, currentUserLiked: likedByCurrentUser}"
>
<div
class="svg-icon mr-1"
:title="$t('liked')"
v-html="icons.liked"
></div>
+{{ likeCount }}
</div>
<div
v-if="likeCount === 0"
class="action d-flex align-items-center mr-1"
>
<div
class="svg-icon"
:title="$t('like')"
v-html="icons.like"
></div>
</div>
</div>
<span v-if="likeCount === 0">{{ $t('like') }}</span>
</div>
</template>
<style lang="scss" scoped>
@import '~@/assets/scss/colors.scss';
@import '~@/assets/scss/tiers.scss';
.action {
display: inline-block;
margin-right: 1em;
.svg-icon {
color: $gray-100;
width: 16px;
}
&.isLiked {
color: $purple-200;
font-weight: bold;
.svg-icon {
color: $purple-300;
}
}
}
.like-button {
color: $gray-100;
font-size: 12px;
line-height: 16px;
&:hover {
cursor: pointer;
color: $purple-200;
.svg-icon {
color: $purple-300;
}
}
}
</style>
<script>
import likeIcon from '@/assets/svg/like.svg';
import likedIcon from '@/assets/svg/liked.svg';
export default {
props: {
likeCount: {
type: Number,
},
likedByCurrentUser: {
type: Boolean,
},
},
data () {
return {
icons: Object.freeze({
like: likeIcon,
liked: likedIcon,
}),
};
},
methods: {
async like () {
this.$emit('toggle-like');
},
likeTooltip (likedStatus) {
if (!likedStatus) return this.$t('like');
return null;
},
},
};
</script>
@@ -1,73 +1,157 @@
<template>
<div class="card-body">
<user-link
:user-id="msg.uuid"
:name="msg.user"
:backer="msg.backer"
:contributor="msg.contributor"
/>
<p class="time">
<span
v-if="msg.username"
class="mr-1"
>@{{ msg.username }}</span><span
v-if="msg.username"
class="mr-1"
></span>
<span
v-b-tooltip.hover="messageDate"
>{{ msg.timestamp | timeAgo }}&nbsp;</span>
<span v-if="msg.client && user.contributor.level >= 4"> ({{ msg.client }})</span>
</p>
<div
class="card"
:class="{
'system-message': isSystemMessage
}"
>
<div
class="text markdown"
dir="auto"
v-html="parseMarkdown(msg.text)"
></div>
<div
v-if="isMessageReported"
class="reported"
>
<span v-once>{{ $t('reportedMessage') }}</span><br>
<span v-once>{{ $t('canDeleteNow') }}</span>
</div>
<hr>
<div
v-if="msg.id"
class="d-flex"
v-b-tooltip.hover="messageDateForSystemMessage"
class="message-card"
:class="{
'user-sent-message': userSentMessage,
'user-received-message': !userSentMessage && !isSystemMessage,
'system-message': isSystemMessage
}"
>
<div
v-if="!isMessageReported"
class="action d-flex align-items-center"
@click="report(msg)"
v-if="isUserMentioned"
class="mentioned-icon"
></div>
<div
v-if="userIsModerator && msg.flagCount"
class="message-hidden"
>
<div
v-once
class="svg-icon"
v-html="icons.report"
></div>
<div v-once>
{{ $t('report') }}
</div>
{{ flagCountDescription }}
</div>
<div
class="action d-flex align-items-center"
@click="remove()"
class="card-body"
>
<user-link
v-if="!isSystemMessage"
:user-id="msg.uuid"
:name="msg.user"
:backer="msg.backer"
:contributor="msg.contributor"
/>
<p
v-if="!isSystemMessage"
class="time"
>
<span
v-if="msg.username"
class="mr-1"
>@{{ msg.username }}</span><span
v-if="msg.username"
class="mr-1"
></span>
<span v-b-tooltip.hover="messageDate">{{ msg.timestamp | timeAgo }}&nbsp;</span>
<span v-if="msg.client && user.contributor.level >= 4">
({{ msg.client }})
</span>
</p>
<b-dropdown
v-if="!isSystemMessage"
right="right"
variant="flat"
toggle-class="with-icon"
class="card-menu no-min-width"
:no-caret="true"
>
<template #button-content>
<span
v-once
class="svg-icon inline menuIcon color"
v-html="icons.menuIcon"
>
</span>
</template>
<b-dropdown-item
class="selectListItem"
@click="copy(msg)"
>
<span class="with-icon">
<span
v-once
class="svg-icon icon-16 color"
v-html="icons.copy"
></span>
<span v-once>
{{ $t('copy') }}
</span>
</span>
</b-dropdown-item>
<b-dropdown-item
v-if="canReportMessage"
class="selectListItem custom-hover--red"
@click="report(msg)"
>
<span class="with-icon">
<span
v-once
class="svg-icon icon-16 color"
v-html="icons.report"
></span>
<span v-once>
{{ $t('report') }}
</span>
</span>
</b-dropdown-item>
<b-dropdown-item
v-if="canDeleteMessage"
class="selectListItem custom-hover--red"
@click="remove()"
>
<span class="with-icon">
<span
v-once
class="svg-icon icon-16 color"
v-html="icons.delete"
></span>
<span v-once>
{{ $t('delete') }}
</span>
</span>
</b-dropdown-item>
</b-dropdown>
<div
v-once
class="svg-icon"
v-html="icons.delete"
></div>
<div v-once>
{{ $t('delete') }}
v-if="isSystemMessage"
class="system-message-body"
>
{{ msg.unformattedText }}
</div>
<div
v-else
ref="markdownContainer"
class="text markdown"
dir="auto"
v-html="parseMarkdown(msg.text)"
></div>
<div
v-if="isMessageReported"
class="reported"
>
<span v-once>{{ $t('reportedMessage') }}</span><br>
<span v-once>{{ $t('canDeleteNow') }}</span>
</div>
<like-button
v-if="canLikeMessage"
class="mt-75"
:liked-by-current-user="msg.likes[user._id]"
:like-count="likeCount"
@toggle-like="like()"
/>
</div>
</div>
</div>
</template>
<style lang="scss">
.message-card {
.at-highlight {
background-color: rgba(213, 200, 255, 0.32);
padding: 0.1rem;
@@ -76,43 +160,76 @@
.at-text {
color: #6133b4;
}
.card-menu button {
justify-content: center;
margin: 0;
padding: 0;
height: 1rem;
width: 1rem;
}
.markdown p:last-of-type {
margin-bottom: 0;
}
}
</style>
<style lang="scss" scoped>
@import '~@/assets/scss/colors.scss';
@import '~@/assets/scss/tiers.scss';
@import '~@/assets/scss/colors.scss';
@import '~@/assets/scss/tiers.scss';
.action {
display: inline-block;
color: $gray-200;
margin-right: 1em;
font-size: 12px;
.card {
background: transparent !important;
margin-bottom: 0 !important;
}
:hover {
cursor: pointer;
}
.message-card:not(.system-message) {
background: white;
}
.svg-icon {
color: $gray-300;
margin-right: .2em;
width: 16px;
}
.mentioned-icon {
width: 16px;
height: 16px;
border-radius: 50%;
background-color: $purple-500;
box-shadow: 0 1px 1px 0 rgba(26, 24, 29, 0.12);
position: absolute;
right: -.5em;
top: -.5em;
}
.message-hidden {
margin-left: 1.5em;
margin-top: 1em;
color: red;
}
.active {
color: $purple-300;
.svg-icon {
color: $purple-400;
}
}
.active {
color: $purple-300;
.message-card {
border-radius: 7px;
margin: 0;
padding: 1rem 0.75rem 0.5rem 1rem;
.svg-icon {
color: $purple-400;
}
&.system-message {
padding-top: 0.5rem;
}
.card-body {
padding: 0.75rem 1.25rem 0.75rem 1.25rem;
position: relative;
padding: 0;
.time {
font-size: 12px;
color: $gray-200;
color: $gray-100;
margin-bottom: 0.5rem;
}
@@ -123,49 +240,173 @@
min-height: 0rem;
}
}
}
hr {
margin-bottom: 0.5rem;
margin-top: 0.5rem;
}
.card-menu {
position: absolute;
top: 0;
right: 0;
.reported {
margin-top: 18px;
color: $red-50;
&:not(.show) {
display: none;
}
}
.card-body:hover {
.card-menu {
display: block;
}
}
hr {
margin-bottom: 0.5rem;
margin-top: 0.5rem;
}
.reported {
margin-top: 18px;
color: $red-50;
}
.selectListItem:not(:hover) .svg-icon.icon-16.color {
color: #{$gray-100}
}
.custom-hover--red {
--hover-color: #{$maroon-50};
--hover-background: #{rgba($red-500, 0.25)};
}
.user-sent-message {
border: 1px solid $purple-400;
}
.system-message {
border: 1px solid $purple-400;
}
.user-received-message {
border: 1px solid $gray-500;
}
.card-menu {
// icon-color is the menu icon itself
--icon-color: #{$gray-100};
--dropdown-item-hover-icon-color: #{$gray-100};
&:hover {
--icon-color: #{$purple-300};
}
}
.menuIcon {
width: 4px;
height: 1rem;
object-fit: contain;
}
.system-message-body {
line-height: 1.71;
text-align: center;
color: $purple-300;
}
</style>
<script>
import axios from 'axios';
import moment from 'moment';
import cloneDeep from 'lodash/cloneDeep';
import escapeRegExp from 'lodash/escapeRegExp';
import { CHAT_FLAG_FROM_SHADOW_MUTE, CHAT_FLAG_LIMIT_FOR_HIDING } from '@/../../common/script/constants';
import externalLinks from '../../mixins/externalLinks';
import { CopyToClipboardMixin } from '@/mixins/copyToClipboard';
import renderWithMentions from '@/libs/renderWithMentions';
import { mapState } from '@/libs/store';
import userLink from '../userLink';
import deleteIcon from '@/assets/svg/delete.svg';
import reportIcon from '@/assets/svg/report.svg';
import menuIcon from '@/assets/svg/menu.svg';
import { userStateMixin } from '@/mixins/userState';
import copyIcon from '@/assets/svg/copy.svg';
import LikeButton from '@/components/messages/likeButton.vue';
const LikeLogicMixin = {
computed: {
likeCount () {
const message = this.msg;
if (!message.likes) return 0;
let likeCount = 0;
for (const key of Object.keys(message.likes)) {
const like = message.likes[key];
if (like) likeCount += 1;
}
return likeCount;
},
},
methods: {
async like () {
const message = cloneDeep(this.msg);
await this.$store.dispatch('chat:like', {
groupId: this.groupId,
chatMessageId: this.privateMessageMode ? message.uniqueMessageId : message.id,
});
message.likes[this.user._id] = !message.likes[this.user._id];
this.$emit('message-liked', message);
this.$root.$emit('bv::hide::tooltip');
},
},
};
export default {
components: {
LikeButton,
userLink,
},
filters: {
timeAgo (value) {
return moment(value).fromNow();
},
date (value) {
// @TODO: Vue doesn't support this so we cant user preference
return moment(value).toDate().toString();
},
},
mixins: [externalLinks],
mixins: [
externalLinks, userStateMixin, LikeLogicMixin,
CopyToClipboardMixin,
],
props: {
msg: {},
msg: {
type: Object,
},
groupId: {
type: String,
},
privateMessageMode: {
type: Boolean,
},
userSentMessage: {
type: Boolean,
},
},
data () {
return {
icons: Object.freeze({
delete: deleteIcon,
report: reportIcon,
copy: copyIcon,
menuIcon,
}),
reported: false,
};
@@ -175,19 +416,100 @@ export default {
isMessageReported () {
return (this.msg.flags && this.msg.flags[this.user.id]) || this.reported;
},
messageDateForSystemMessage () {
return this.isSystemMessage ? this.messageDate : '';
},
messageDate () {
const date = moment(this.msg.timestamp).toDate();
return date.toString();
},
userIsModerator () {
return this.hasPermission(this.user, 'moderator');
},
isSystemMessage () {
return this.msg.uuid === 'system';
},
canLikeMessage () {
if (this.isSystemMessage) {
return false;
}
if (this.privateMessageMode) {
return Boolean(this.msg.uniqueMessageId);
}
return this.msg.id;
},
canDeleteMessage () {
return this.privateMessageMode
|| this.msg.uuid === this.user._id
|| this.userIsModerator;
},
canReportMessage () {
if (this.privateMessageMode) {
return !this.isMessageReported;
}
return (this.user.flags.communityGuidelinesAccepted && this.msg.uuid !== 'system')
&& (!this.isMessageReported || this.userIsModerator);
},
isUserMentioned () {
const message = this.msg;
if (message.highlight) {
return true;
}
const { user } = this;
const displayName = user.profile.name;
const { username } = user.auth.local;
const pattern = `@(${escapeRegExp(displayName)}|${escapeRegExp(username)})(\\b)`;
message.highlight = new RegExp(pattern, 'i').test(message.text);
return message.highlight;
},
flagCountDescription () {
if (!this.msg.flagCount) {
return '';
}
if (this.msg.flagCount < CHAT_FLAG_LIMIT_FOR_HIDING) {
return 'Message flagged once, not hidden';
}
if (this.msg.flagCount < CHAT_FLAG_FROM_SHADOW_MUTE) {
return 'Message hidden';
}
return 'Message hidden (shadow-muted)';
},
},
mounted () {
this.$emit('message-card-mounted');
this.handleExternalLinks();
this.mapProfileLinksToModal();
},
updated () {
this.handleExternalLinks();
this.mapProfileLinksToModal();
},
methods: {
mapProfileLinksToModal () {
const links = this.$refs.markdownContainer.getElementsByTagName('a');
for (let i = 0; i < links.length; i += 1) {
let link = links[i].pathname;
// Internet Explorer does not provide the leading slash character in the pathname
link = link.charAt(0) === '/' ? link : `/${link}`;
if (link.startsWith('/profile/')) {
links[i].onclick = ev => {
ev.preventDefault();
this.$router.push({ path: link });
};
}
}
},
report () {
this.$root.$on('habitica:report-result', data => {
if (data.ok) {
@@ -199,16 +521,29 @@ export default {
this.$root.$emit('habitica::report-chat', {
message: this.msg,
groupId: 'privateMessage',
groupId: this.groupId,
});
},
async remove () {
if (!window.confirm(this.$t('areYouSureDeleteMessage'))) return; // eslint-disable-line no-alert
// eslint-disable-next-line no-alert
if (!window.confirm(this.$t('areYouSureDeleteMessage'))) {
return;
}
const message = this.msg;
this.$emit('message-removed', message);
await axios.delete(`/api/v4/inbox/messages/${message.id}`);
if (this.privateMessageMode) {
await axios.delete(`/api/v4/inbox/messages/${message.id}`);
} else {
await this.$store.dispatch('chat:deleteChat', {
groupId: this.groupId,
chatId: message.id,
});
}
},
copy (message) {
this.mixinCopyToClipboard(message.text, this.$t('messageCopiedToClipboard'));
},
parseMarkdown (text) {
return renderWithMentions(text, this.user);
@@ -1,9 +1,9 @@
<template>
<div
ref="container"
class="container-fluid"
class="message-list"
>
<div class="row loadmore">
<div class="loadmore">
<div v-if="canLoadMore && !isLoading">
<div class="loadmore-divider-holder">
<div class="loadmore-divider"></div>
@@ -28,7 +28,7 @@
<div
v-for="(msg) in messages"
:key="msg.id"
class="row message-row"
class="message-row"
:class="{ 'margin-right': user._id !== msg.uuid}"
>
<div
@@ -39,28 +39,31 @@
class="avatar-left"
:member="conversationOpponentUser"
:avatar-only="true"
:override-top-padding="'14px'"
:show-weapon="false"
:debug-mode="false"
:override-top-padding="'0'"
:hide-class-badge="true"
@click.native="showMemberModal(msg.uuid)"
/>
<div
class="card"
:class="{'card-right': user._id !== msg.uuid, 'card-left': user._id === msg.uuid}"
>
<message-card
:msg="msg"
@message-removed="messageRemoved"
@show-member-modal="showMemberModal"
@message-card-mounted="itemWasMounted"
/>
</div>
<message-card
:msg="msg"
:user-sent-message="user._id === msg.uuid"
:group-id="'privateMessage'"
:private-message-mode="true"
@message-liked="messageLiked"
@message-removed="messageRemoved"
@show-member-modal="showMemberModal"
@message-card-mounted="itemWasMounted"
/>
<avatar
v-if="user && user._id === msg.uuid"
class="avatar-right"
:member="user"
:avatar-only="true"
:show-weapon="false"
:debug-mode="false"
:hide-class-badge="true"
:override-top-padding="'14px'"
:override-top-padding="'0'"
@click.native="showMemberModal(msg.uuid)"
/>
</div>
@@ -69,121 +72,123 @@
</template>
<style lang="scss" scoped>
@import '~@/assets/scss/colors.scss';
@import '~@/assets/scss/colors.scss';
.avatar {
width: 170px;
min-width: 8rem;
height: 120px;
padding-top: 0 !important;
.avatar-left, .avatar-right {
align-self: center;
::v-deep .character-sprites {
margin-bottom: -5px !important;
padding-bottom: 0 !important;
margin-top: -1px !important;
}
.avatar-right {
margin-left: -1rem;
::v-deep .avatar {
margin-left: -1.75rem;
margin-right: -0.5rem;
}
}
::v-deep .character-sprites {
margin-right: 1rem !important;
.avatar-left {
margin-right: 1.5rem;
}
.avatar-right {
overflow: clip;
margin-left: 1.5rem;
::v-deep .character-sprites {
margin-right: 1rem !important;
}
}
.card {
border: 0px;
margin-bottom: 1rem;
padding: 0rem;
width: 684px;
}
.message-list {
width: 100%;
padding-right: 10px;
margin-right: 0 !important;
}
.message-row {
margin-left: 12px;
margin-right: 0;
margin-bottom: 1.2rem;
&:not(.margin-right) {
.d-flex {
justify-content: flex-end;
}
}
}
.card {
border: 0px;
margin-bottom: 1rem;
padding: 0rem;
width: 684px;
}
.message-row {
margin-left: 12px;
margin-right: 12px;
.hr {
width: 100%;
height: 20px;
border-bottom: 1px solid $gray-500;
text-align: center;
margin: 2em 0;
}
&:not(.margin-right) {
.d-flex {
justify-content: flex-end;
}
}
}
@media only screen and (max-width: 1200px) {
.card {
width: 100%;
}
}
.hr-middle {
font-size: 16px;
font-weight: bold;
font-family: 'Roboto Condensed';
line-height: 1.5;
text-align: center;
color: $gray-200;
background-color: $gray-700;
padding: .2em;
margin-top: .2em;
display: inline-block;
width: 100px;
}
@media only screen and (min-width: 1400px) {
.message-row {
margin-left: -15px;
margin-right: -30px;
}
}
.loadmore {
justify-content: center;
margin-right: 12px;
margin-top: 12px;
margin-bottom: 24px;
.card-left {
border: 1px solid $purple-500;
}
.card-right {
border: 1px solid $gray-500;
}
.hr {
> div {
display: flex;
width: 100%;
height: 20px;
border-bottom: 1px solid $gray-500;
text-align: center;
margin: 2em 0;
}
align-items: center;
.hr-middle {
font-size: 16px;
font-weight: bold;
font-family: 'Roboto Condensed';
line-height: 1.5;
text-align: center;
color: $gray-200;
background-color: $gray-700;
padding: .2em;
margin-top: .2em;
display: inline-block;
width: 100px;
}
.loadmore {
justify-content: center;
margin-right: 12px;
margin-top: 12px;
margin-bottom: 24px;
> div {
display: flex;
width: 100%;
align-items: center;
button {
text-align: center;
color: $gray-50;
}
button {
text-align: center;
color: $gray-50;
}
}
}
.loadmore-divider-holder {
flex: 1;
margin-left: 24px;
margin-right: 24px;
.loadmore-divider-holder {
flex: 1;
margin-left: 24px;
margin-right: 24px;
&:last-of-type {
margin-right: 0;
}
&:last-of-type {
margin-right: 0;
}
}
.loadmore-divider {
height: 1px;
border-top: 1px $gray-500 solid;
width: 100%;
.loadmore-divider {
height: 1px;
border-top: 1px $gray-500 solid;
width: 100%;
}
}
.loading {
padding-left: 1.5rem;
margin-bottom: 1rem;
}
.loading {
padding-left: 1.5rem;
margin-bottom: 1rem;
}
</style>
@@ -280,6 +285,9 @@ export default {
// container.style.overflowY = 'scroll';
}
}, 50),
messageLiked (message) {
this.$emit('message-liked', message);
},
messageRemoved (message) {
this.$emit('message-removed', message);
},
@@ -71,7 +71,6 @@
id="selectUser"
v-model="userSearchTerm"
:is-valid="foundUser._id"
:placeholder="$t('usernameOrUserId')"
:invalid-issues="userInputInvalidIssues"
/>
@@ -318,6 +317,7 @@ export default {
computed: {
...mapState({
currentEventList: 'worldState.data.currentEventList',
user: 'user.data',
}),
currentEvent () {
return find(this.currentEventList, event => Boolean(event.gemsPromo) || Boolean(event.promo));
@@ -399,6 +399,8 @@ export default {
this.foundUser = result;
}, 500),
selectUser () {
this.foundUser.g1g1 = this.currentEvent?.promo === 'g1g1'
&& this.foundUser._id !== this.user._id;
this.$root.$emit('habitica::send-gift', this.foundUser);
this.close();
},
@@ -59,6 +59,12 @@
<template v-if="paymentData.paymentType === 'gift-subscription'">
<div>
<span
v-if="paymentData.g1g1"
v-html="$t('paymentYouSentSubscriptionG1G1', {
name: paymentData.giftReceiver, months: paymentData.subscription.months})"
></span>
<span
v-else
v-html="$t('paymentYouSentSubscription', {
name: paymentData.giftReceiver, months: paymentData.subscription.months})"
></span>
@@ -429,6 +429,7 @@
}
.btn-update-card {
line-height: 1.714;
border-radius: 4px;
font-size: 14px;
padding: 4px 12px;
@@ -647,6 +648,7 @@
border-radius: 8px;
box-shadow: 0px 1px 3px 0px rgba($black, 0.12), 0px 1px 2px 0px rgba($black, 0.24);
width: 448px;
background-color: $white;
}
.svg-amazon-pay {
@@ -147,9 +147,17 @@
<payments-buttons
v-if="userReceivingGift?._id"
:disabled="!subscription.key"
:stripe-fn="() => redirectToStripe({gift, uuid: userReceivingGift._id, receiverName})"
:stripe-fn="() => redirectToStripe({
gift,
uuid: userReceivingGift._id,
receiverName,
g1g1: userReceivingGift.g1g1,
})"
:paypal-fn="() => openPaypalGift({
gift: gift, giftedTo: userReceivingGift._id, receiverName,
gift: gift,
giftedTo: userReceivingGift._id,
receiverName,
g1g1: userReceivingGift.g1g1,
})"
/>
<payments-buttons
@@ -27,27 +27,15 @@
@changedPosition="tabSelected($event)"
>
<div slot="right-item">
<div
<a
v-once
id="petLikeToEatMarket"
class="drawer-help-text"
href="/static/faq#pet-foods"
target="_blank"
>
<span>{{ $t('petLikeToEat') + ' ' }}</span>
<span
class="svg-icon inline icon-16"
v-html="icons.information"
></span>
</div>
<b-popover
target="petLikeToEatMarket"
:placement="'top'"
>
<div
v-once
class="popover-content-text"
v-html="$t('petLikeToEatText')"
></div>
</b-popover>
<span>{{ $t('petLikeToEat') }}</span>
</a>
</div>
</drawer-header-tabs>
</div>
@@ -80,7 +68,6 @@
import _filter from 'lodash/filter';
import { mapState } from '@/libs/store';
import inventoryUtils from '@/mixins/inventoryUtils';
import svgInformation from '@/assets/svg/information.svg';
import Drawer from '@/components/ui/drawer';
import DrawerSlider from '@/components/ui/drawerSlider';
@@ -127,10 +114,6 @@ export default {
},
],
selectedDrawerTab: this.defaultSelectedTab,
icons: Object.freeze({
information: svgInformation,
}),
};
},
computed: {
@@ -378,7 +378,7 @@
height: 40px;
border-radius: 2px;
background-color: $white;
box-shadow: 0 2px 2px 0 rgba(26, 24, 29, 0.16), 0 1px 4px 0 rgba(26, 24, 29, 0.12);
box-shadow: 0 2px 2px 0 rgba($black, 0.16), 0 1px 4px 0 rgba($black, 0.12);
margin-right: 24px;
input {
@@ -462,17 +462,17 @@
&.gems {
color: $green-10;
background-color: rgba(36, 204, 143, 0.15);
background-color: rgba($green-100, 0.15);
}
&.gold {
color: $yellow-5;
background-color: rgba(255, 190, 93, 0.15);
background-color: rgba($yellow-100, 0.15);
}
&.hourglasses {
color: $hourglass-color;
background-color: rgba(41, 149, 205, 0.15);
background-color: rgba($blue-10, 0.15);
}
}
@@ -516,11 +516,16 @@
button.btn.btn-primary {
margin-top: 16px;
padding: 4px 16px;
height: 32px;
padding: 2px 12px;
line-height: 1.714;
&:focus {
border: 2px solid black;
border: 2px solid $purple-400;
}
&:active {
border: 2px solid $purple-400 !important;
box-shadow:none;
}
}
@@ -297,11 +297,16 @@
button.btn.btn-primary {
margin-top: 16px;
padding: 4px 16px;
height: 32px;
padding: 2px 12px;
line-height: 1.714;
&:focus {
border: 2px solid black;
border: 2px solid $purple-400;
}
&:active {
border: 2px solid $purple-400;
box-shadow: none;
}
.balance {
@@ -198,7 +198,7 @@
top: 25px;
border-radius: 8px;
background-color: $gray-600;
box-shadow: 0 2px 16px 0 rgba(26, 24, 29, 0.32);
box-shadow: 0 2px 16px 0 rgba($black, 0.32);
display: flex;
align-items: center;
flex-direction: column;
@@ -208,12 +208,17 @@
}
button.btn.btn-primary {
margin-top: 14px;
padding: 4px 16px;
height: 32px;
margin-top: 16px;
padding: 2px 12px;
line-height: 1.714;
&:focus {
border: 2px solid black;
border: 2px solid $purple-400;
}
&:active {
border: 2px solid $purple-400;
box-shadow: none;
}
}
@@ -249,7 +254,7 @@
&.gems {
color: $green-10;
background-color: rgba(36, 204, 143, 0.15);
background-color: rgba($green-100, 0.15);
line-height: 1.4;
margin: 0 0 0 -4px;
border-radius: 20px;
@@ -257,7 +262,7 @@
&.gold {
color: $yellow-5;
background-color: rgba(255, 190, 93, 0.15);
background-color: rgba($yellow-100, 0.15);
line-height: 1.4;
margin: 0 0 0 -4px;
border-radius: 20px;
@@ -265,7 +270,7 @@
&.hourglasses {
color: $hourglass-color;
background-color: rgba(41, 149, 205, 0.15);
background-color: rgba($blue-10, 0.15);
line-height: 1.4;
margin: 0 0 0 -4px;
border-radius: 20px;
@@ -163,14 +163,7 @@
slot="itemBadge"
slot-scope="ctx"
>
<span
class="badge-top"
@click.prevent.stop="togglePinned(ctx.item)"
>
<pin-badge
:pinned="ctx.item.pinned"
/>
</span>
<category-item :item="ctx.item" />
</template>
</shopItem>
</div>
@@ -178,6 +171,23 @@
</div>
</div>
</div>
<buy-quest-modal
:item="selectedItemToBuy || {}"
:price-type="selectedItemToBuy ? selectedItemToBuy.currency : ''"
:with-pin="true"
>
<template
slot="item"
slot-scope="ctx"
>
<item
class="flat"
:item="ctx.item"
:item-content-class="ctx.item.class"
:show-popover="false"
/>
</template>
</buy-quest-modal>
</div>
</template>
@@ -346,11 +356,17 @@ import svgWizard from '@/assets/svg/wizard.svg';
import svgRogue from '@/assets/svg/rogue.svg';
import svgHealer from '@/assets/svg/healer.svg';
import BuyQuestModal from '../quests/buyQuestModal.vue';
import CategoryItem from '../market/categoryItem';
import FilterGroup from '@/components/ui/filterGroup';
import FilterSidebar from '@/components/ui/filterSidebar';
import { worldStateMixin } from '@/mixins/worldState';
export default {
components: {
BuyQuestModal,
CategoryItem,
FilterGroup,
FilterSidebar,
Checkbox,
PinBadge,
@@ -386,6 +402,7 @@ export default {
featuredGearBought: false,
currentEvent: null,
backgroundUpdate: new Date(),
selectedItemToBuy: null,
imageURLs: {
background: '',
npc: '',
@@ -550,7 +567,12 @@ export default {
return false;
},
itemSelected (item) {
this.$root.$emit('buyModal::showItem', item);
if (item.type === 'quests') {
this.selectedItemToBuy = item;
this.$root.$emit('bv::show::modal', 'buy-quest-modal');
} else {
this.$root.$emit('buyModal::showItem', item);
}
},
},
};
@@ -26,7 +26,7 @@
position: fixed;
right: 10px;
width: 350px;
z-index: 9999; // to keep it above modal overlays
z-index: 999; // to keep it above modal overlays
top: var(--current-scrollY);
@@ -152,8 +152,11 @@
}
.btn-primary.pull-right {
height: 2.5em;
line-height: 2.25;
margin: auto 0px auto auto;
&:focus, :active {
border: 2px solid $purple-400;
}
}
nav.navbar {
+11 -3
View File
@@ -552,8 +552,16 @@
}
.sign-up {
border: 2px solid transparent;
box-shadow: 0 1px 3px 0 rgba($black, 0.16), 0 1px 3px 0 rgba($black, 0.24);
padding-top: 11px;
padding-bottom: 11px;
&:focus, &:active {
background-color: $blue-50;
border: 2px solid $purple-400;
box-shadow: 0 3px 6px 0 rgba($black, 0.16), 0 3px 6px 0 rgba($black, 0.24);
}
}
::-webkit-input-placeholder { /* Chrome/Opera/Safari */
@@ -650,9 +658,9 @@
.btn-primary {
width: 411px;
height: 48px;
border-radius: 2px;
border-radius: 4px;
background-color: $purple-400;
box-shadow: 0 2px 2px 0 rgba(26, 24, 29, 0.24), 0 1px 4px 0 rgba(26, 24, 29, 0.16);
box-shadow: 0 2px 2px 0 rgba($black, 0.24), 0 1px 4px 0 rgba($black, 0.16);
margin-bottom: 5em;
}
@@ -669,7 +677,7 @@
&:hover {
background-color: $purple-50;
box-shadow: 0 4px 4px 0 rgba(26, 24, 29, 0.16), 0 1px 8px 0 rgba(26, 24, 29, 0.12);
box-shadow: 0 4px 4px 0 rgba($black, 0.16), 0 1px 8px 0 rgba($black, 0.12);
}
}
@@ -88,7 +88,7 @@ $itemHeight: 2rem;
.inline-dropdown {
&.select-multi .dropdown-toggle {
height: auto;
line-height: 1.571;
padding-bottom: 0px;
}
}
@@ -86,7 +86,7 @@
>
<a
target="_blank"
href="https://habitica.fandom.com/wiki/Markdown_Cheat_Sheet"
href="https://github.com/HabitRPG/habitica/wiki/Markdown-in-Habitica"
:class="cssClass('headings')"
>{{ $t('markdownHelpLink') }}</a>
</small>
@@ -651,9 +651,9 @@
input, textarea {
transition-property: border-color, box-shadow, color, background;
background-color: rgba(255, 255, 255, 0.5);
background-color: rgba($white, 0.5);
&:focus:not(:disabled), &:active:not(:disabled), &:hover:not(:disabled) {
background-color: rgba(255, 255, 255, 0.75);
background-color: rgba($white, 0.75);
}
}
@@ -810,11 +810,7 @@
margin-right: 16px;
color: $blue-10;
}
.btn-footer {
height: 2rem;
}
}
}
.weekday-check {
margin-left: 0px;
@@ -884,6 +880,24 @@
margin-bottom: 0;
}
}
.disabled {
background-color: $white;
border: 2px solid transparent;
color: $gray-200;
line-height: 1.714;
box-shadow: 0px 1px 3px 0px rgba(26, 24, 29, 0.12), 0px 1px 2px 0px rgba(26, 24, 29, 0.24);
&:focus {
background-color: $white;
border: 2px solid $purple-400;
box-shadow: none;
}
&:active {
box-shadow: 0px 1px 3px 0px rgba(26, 24, 29, 0.12), 0px 1px 2px 0px rgba(26, 24, 29, 0.24);
}
}
}
@media only screen and (max-width: 768px) {
+23 -3
View File
@@ -61,6 +61,18 @@
left: calc((100% + 236px - 978px) / 2);
right: 0%;
}
@media screen and (max-width: 575px) {
max-width: none;
left: 3%;
right: 3%;
}
.message {
@media screen and (max-width: 450px) {
width: 100%;
}
}
}
.drawer-toggle-icon {
@@ -117,6 +129,12 @@
padding-top: 6px;
padding-left: 24px;
padding-right: 24px;
a {
line-height: 1.33;
color: $gray-500;
font-weight: normal;
}
}
.drawer-tab {
@@ -136,7 +154,7 @@
color: $white !important;
text-decoration: none !important;
border-bottom: 2px solid transparent;
padding: 0.5rem;
padding: 8px;
&-active, &:hover {
color: $white !important;
@@ -157,17 +175,19 @@
}
.drawer-slider {
padding: 12px 0 0 8px;
padding: 0;
white-space: nowrap;
position: relative;
width: 100%;
& .message {
display: flex;
align-items: center;
justify-content: center;
margin: auto;
top: calc(50% - 30px);
left: 24px;
left: 0;
right: 0;
position: absolute;
@@ -51,7 +51,7 @@
.header-tabs {
display: grid;
grid-template-columns: 1fr auto 1fr;
grid-template-columns: max-content;
}
// MS Edge
@@ -34,12 +34,6 @@
<template
v-for="item in showItems"
>
<div
v-if="shouldAddVerticalLine(item)"
:key="item.key"
class="vertical-divider"
:style="dividerMargins"
></div>
<slot
name="item"
:item="item"
@@ -56,6 +50,10 @@
$buttonAreaWidth: 60;
.items > div {
margin: 0 12px
}
.slider-root {
position: relative;
}
@@ -95,9 +93,11 @@
&.left-button {
left: 0;
padding-left: 0px;
}
&.right-button {
padding-left:20px;
right: 0;
}
}
@@ -108,15 +108,6 @@
justify-content: center;
align-items: center;
padding-top: 10px;
margin-left: $buttonAreaWidth+ px;
margin-right: $buttonAreaWidth+ px;
}
.vertical-divider {
height: 92px;
width: 1px;
background: #34313a;
margin-bottom: 8px;
}
</style>
@@ -199,9 +190,6 @@ export default {
itemsPerPage () {
return Math.floor(this.currentWidth / (this.itemWidth + this.itemMargin));
},
shouldAddVerticalLine (item) {
return this.items[this.itemsPerPage() - 1] === item && this.pointer !== 5;
},
scrollButtonsVisible () {
return this.items.length > this.itemsPerPage();
},
@@ -12,7 +12,9 @@
@select="selectItem($event)"
>
<template #item="{ item }">
<span :class="{'dropdown-icon-item': withIcon}">
<span
:class="{'dropdown-icon-item': withIcon}"
>
<slot
name="item"
:item="item"
@@ -54,7 +56,3 @@ export default {
},
};
</script>
<style scoped lang="scss">
</style>
@@ -20,6 +20,7 @@
}"
>
<input
ref="textInput"
:value="value"
class="form-control"
:type="inputType"
@@ -29,19 +30,23 @@
}"
:readonly="readonly"
:aria-readonly="readonly"
autocomplete="off"
:placeholder="placeholder"
@keyup="handleChange"
@keyup.enter="$emit('enter')"
@blur="$emit('blur')"
>
</div>
<div
v-for="issue in invalidIssues"
:key="issue"
class="input-error"
>
{{ issue }} &nbsp;
</div>
<template v-if="!hideErrorLine">
<div
v-for="issue in invalidIssues"
:key="issue"
class="input-error"
>
{{ issue }} &nbsp;
</div>
</template>
</div>
</div>
</template>
@@ -85,6 +90,10 @@ export default {
type: Array,
default: () => [],
},
hideErrorLine: {
type: Boolean,
default: false,
},
},
data () {
return {
@@ -107,6 +116,9 @@ export default {
this.wasChanged = true;
this.$emit('update:value', value);
},
focus () {
this.$refs.textInput.focus();
},
},
};
</script>
@@ -128,4 +140,12 @@ export default {
margin-bottom: 0;
}
/* this removes safari "save username" UI, we only search for one, we dont want to save it */
input::-webkit-contacts-auto-fill-button,
input::-webkit-credentials-auto-fill-button {
visibility: hidden;
position: absolute;
right: 0;
}
</style>
+4 -13
View File
@@ -29,20 +29,12 @@
@import '~@/assets/scss/colors.scss';
.user-link { // this is the user name
font-family: 'Roboto Condensed', sans-serif;
font-weight: bold;
margin-bottom: 0;
cursor: pointer;
display: inline-block;
font-size: 16px;
// currently used in the member-details-new.vue
&.smaller {
font-family: Roboto;
font-size: 14px;
font-weight: bold;
line-height: 1.71;
}
font-size: 14px;
line-height: 1.71;
display: inline-flex !important;
&.no-tier {
color: $gray-50;
@@ -111,7 +103,6 @@ export default {
'backer',
'contributor',
'hideTooltip',
'smallerStyle',
'showBuffed',
'context',
],
@@ -173,7 +164,7 @@ export default {
return this.hideTooltip ? '' : achievementsLib.getContribText(this.contributor, this.isNPC) || '';
},
levelStyle () {
return `${this.userLevelStyleFromLevel(this.level, this.isNPC)} ${this.smallerStyle ? 'smaller' : ''}`;
return `${this.userLevelStyleFromLevel(this.level, this.isNPC)}`;
},
},
};
@@ -979,6 +979,7 @@
import moment from 'moment';
import axios from 'axios';
import each from 'lodash/each';
import find from 'lodash/find';
import cloneDeep from 'lodash/cloneDeep';
import achievementsLib from '@/../../common/script/libs/achievements';
import Content from '@/../../common/script/content';
@@ -1062,8 +1063,12 @@ export default {
},
computed: {
...mapState({
currentEventList: 'worldState.data.currentEventList',
flatGear: 'content.gear.flat',
}),
currentEvent () {
return find(this.currentEventList, event => Boolean(event.promo));
},
userJoinedDate () {
return moment(this.user.auth.timestamps.created)
.format(this.userLoggedIn.preferences.dateFormat.toUpperCase());
@@ -1257,6 +1262,7 @@ export default {
},
openSendGemsModal () {
this.user.g1g1 = this.currentEvent?.promo === 'g1g1';
this.$store.state.giftModalOptions.startingPage = 'buyGems';
this.$root.$emit('habitica::send-gift', this.user);
},
@@ -0,0 +1,102 @@
import debounce from 'lodash/debounce';
export const autoCompleteHelperMixin = {
data () {
return {
mixinData: {
autoComplete: {
caretPosition: 0,
coords: {
TOP: 0,
LEFT: 0,
},
},
},
};
},
methods: {
autoCompleteMixinHandleTab (e) {
if (this.$refs.autocomplete.searchActive) {
e.preventDefault();
if (e.shiftKey) {
this.$refs.autocomplete.selectPrevious();
} else {
this.$refs.autocomplete.selectNext();
}
}
},
autoCompleteMixinHandleEscape (e) {
if (this.$refs.autocomplete.searchActive) {
e.preventDefault();
this.$refs.autocomplete.cancel();
}
},
autoCompleteMixinSelectNextAutocomplete (e) {
if (this.$refs.autocomplete.searchActive) {
e.preventDefault();
this.$refs.autocomplete.selectNext();
}
},
autoCompleteMixinSelectPreviousAutocomplete (e) {
if (this.$refs.autocomplete.searchActive) {
e.preventDefault();
this.$refs.autocomplete.selectPrevious();
}
},
autoCompleteMixinSelectAutocomplete (e) {
if (this.$refs.autocomplete.searchActive) {
if (this.$refs.autocomplete.selected !== null) {
e.preventDefault();
this.$refs.autocomplete.makeSelection();
} else {
// no autocomplete selected, newline instead
this.$refs.autocomplete.cancel();
}
}
},
autoCompleteMixinUpdateCarretPosition: debounce(function updateCarretPosition (eventUpdate) {
this._updateCarretPosition(eventUpdate);
}, 250),
autoCompleteMixinResetCoordsPosition () {
this.mixinData.autoComplete.coords = {
TOP: 0,
LEFT: 0,
};
},
// https://medium.com/@_jh3y/how-to-where-s-the-caret-getting-the-xy-position-of-the-caret-a24ba372990a
_getCoord (e, text) {
const caretPosition = text.selectionEnd;
this.mixinData.autoComplete.caretPosition = caretPosition;
const div = document.createElement('div');
const span = document.createElement('span');
const copyStyle = getComputedStyle(text);
[].forEach.call(copyStyle, prop => {
div.style[prop] = copyStyle[prop];
});
div.style.position = 'absolute';
document.body.appendChild(div);
div.textContent = text.value.substr(0, caretPosition);
span.textContent = text.value.substr(caretPosition) || '.';
div.appendChild(span);
this.mixinData.autoComplete.coords = {
TOP: span.offsetTop,
LEFT: span.offsetLeft,
};
document.body.removeChild(div);
},
_updateCarretPosition (eventUpdate) {
const text = eventUpdate.target;
this._getCoord(eventUpdate, text);
},
},
};
+5 -3
View File
@@ -1,7 +1,7 @@
import notifications from './notifications';
import { NotificationMixins } from './notifications';
export default {
mixins: [notifications],
export const CopyToClipboardMixin = {
mixins: [NotificationMixins],
methods: {
async mixinCopyToClipboard (valueToCopy, notificationToShow = null) {
if (navigator.clipboard) {
@@ -21,3 +21,5 @@ export default {
},
},
};
export default CopyToClipboardMixin;
+8
View File
@@ -71,6 +71,7 @@ export default {
giftData,
gemsBlock,
sku,
g1g1,
} = data;
let { url } = data;
@@ -80,6 +81,10 @@ export default {
paymentType: type,
};
if (type === 'gift-subscription') {
appState.g1g1 = g1g1;
}
if (type === 'subscription') {
appState.subscriptionKey = this.subscriptionPlan || this.subscription.key;
}
@@ -164,6 +169,9 @@ export default {
paymentCompleted: false,
paymentType,
};
if (paymentType === 'gift-subscription') {
appState.g1g1 = data.g1g1;
}
if (paymentType === 'subscription') {
appState.subscriptionKey = sub.key;
} else if (paymentType === 'groupPlan') {
@@ -62,7 +62,7 @@
<script>
import moment from 'moment';
import userLabel from '../userLabel';
import userLabel from '../../components/userLabel.vue';
import dots from '@/assets/svg/dots.svg';
import block from '@/assets/svg/block.svg';
@@ -117,7 +117,7 @@ export default {
</script>
<style lang="scss">
@import '~@/assets/scss/colors.scss';
@import '~@/assets/scss/colors';
.action-padding {
height: 24px !important;
@@ -153,7 +153,7 @@ export default {
</style>
<style lang="scss" scoped>
@import '~@/assets/scss/colors.scss';
@import '~@/assets/scss/colors';
.conversation {
padding: 1rem 1.5rem;
@@ -0,0 +1,64 @@
<template>
<div
v-if="filtersConversations.length > 0"
class="conversations"
>
<conversation-item
v-for="conversation in filtersConversations"
:key="conversation.key"
:active-key="selectedConversation?.key"
:contributor="conversation.contributor"
:backer="conversation.backer"
:uuid="conversation.key"
:display-name="conversation.name"
:username="conversation.username"
:last-message-date="conversation.date"
:last-message-text="conversation.lastMessageText
? removeTags(parseMarkdown(conversation.lastMessageText)) : ''"
@click="selectConversation(conversation.key)"
/>
</div>
</template>
<style scoped lang="scss">
.conversations {
overflow-x: hidden;
overflow-y: auto;
height: 100%;
}
</style>
<script>
import { defineComponent } from 'vue';
import habiticaMarkdown from 'habitica-markdown';
import conversationItem from '@/pages/private-messages/pm-conversation-item.vue';
export default defineComponent({
components: { conversationItem },
props: {
filtersConversations: {
type: Array,
default: () => [],
},
selectedConversation: {
type: Object,
default: null,
},
},
methods: {
removeTags (html) {
const tmp = document.createElement('DIV');
tmp.innerHTML = html;
return tmp.textContent || tmp.innerText || '';
},
parseMarkdown (text) {
if (!text) return null;
return habiticaMarkdown.render(String(text));
},
selectConversation (conversationKey) {
this.$emit('selectConversation', conversationKey);
},
},
});
</script>
@@ -0,0 +1,37 @@
<template>
<div
class="pm-disabled-caption text-center"
>
<h4>{{ disabledTexts.title }}</h4>
<p>{{ disabledTexts.description }}</p>
</div>
</template>
<style scoped lang="scss">
@import '~@/assets/scss/colors.scss';
.pm-disabled-caption {
padding-top: 1.5em;
z-index: 2;
h4, p {
color: $gray-200;
}
h4 {
margin-top: 0;
margin-bottom: 0.4em;
}
p {
font-size: 12px;
margin-bottom: 0;
}
}
</style>
<script>
export default {
props: ['disabledTexts'],
};
</script>
@@ -0,0 +1,71 @@
<template>
<div
class="empty-messages m-auto text-center empty-sidebar"
>
<div class="no-messages-box">
<div
v-once
class="svg-icon envelope mb-4"
v-html="icons.mailIcon"
></div>
<strong
v-once
class="mb-1"
>
{{ $t('emptyMessagesLine1') }}
</strong>
<p v-if="!chatRevoked">
{{ $t('emptyMessagesLine2') }}
</p>
</div>
<button
class="btn btn-primary mt-4 d-flex align-items-center"
@click="$emit('newMessageClicked')"
>
<div
class="svg-icon icon-10 color mr-2"
v-html="icons.positive"
></div>
{{ $t('newMessage') }}
</button>
</div>
</template>
<style scoped lang="scss">
@import '~@/assets/scss/colors.scss';
strong {
line-height: 1.71;
color: $gray-100;
}
.svg-icon.icon-10 {
margin: 3px;
}
p {
font-size: 14px;
font-weight: 400;
line-height: 24px;
}
</style>
<script>
import mailIcon from '@/assets/svg/mail.svg';
import positiveIcon from '@/assets/svg/positive.svg';
export default {
props: {
chatRevoked: Boolean,
},
data () {
return {
icons: Object.freeze({
mailIcon,
positive: positiveIcon,
}),
};
},
};
</script>
@@ -0,0 +1,69 @@
<template>
<div
v-once
class="centered empty-messages m-auto text-center"
>
<avatar
v-if="memberObj"
:member="memberObj"
:avatar-only="true"
:show-weapon="false"
:hide-class-badge="true"
:override-top-padding="'0px'"
:sprites-margin="'0 0 0 -30px'"
:debug-mode="false"
:center-avatar="true"
class="mb-3"
/>
<strong>{{ memberObj.profile.name }}</strong>
<div class="username mb-3">
@{{ memberObj.auth.local.username }}
</div>
<div
class="kind-text"
v-html="$t('rememberToBeKind')"
></div>
</div>
</template>
<style scoped lang="scss">
@import '~@/assets/scss/colors.scss';
.centered {
align-content: center;
}
.center-avatar {
margin: 0 auto;
}
strong {
line-height: 1.71;
}
.username {
font-size: 12px;
line-height: 1.33;
color: $gray-100;
margin-top: -4px;
}
.kind-text {
width: 330px;
line-height: 1.71;
color: $gray-100;
}
</style>
<script>
import Avatar from '@/components/avatar.vue';
export default {
components: { Avatar },
props: {
memberObj: null,
},
};
</script>
@@ -0,0 +1,44 @@
export namespace PrivateMessages {
// Shared properties between message types
interface SharedMessageProps {
username: string;
contributor: Record<string, unknown>;
userStyles: Record<string, unknown>;
canReceive: boolean;
}
/**
* This is the Type we get from our API
*/
interface ConversationSummaryMessageEntry extends SharedMessageProps {
uuid: string;
user: string;
timestamp: string;
text: string;
count: number;
}
/**
* The Visual (Sidebar) Entry
*/
interface ConversationEntry extends SharedMessageProps {
/**
* UUID
*/
key: string;
name: string;
lastMessageText: '',
canLoadMore: boolean;
page: 0
}
/**
* Loaded Private Messages, partial type
*/
interface PrivateMessageEntry extends SharedMessageProps {
text: string;
}
}
@@ -0,0 +1,167 @@
<template>
<div class="ml-4">
<strong
v-once
v-html="$t('to')"
></strong>
<validated-text-input
id="selectUser"
ref="targetUserInput"
v-model="targetUserInputValue"
class="mx-2"
:is-valid="foundUser._id"
:only-show-invalid-state="foundUser._id === undefined"
:hide-error-line="true"
:placeholder="$t('usernameOrUserId')"
:invalid-issues="userInputInvalidIssues"
@enter="triggerNewConversation"
/>
<button
class="btn btn-primary"
:disabled="preventTrigger"
@click="triggerNewConversation()"
>
{{ $t('confirm') }}
</button>
<button
class="ml-2 btn btn-secondary"
@click="$emit('cancelNewConversation')"
>
{{ $t('cancel') }}
</button>
</div>
</template>
<style scoped lang="scss">
@import '~@/assets/scss/colors.scss';
div {
display: flex;
align-items: center;
}
div > * {
height: 32px;
}
strong {
line-height: 1.71;
align-content: center;
}
input {
border-radius: 2px;
border-width: 2px;
width: 420px;
}
#selectUser {
/* changing the style of validate-text-input to the same as others */
::v-deep {
.input-group {
border-width: 2px;
input {
width: 420px;
height: 100%;
color: $gray-50;
}
}
.input-group {
&:focus, &:active, &:focus-within {
border: solid 2px $purple-400;
}
}
}
}
</style>
<script>
import debounce from 'lodash/debounce';
import isUUID from 'validator/es/lib/isUUID';
import ValidatedTextInput from '@/components/ui/validatedTextInput.vue';
export default {
components: {
ValidatedTextInput,
},
mixins: [],
data () {
return {
targetUserInputValue: '',
userNotFound: false,
foundUser: {},
};
},
computed: {
preventTrigger () {
return this.targetUserInputValue.length < 2;
},
userInputInvalidIssues () {
return this.targetUserInputValue.length > 0 && this.userNotFound
? [this.$t('userWithUsernameOrUserIdNotFound')]
: [''];
},
},
watch: {
targetUserInputValue: {
handler () {
this.searchUser(this.targetUserInputValue.replace('@', ''));
},
},
},
mounted () {
this.$refs.targetUserInput.focus();
},
methods: {
close () {
this.$root.$emit('bv::hide::modal', 'select-user-modal');
},
searchUser: debounce(async function userSearch (searchTerm = '') {
this.foundUser = {};
if (searchTerm.length < 1) {
this.userNotFound = false;
return;
}
let result;
if (isUUID(searchTerm)) {
try {
result = await this.$store.dispatch('members:fetchMember', {
memberId: searchTerm,
});
} catch {
result = null;
}
} else {
try {
result = await this.$store.dispatch('members:fetchMemberByUsername', {
username: searchTerm,
});
} catch {
result = null;
}
}
if (!result) {
this.userNotFound = true;
return;
}
this.userNotFound = false;
this.foundUser = result;
}, 500),
triggerNewConversation () {
const userWithoutAt = this.$refs.targetUserInput.value.replace('@', '');
this.$emit('startNewConversation', userWithoutAt);
},
},
};
</script>
+1 -1
View File
@@ -49,7 +49,7 @@ const GroupPlanIndex = () => import(/* webpackChunkName: "group-plans" */ '@/com
const GroupPlanTaskInformation = () => import(/* webpackChunkName: "group-plans" */ '@/components/group-plans/taskInformation');
const GroupPlanBilling = () => import(/* webpackChunkName: "group-plans" */ '@/components/group-plans/billing');
const MessagesIndex = () => import(/* webpackChunkName: "private-messages" */ '@/pages/private-messages');
const MessagesIndex = () => import(/* webpackChunkName: "private-messages" */ '@/pages/private-messages/index.vue');
// Challenges
const ChallengeIndex = () => import(/* webpackChunkName: "challenges" */ '@/components/challenges/index');
+8 -1
View File
@@ -43,7 +43,14 @@ export async function deleteChat (store, payload) {
}
export async function like (store, payload) {
const url = `/api/v4/groups/${payload.groupId}/chat/${payload.chatId}/like`;
let url = '';
if (payload.groupId === 'privateMessage') {
url = `/api/v4/inbox/like-private-message/${payload.chatMessageId}`;
} else {
url = `/api/v4/groups/${payload.groupId}/chat/${payload.chatMessageId}/like`;
}
const response = await axios.post(url);
return response.data.data;
}
@@ -1,14 +1,16 @@
import Vue from 'vue';
import { shallowMount, createLocalVue } from '@vue/test-utils';
import ChatCard from '@/components/chat/chatCard.vue';
import BootstrapVue from 'bootstrap-vue';
import MessageCard from '@/components/messages/messageCard.vue';
import Store from '@/libs/store';
const localVue = createLocalVue();
localVue.use(Store);
localVue.use(Vue.directive('b-tooltip', {}));
localVue.use(BootstrapVue);
describe('ChatCard', () => {
describe('MessageCard', () => {
function createMessage (text) {
return { text, likes: {} };
}
@@ -26,7 +28,7 @@ describe('ChatCard', () => {
let wrapper;
beforeEach(() => {
wrapper = shallowMount(ChatCard, {
wrapper = shallowMount(MessageCard, {
propsData: { msg: message },
store: new Store({
state: {
+1 -1
View File
@@ -1,5 +1,5 @@
{
"achievement": "Постижение",
"achievement": "Достижения",
"onwards": "Напред!",
"levelup": "Изпълнявайки целите си в истинския живот, Вие се качихте ниво и здравето Ви беше запълнено!",
"reachedLevel": "Достигнахте Ниво <%= level %>",
+10 -4
View File
@@ -789,7 +789,7 @@
"backgroundBirthdayBashNotes": "Habitica feiert eine Geburtstagsparty und alle sind eingeladen!",
"eventBackgrounds": "Ereignis-Hintergründe",
"backgroundBirthdayBashText": "Geburtstagsparty",
"backgroundInsideACrystalNotes": "Schaue aus einem Kristall hinaus.",
"backgroundInsideACrystalNotes": "Schau aus dem Inneren eines Kristalls heraus.",
"backgrounds072023": "SET 110: Veröffentlicht im Juli 2023",
"backgroundOnAPaddlewheelBoatText": "Auf einem Schaufelradboot",
"backgroundOnAPaddlewheelBoatNotes": "Fahre mit einem Schaufelradboot.",
@@ -820,9 +820,9 @@
"backgroundIceSculptureFestivalText": "Eisskulptur Festival",
"backgroundIceSculptureFestivalNotes": "Besuche ein Eisskulptur Festival.",
"backgroundWinterFullMoonNotes": "Bestaune den Wintervollmond.",
"backgroundBarrelCellarText": "Faßkeller",
"backgroundBarrelCellarText": "Fasskeller",
"backgrounds112023": "SET 114: Veröffentlicht im November 2023",
"backgroundBarrelCellarNotes": "Schau dich im Faßkeller nach Tafelfreuden um.",
"backgroundBarrelCellarNotes": "Schau dich im Fasskeller nach Tafelfreuden um.",
"backgroundSpectralCandleRoomText": "Raum der gespenstischen Kerzen",
"backgroundSpectralCandleRoomNotes": "Sprich mit Geistern im Raum der gespenstischen Kerzen.",
"backgroundMonstrousCaveText": "Monströse Höhle",
@@ -885,5 +885,11 @@
"backgrounds102024": "Set 124: Veröffentlicht im September 2024",
"backgroundCastleHallWithHearthText": "Schlosshalle mit Feuerstelle",
"backgrounds112024": "SET 126: Veröffentlicht im November 2024",
"backgroundCastleHallWithHearthNotes": "Entspanne dich in der Wärme einer Schlosshalle mit einer Feuerstelle."
"backgroundCastleHallWithHearthNotes": "Entspanne dich in der Wärme einer Schlosshalle mit einer Feuerstelle.",
"backgrounds122024": "SET 127: Veröffentlicht im Dezember 2024",
"backgroundFirstSnowForestText": "Der erste Schnee im Wald",
"backgroundFirstSnowForestNotes": "Tritt in den ersten Schnee im Wald.",
"backgrounds012025": "Set 128: Veröffentlicht im Januar 2025",
"backgroundWinterLandscapeWithCabinText": "Winterlandschaft mit Hütte",
"backgroundWinterLandscapeWithCabinNotes": "Macht es dir in einer Winterlandschaft mit einer Hütte gemütlich."
}
+2 -1
View File
@@ -391,5 +391,6 @@
"questEggRaccoonAdjective": "ein gefräßiger",
"questEggDogText": "Welpe",
"questEggDogMountText": "Hund",
"questEggDogAdjective": "ein freundlicher"
"questEggDogAdjective": "ein freundlicher",
"hatchingPotionGingerbread": "Lebkuchen"
}
+1 -1
View File
@@ -16,7 +16,7 @@
"webFaqAnswer34": "Haustiere mögen Futter, das zu ihrer Farbe passt. Basis-Tiere sind die Ausnahme, aber alle Basis-Tiere mögen den gleichen Gegenstand. Im Folgenden siehst du, welche Nahrungsmittel jedes Haustier mag:\n\n * Basistiere mögen Fleisch\n * Weiße Haustiere mögen Milch\n * Wüstenhaustiere mögen Kartoffeln\n * Rote Haustiere mögen Erdbeeren\n * Schattentiere mögen Schokolade\n * Skelett-Tiere mögen Fisch\n * Zombie-Tiere mögen verdorbenes Fleisch\n * Zuckerwatte rosa Haustiere mögen rosa Zuckerwatte\n * Zuckerwatte blaue Haustiere mögen blaue Zuckerwatte\n * Goldene Haustiere mögen Honig",
"webFaqAnswer35": "Sobald du dein Haustier genug gefüttert hast, um es zu einem Reittier zu machen, musst du diese Art von Haustier erneut ausbrüten, um es in deinem Stall zu haben.\n\nUm Reittiere in den mobilen Apps zu sehen:\n\n * Wähle im Menü \"Haustiere & Reittiere\" und wechseln zur Registerkarte \"Reittiere\".\n\nSo zeigst du Reittiere auf der Website an:\n\n * Wähle im Menü \"Inventar\" die Option \"Haustiere und Reittiere\" und scrollen nach unten zum Abschnitt \"Reittiere\"",
"webFaqAnswer37": "Kontrolliere, ob die Option Kostüm aktiviert ist. Wenn dein Avatar ein Kostüm trägt, wird dieses Ausrüstungsset anstelle deiner Kampfausrüstung angezeigt.\n\nSo schaltest du das Kostüm in den mobilen Apps ein:\n * Wähle im Menü \"Ausrüstung\", um den Schalter für das Kostüm zu finden.\n\nSo schaltest du das Kostüm auf der Website um:\n * Wähle in deinem Inventar \"Ausrüstung\" und suche den Schalter \"Kostüm\" auf der Registerkarte \"Kostüm\" in der Ausrüstungsschublade",
"webFaqAnswer41": "Mystische Sanduhren sind die exklusive Abonnentenwährung von Habitica, die im Mysteriöse Zeitreisende Laden verwendet wird! Sanduhren werden nach einem bestimmten Zeitplan geliefert, der auf Ihrem Abonnementplan basiert.\n\nZeitplan für die Lieferung von Sanduhren:\n * 1-Monats-Abonnenten erhalten 1 Sanduhr am Anfang des Monats nach der 3. aufeinanderfolgenden Zahlung.\n * 3-Monats-Abonnenten erhalten 1 Sanduhr sofort nach Abschluss des Abonnements, dann 1 weitere Sanduhr zu Beginn des Monats nach jeder Erneuerung.\n * 6-Monats-Abonnenten erhalten 2 Sanduhren sofort nach Abschluss des Abonnements, dann 2 weitere Sanduhren zu Beginn des Monats nach jeder Verlängerung.\n * 12-Monats-Abonnenten erhalten 4 Sanduhren sofort nach Abschluss des Abonnements, dann 4 weitere Sanduhren zu Beginn des Monats nach jeder Verlängerung.",
"webFaqAnswer41": "Mystische Sanduhren sind die exklusive Abonnentenwährung von Habitica, die im Zeitreisenden-Shop verwendet wird. Abonnenten erhalten 1 Mystische Sanduhr am Anfang jedes Monats, in dem sie Abonnenten-Vorteile haben, zusammen mit einigen weiteren Vorteilen. Bitte beachte unsere Abonnement-Optionen, wenn Du an den besonderen Hintergründen-, Haustier-, Quest- und Ausrüstungsangeboten im Zeitreisenden-Shop interessiert bist!",
"webFaqAnswer42": "Eine der besten Möglichkeiten, sich zu motivieren und sich selbst für die Erledigung von Aufgaben verantwortlich zu machen, ist der Beitritt zu einer Gruppe! Eine Party mit anderen Habitica-Spielern ist eine großartige Möglichkeit, Quests anzunehmen, um Haustiere und Ausrüstung zu erhalten, Stärkungszauber von den Fertigkeiten der Party-Mitglieder zu bekommen und deine Motivation zu steigern.\n\nEine weitere Möglichkeit, die Verantwortlichkeit zu erhöhen, ist die Teilnahme an einer Herausforderung. Herausforderungen fügen eurer Liste automatisch Aufgaben hinzu, die mit einem bestimmten Ziel verbunden sind! Außerdem bieten sie ein Element des Wettbewerbs mit anderen Habitica-Spielern, das dir einen Motivationsschub geben kann, während du nach dem Edelsteinpreis strebst. Es gibt offizielle Herausforderungen, die vom Habitica-Team erstellt wurden, sowie Herausforderungen, die von anderen Spielern erstellt wurden.",
"webFaqAnswer44": "Du musst die Challenge verlassen oder warten, bis die Challenge geschlossen wird, um die zugehörigen Aufgaben zu löschen. Ein rotes Megaphon-Symbol bedeutet, dass die Challenge geschlossen wurde, ein graues Megaphon bedeutet, dass die Challenge noch läuft.\n\nSo löschst du Challenge-Aufgaben in der **Android**-App:\n 1. Tippe auf eine Aufgabe, die zur Challenge gehört.\n 2. Tippe auf \"Löschen\" in der oberen rechten Ecke des Bildschirms.\n 3. Wähle, um die Aufgaben der Herausforderung aus deiner Aufgabenliste zu entfernen.\n\nSo löschst du Challenge-Aufgaben in der **iOS**-App:\n 1. Suche die Challenge-Aufgabe, die du löschen möchtest, und sieh dir das Megaphon-Symbol an.\n 2. Wenn das Megaphon-Symbol rot ist, tippe auf die Aufgabe und wähle unten \"Löschen\".\n 3. Wenn das Megaphon-Symbol grau ist, musst du die Herausforderung finden und sie verlassen.\n\nSo löschst du Challenge-Aufgaben auf der **Website**:\n 1. Suche die Challenge-Aufgabe, die du löschen möchtest, und sieh dir das Megaphon-Symbol an.\n 2. Wenn das Megaphon-Symbol rot ist, klicke darauf und wähle dann, die Aufgabe aus deiner Aufgabenliste zu entfernen.\n 3. Wenn das Megaphon-Symbol grau ist, musst du die Herausforderung finden und sie verlassen, um die Aufgabe zu entfernen.",
"sunsetFaqPara5": "Wenn Sie mehr über die Änderungen erfahren möchten, ließ bitte die folgenden Informationen.",
+255 -2
View File
@@ -2924,7 +2924,7 @@
"armorSpecialFall2024HealerText": "Space Invader Rüstung",
"armorSpecialFall2024HealerNotes": "Sei eins mit der Galaxis und hypnotisiere Zuschauer mit dieser Rüstung. Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe 2024 Herbstausrüstung.",
"armorSpecialFall2024MageText": "Unterwelt Hexer Rüstung",
"armorSpecialFall2024MageNotes": "Sei eins mit der Unterwelt und umarme die Macht der Magier, die vor dir diese Rüstung trugen. Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe 2024 Herbstaausrüstung.",
"armorSpecialFall2024MageNotes": "Sei eins mit der Unterwelt und umarme die Macht der Magier, die vor dir diese Rüstung trugen. Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe 2024 Herbstausrüstung.",
"weaponArmoireFunnyFoolBatonNotes": "Du kannst mit einem Schwung Deines Stabes eine Pointe vortragen, die Aufmerksamkeit erregen oder Beifall ernten. Erhöht Ausdauer und Stärke jeweils um <%= attrs %>. Verzauberter Schrank: Lustiges Narren-Set (Gegenstand 3 von 3)",
"armorArmoireTeaGownText": "Teeparty Kleid",
"armorArmoireTeaGownNotes": "Du bist zäh, kreativ, brilliant und so modisch! Erhöht Stärke und Intelligenz um jeweils <%= attrs %>. Verzauberter Schrank: Teeparty Set (Gegenstand 1 von 3).",
@@ -2936,5 +2936,258 @@
"weaponArmoireSpookyCandyBucketText": "Grusliger Süßigkeiten Eimer",
"armorMystery202407Notes": "Gleite durch Seen und Kanäle mit deinem hin und her fegenden rosa Schwanz! Gewährt keinen Attributbonus. Juli 2024 Abonnentengegenstand.",
"armorArmoireJewelersApronText": "Juweliers-Schürze",
"armorArmoireJewelersApronNotes": "Diese Hochleistungsschürze ist genau das Richtige zum Anziehen, wenn du dich kreativ fühlst. Das Beste daran sind die Dutzende kleiner Taschen, um alles, was du brauchst, darin zu verstauen. Erhöht Intelligenz um <%= int %>. Verzauberter Schrank: Juwelier Set (Gegenstand 1 von 4)."
"armorArmoireJewelersApronNotes": "Diese Hochleistungsschürze ist genau das Richtige zum Anziehen, wenn du dich kreativ fühlst. Das Beste daran sind die Dutzende kleiner Taschen, um alles, was du brauchst, darin zu verstauen. Erhöht Intelligenz um <%= int %>. Verzauberter Schrank: Juwelier Set (Gegenstand 1 von 4).",
"armorArmoireBlueStripedSwimsuitText": "Blau gestreifter Badeanzug",
"armorArmoireSmileyShirtText": "Shirt mit Smiley-Gesicht",
"armorArmoireSoftWhiteSuitText": "Weicher weißer Anzug",
"armorArmoireSchoolUniformPantsText": "Schuluniform mit Hose",
"armorArmoireSchoolUniformSkirtNotes": "Ob du nun eine Schule für magische Zauberer, Drachenreiter, Ballsportspieler, kreative Künstler oder Mitglieder einer Organisation, die zu geheim ist, um sie hier aufzuzählen, besuchst, du wirst mit dieser Uniform gut dazu passen. Erhöht Intelligenz um <%= int %>.Verzauberter Schrank: Schuluniform-Set (Gegenstand 1 von 4).",
"armorArmoireHattersSuitNotes": "Dein Outfit ist nicht vollständig ohne deine grüne Glücks-Fliege. Trage dies zu deiner nächsten verrückten Teeparty. Oder angenehmen Teeparty. Oder begeisterten Teeparty. Oder... Erhöht Ausdauer um <%= con %>. Verzauberter Schrank: Hutmacher-Set (Gegenstand 2 von 4).",
"armorArmoireBlueStripedSwimsuitNotes": "Was könnte spannender sein als Seemonster am Strand zu bekämpfen? Erhöht Ausdauer um <%= con %>. Verzauberter Schrank: Strand-Set (Gegenstand 2 von 4).",
"armorArmoireSchoolUniformPantsNotes": "Ob du nun eine Schule für magische Zauberer, Drachenreiter, Ballsportspieler, kreative Künstler oder Mitglieder einer Organisation, die zu geheim ist, um sie hier aufzuzählen, besuchst, du wirst mit dieser Uniform gut dazu passen. Erhöht Intelligenz um <%= int %>.Verzauberter Schrank: Schuluniform-Set (Gegenstand 2 von 4).",
"armorArmoireGreenFluffTrimmedCoatNotes": "Sagen erzählen, dass einmal in einer Generation ein Mantel daherkommt, der der wärmste und bequemste von allen ist. Sein Flausch ist außergewöhnlich und seine Knöpfe sind sogar von fäustlingsumhüllten Händen handhabbar. Das ist dieser Mantel hier. Erhöht Stärke und Intelligenz um jeweils <%= attrs %>. Verzauberter Schrank: Fallenstellerhut-Set (Gegenstand 2 von 2).",
"armorArmoireSoftWhiteSuitNotes": "Weiß ist eine friedvolle Farbe. Ob du nun ein strahlend weißes Bettlaken oder eine Decke aus frischgefallenem Schnee betrachtest, du wirst einen klaren und vorbereiteten Geist haben. Erhöht Ausdauer um <% con %> und Wahrnehmung um <%= per %>. Verzauberter Schrank: Weiße Lounge-Kleidung (Gegenstand 2 von 3).",
"armorArmoireCorsairsCoatAndCapeText": "Mantel und Umhang des Korsaren",
"armorArmoireSmileyShirtNotes": "Weil du glücklich bist! Zeig der Welt, dass du heute den ganzen Tag lächelst. Erhöht Intelligenz und Wahrnehmung um jeweils <%= attrs %>. Verzauberter Schrank: Optimisten-Set (Gegenstand 1 von 4).",
"armorArmoireYellowStripedSwimsuitText": "Gelb gestreifter Badeanzug",
"armorArmoireYellowStripedSwimsuitNotes": "Was könnte erfreulicher sein als Seemonster am Strand zu bekämpfen? Erhöht Ausdauer um <%= con %>. Verzauberter Schrank: Strand-Set (Gegenstand 1 von 4).",
"armorArmoireGreenFluffTrimmedCoatText": "Mantel mit grünem Flauschband",
"armorArmoireSchoolUniformSkirtText": "Schuluniform mit Rock",
"armorArmoireHattersSuitText": "Anzug des Hutmachers",
"armorArmoireKarateGiText": "Karate Gi",
"armorArmoireKarateGiNotes": "Diese leichte Karate-Uniform ist perfekt für Training oder Wettbewerbe. Erhöht Stärke um <%= str %>. Verzauberter Schrank: Karate-Set (Gegenstand 1 von 10).",
"weaponArmoireStormKnightAxeText": "Axt des Sturmritters",
"weaponArmoireStormKnightAxeNotes": "Sammle deine Wut und schlage wie ein Donnerschlag zu! Erhöht Stärke um <%= str %>. Verzauberter Schrank: Sturmritter-Set (Gegenstand 3 von 3)",
"armorArmoireDiagonalRainbowShirtNotes": "Ein Klecks Farbe mit einem Schuss Stil. Sei fröhlich! Erhöht Ausdauer und Wahrnehmung um jeweils <%= attrs %> . Verzauberter Schrank: Regenbogen-Set (Gegenstand 2 von 2).",
"armorArmoireAdmiralsUniformText": "Admirals-Uniform",
"armorArmoireAdmiralsUniformNotes": "Wir salutieren dir! Diese Marineuniform signalisiert, dass du bereit bist, das Kommando sowohl von deinen Aufgaben als auch von einem Schiff zu übernehmen. Erhöht Ausdauer und Stärke um jeweils <%= attrs %> . Verzauberter Schrank: Admirals-Set (Gegenstand 2 von 2).",
"armorArmoireShawlCollarCoatText": "Schalkragen-Mantel",
"armorArmoireStripedRainbowShirtText": "Gestreiftes Regenbogen-Shirt",
"armorArmoireStripedRainbowShirtNotes": "Die Farben des Regenbogens sahen noch nie zuvor so gut aus. Sei mutig! Erhöht Stärke und Intelligenz um jeweils <%= attrs %>. Verzauberter Schrank: Regenbogen-Set (Gegenstand 1 von 2).",
"armorArmoireDiagonalRainbowShirtText": "Diagonales Regenbogen-Shirt",
"armorArmoireBasketballUniformText": "Basketball-Uniform",
"armorArmoireBasketballUniformNotes": "Fragst du dich, was auf dem Rücken dieser Uniform aufgedruckt ist? Deine Glückszahl, natürlich! Erhöht Wahrnehmung um <%= per %>.Verzauberter Schrank: Altertümliches Basketballset (Gegenstand 1 von 2).",
"armorArmoireShawlCollarCoatNotes": "Ein weiser Zauberer sagte einst, dass nichts besser ist als es sowohl gemütlich zu haben als auch produktiv zu sein! Trage diesen warmen und stylischen Mantel, wenn du die diesjährigen Herausforderungen meisterst. Erhöht Ausdauer um <%= con %>.",
"armorArmoirePaintersApronText": "Schürze des Malers",
"armorArmoirePaintersApronNotes": "Diese Schürze kann deine Kleidung vor Farbe und deine kreativen Projekte vor harschen Kritiken schützen. Erhöht Ausdauer um <%= con %>. Verzauberter Schrank: Maler-Set (Gegenstand 1 von 4).",
"weaponSpecialWinter2025WarriorText": "Axt des Elchkriegers",
"weaponSpecialWinter2025WarriorNotes": "Eine mächtige Axt für einen mächtigen Elch! Du wirst unaufhaltbar sein! Erhöht Stärke um <%= str %>. Limitierte Ausgabe 2024-2025 Winterausrüstung.",
"weaponSpecialWinter2025RogueText": "Schneeflockenausbruch",
"weaponSpecialWinter2025RogueNotes": "Stampfe und blende diese schwierigen Aufgaben zur Unterwerfung! Du wirst unaufhaltbar sein! Erhöht Stärke um <%= str %>.Limitierte Ausgabe 2024-2025 Winterausrüstung.",
"weaponSpecialWinter2025HealerText": "Sternenzauberstab",
"weaponSpecialWinter2025HealerNotes": "Was du jetzt brauchst, sind mehr Lichter und ein leuchtender Stern obendrauf! Du wirst unaufhaltbar sein! Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe 2024-2025 Winterausrüstung.",
"weaponSpecialWinter2025MageText": "Nordlicht-Display",
"weaponSpecialWinter2025MageNotes": "Diese beeindruckende, farbenfrohe Show bietet die perfekte Kulisse! Du wirst unaufhaltbar sein! Erhöht Intelligenz um <%= int %> und Wahrnehmung um <%= per %>. Limitierte Ausgabe 2024-2025 Winterausrüstung.",
"armorSpecialWinter2025WarriorText": "Rüstung des Elchkriegers",
"armorSpecialWinter2025RogueText": "Schneekostüm",
"armorSpecialWinter2025HealerText": "Lichterketten-Robe",
"armorSpecialWinter2025HealerNotes": "Funkle Deinen Weg durch deine Aufgaben. Sei nur vorsichtig - wenn eine Birne ausgeht, gehen alle aus. Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe 2024-2025 Winterausrüstung.",
"armorSpecialWinter2025MageText": "Aurora-Umhang",
"armorSpecialWinter2025MageNotes": "Wunder, Exzentrik, Verzauberung und Pracht werden Deine Tage füllen, wenn Du in diesem Umhang tanzt. Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe 2024-2025 Winterausrüstung.",
"armorSpecialWinter2025WarriorNotes": "Jeder wird beiseitetreten und Dir Platz machen, wenn Du diese Rüstung trägst. Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe 2024-2025 Winterausrüstung.",
"armorSpecialWinter2025RogueNotes": "Auch wenn Du so ausiehst, als wärst Du mit kaltem Schnee bedeckt, bist Du angenehm gewärmt, ausgelassen und glücklich, wenn du dieses Kostüm trägst. Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe 2024-2025 Winterausrüstung.",
"armorMystery202412Text": "Zuckerstangen-Waldkaninchen-Umhang",
"armorMystery202412Notes": "Ein unterhaltsamer und fluffiger Look, um dich an einem Wintertag gemütlich zu halten. Gewährt keinen Attributbonus. Dezember 2024 Abonnentengegenstand.",
"armorArmoireDragonKnightsArmorText": "Drachenritterrüstung",
"armorArmoireFunnyFoolCostumeText": "Kostüm des lustigen Narren",
"armorArmoireStormKnightArmorText": "Rüstung des Sturmritters",
"armorArmoireCorsairsCoatAndCapeNotes": "Ob Du nun deine Zeit an den Docks totschlägst oder auf dem offenen Meer nach Gefahren Aussschau hältst, werden diese Dich mit Sicherheit trocken halten und Dich dramatisch aussehen lassen. Halte nur das Gleichgewicht an Deck. Erhöht Ausdauer um <%= con %>. Verzauberter Schrank: Korsaren-Set (Gegenstand 1 von 3)",
"armorArmoireDragonKnightsArmorNotes": "Bündle die Stärke und Macht eines Drachen mit dieser Rüstung aus Silber und verlorenen Schuppen. Erhöht Stärke um <%= str %>. Verzauberter Schrank: Drachenritter-Set (Gegenstand 2 von 3)",
"armorArmoireFunnyFoolCostumeNotes": "Dum-di-dum! Sicher scherzest Du. Dieses farbenfrohe Outfit steht Dir ausgezeichnet! Erhöht Stärke um <%= str %>. Verzauberter Schrank: Lustiger Narr-Set (Gegenstand 2 von 3)",
"armorArmoireStormKnightArmorNotes": "In dieser Rüstung bist Du fast unverwundbar. Deine Feinde werden niemals das Ende des Sturms sehen. Erhöht Wahrnehmung um <%= per %>. Verzauberter Schrank: Sturmritter-Set (Gegenstand 2 von 3)",
"headSpecialWinter2023WarriorNotes": "Dieser Walrosshelm eignet sich hervorragend um mit einem Freund zu plaudern oder an einer pfiffigen Mahlzeit teilzunehmen. Erhöht Stärke um <%= str %>. Limitierte Ausgabe 2022-2023 Winterausrüstung.",
"armorArmoireFestiveHelperOverallsText": "Festliche Helfer-Latzhosen",
"headSpecialWinter2023WarriorText": "Walrosshelm",
"armorArmoireFestiveHelperOverallsNotes": "Diese strapazierfähige und bequeme Latzhose eignet sich hervorragend um zu arbeiten, zu spielen und andere zu unterstützen. Außerdem hat sie Taschen! Erhöht Ausdauer um <%= con %>. Verzauberter Schrank: Festliches Helferset (Gegenstand 2 von 2)",
"eyewearMystery202308Text": "Schläfrige Augen",
"headSpecialWinter2023RogueText": "Geschenkschleife",
"headSpecialWinter2023RogueNotes": "Die Versuchung der Leute, dein Haar „auszupacken“, gibt dir Gelegenheit, das Ducken und Ausweichen zu üben. Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe 2022-2023 Winterausrüstung.",
"headSpecialWinter2023MageText": "Feenlicht-Diadem",
"headSpecialSpring2023RogueText": "Raupen-Kutte",
"headSpecialWinter2023MageNotes": "Wurdest du mit einem Sternennacht-Elixier ausgebrütet? Denn ich habe für dich Sterne in meinen Augen. Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe 2022-2023 Winterausrüstung.",
"headSpecialWinter2023HealerNotes": "Dieser kardinalrote Helm eignet sich perfekt, um die Wintersaison durch pfeifen und singen einzuläuten. Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe 2022-2023 Winterausrüstung.",
"headSpecialWinter2023HealerText": "Kardinalroter Helm",
"headSpecialSpring2023RogueNotes": "Achte darauf, dass du diese verlockenden Fühler einziehst, wenn Vögel über dir jagen! Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe 2023 Frühlingsausrüstung.",
"headSpecialFall2024MageNotes": "Ob Du nun geheimnisvoll oder skurril bist, man wird Dich nicht übersehen, wenn Du dies trägst! Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe Herbst-Ausrüstung 2024.",
"headSpecialFall2024MageText": "Zauberer-Maske der Unterwelt",
"shieldSpecialWinter2025HealerNotes": "Das perfekte Geschenk wartet nur darauf, geöffnet zu werden. Was könnte drin sein? Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe Wintergegenstand 2024-2025.",
"shieldSpecialWinter2025HealerText": "Das Perfekte Geschenk",
"eyewearArmoireJewelersEyeLoupeNotes": "Diese Augenlupe vergrößert das zu bearbeitende Objekt, sodass Du jedes Detail sehen kannst. Erhöht Wahrnehmung um <%= per %>. Verzauberter Schrank: Juwelierset (Gegenstand 1 von 2).",
"eyewearArmoireJewelersEyeLoupeText": "Juwelier-Augenlupe",
"headSpecialSpring2023WarriorText": "Kolibri Helm",
"headSpecialSpring2023MageNotes": "Du solltest diese Gläser in der Nacht tragen, damit du bei Mondlicht klar sehen kannst. Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe 2023 Frühlingsausrüstung.",
"headSpecialSpring2023WarriorNotes": "Bedecke dein Gesicht mit irisierenden Federn, wenn du in die Schlacht fliegst. Erhöht Stärke um <%= str %>. Limitierte Ausgabe 2023 Frühlingsausrüstung.",
"headSpecialSpring2023MageText": "Mondstein Visier",
"headSpecialSummer2023RogueText": "Guppy Kappe",
"headSpecialSummer2023WarriorText": "Goldfisch Flosse",
"headSpecialSummer2023WarriorNotes": "Diese fabelhafte Flosse gibt dir Stabilität, wenn du mühsamen, vor dir liegenden Aufgaben entgegenschwimmst. Erhöht Stärke um <%= str %>. Limitierte Ausgabe 2023 Sommerausrüstung.",
"headSpecialSummer2023RogueNotes": "Gup, zwo, drei vier! Keine Zeit, gegessen zu werden, muß Aufgaben abhaken! Erhöht Wahrnehmung um <%= per %>.Limitierte Ausgabe 2023 Sommerausrüstung.",
"headSpecialSpring2023HealerText": "Lilien Blüte",
"headSpecialSummer2023MageText": "Korallen-Geweih",
"headSpecialSummer2023MageNotes": "Die Weisheit eines ganzen Ökosystems ist mit dir, wenn du deine maritime Magie wirkst. Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe 2023 Sommerausrüstung.",
"headSpecialSummer2023HealerNotes": "Das sind keine Schlangen! Du kannst deine Augen öffnen, es ist sicher! Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe 2023 Sommerausrüstung.",
"headSpecialSummer2023HealerText": "Seetang Krone",
"headSpecialFall2023RogueNotes": "Dieser verhexte Eintopf hat dir das haarige Gesicht und die langen Ohren eines Esels beschert! Wie überaus shakespeareisch. Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe 2023 Herbstausrüstung.",
"headSpecialFall2023RogueText": "Verzaubertes Gesicht",
"headSpecialFall2023WarriorText": "Spukschirm",
"headSpecialFall2023WarriorNotes": "Welcher Horror lauert in diesem Reich der Verzerrung und des Rauschens? Du musst am Ball bleiben, um das herauszufinden! Erhöht Stärke um <%= str %>. Limitierte Ausgabe 2023 Herbstausrüstung.",
"headSpecialFall2023MageText": "Scharlachrote Hexenmeister Maske",
"headSpecialFall2023MageNotes": "Mit stechenden Augen und pointiertem Flair macht es jede Illusion plötzlich zu einer Möglichkeit. Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe 2023 Herbstausrüstung.",
"headSpecialWinter2024RogueText": "Schneeeulen Haube",
"headSpecialNye2023Notes": "Du hast einen Lächerlichen Partyhut erhalten! Trage ihn mit Stolz, wenn du das neue Jahr einläutest! Gewährt keinen Attributbonus.",
"headSpecialWinter2024RogueNotes": "Wen wirst du sehen, wenn du diese Hauuuube trägst? Nun, wen wirst du NICHT sehen? Du wirst jede Bewegung, jede Geste, jedes Detail um dich herum erfassen. Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe Winter 2023-2024 Ausrüstung.",
"headSpecialNye2023Text": "Lächerlicher Partyhut",
"headSpecialSpring2023HealerNotes": "Dieses brillante und farbenfrohe Bild hat die gleiche Farbgebung wie die Sphäre der Wiedergeburt! Wie symbolträchtig! Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe 2023 Frühlingsausrüstung.",
"headSpecialFall2023HealerText": "Sumpfkreaturen-Maske",
"headSpecialFall2023HealerNotes": "Mit Augen, so dunkel wie das Moor, aus dem es entstieg, fixiert es seine Gegner. Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe 2023 Herbstausrüstung.",
"headSpecialWinter2024WarriorNotes": "Noch nie war es so köstlich, seine Birne zu schützen! Erhöht Stärke um <%= str %>. Limitierte Ausgabe Winter 2023-2024 Ausrüstung.",
"headSpecialWinter2024HealerNotes": "Oh oh, ein missglückter Zauberspruch hat dich im Eis gefangen! Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe Winter 2023-2024 Ausrüstung.",
"headSpecialWinter2024HealerText": "Gefrorener Helm",
"headSpecialWinter2024MageNotes": "Die mit Fleece gefütterte Kapuze schützt dich vor Kälte, aber auch vor negativen Gedanken und Vibes. Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe Winter 2023-2024 Ausrüstung.",
"headSpecialSpring2024MageText": "Hibiskus-Hut",
"headSpecialWinter2024WarriorText": "Pfefferminz-Schokobruch-Helm",
"headSpecialSpring2024WarriorText": "Fluorit Kopfputz",
"headSpecialWinter2024MageText": "Narwal Zauberer Haube",
"headSpecialSpring2024MageNotes": "Was könnte einschüchternder auf Feinde wirken, als diesen mit Pollen bedeckten Hut zu zeigen? Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe Frühling 2024 Ausrüstung.",
"headSpecialSpring2024RogueText": "Nass-Schnee-Kapuze",
"headSpecialSpring2024WarriorNotes": "Was könnte atemberaubender sein, als diese Kristallkrone im Kampf zu tragen? Erhöht Stärke um <%= str %>. Limitierte Ausgabe Frühling 2024 Ausrüstung.",
"headSpecialSpring2024HealerNotes": "Welche fröhlichen Lieder wirst du singen, wenn du diesen Helm trägst? Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe Frühling 2024 Ausrüstung.",
"headSpecialSpring2024RogueNotes": "Welche Wünsche und Hoffnungen werden auftauchen, wenn Eis und Schnee einem fruchtbaren Boden weichen? Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe Frühling 2024 Ausrüstung.",
"armorArmoireSnowyFluffTrimmedCoatText": "Schneeweißer Flauschmantel",
"armorArmoireSnowyFluffTrimmedCoatNotes": "Wenn die ersten Flocken um dich herum fallen, hält dich dieser Mantel nicht nur warm, sondern sorgt auch dafür, dass du dich perfekt in die verschneite Umgebung einfügst. Gleite mit Stil über das Eis! Erhöht Stärke und Intelligenz um jeweils <%= attrs %>. Verzauberter Schrank: Schneebedeckter Schlappergut-Set (Gegenstand 2 von 2).",
"headSpecialSummer2024HealerNotes": "Diese spiralförmige Muschel erinnert dich daran, nicht durchzudrehen. Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe Sommer 2024 Ausrüstung.",
"headMystery202301Text": "Tapfere Vulpinaohren",
"headSpecialSummer2024MageNotes": "Dieser Hut schwingt sanft in den Meeresströmungen und hilft dir, deine Weisheit zu kanalisieren. Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe Sommer 2024 Ausrüstung.",
"headSpecialWinter2025RogueNotes": "Dieser Hut hat definitiv etwas Magisches an sich, denn er verwandelt dich in einen Schneemenschen. Lass den Hasen nur nicht zu nahe an deine Karottennase herankommen. Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe Winterausrüstung 2024-2025.",
"headMystery202403Notes": "Du kannst dich glücklich schätzen, diese feine Mütze aus smaragdgrünem Samt mit ihrem feinen meergrünen Edelstein tragen zu können. Gewährt keinen Attributbonus. März 2024 Abonnentengegenstand.",
"headMystery202312Text": "Winterlich Blaues Haar",
"headSpecialSummer2024RogueText": "Nacktschnecken-Helm",
"headMystery202403Text": "Aquamarin-Glückskappe",
"headSpecialSummer2024WarriorText": "Walhai-Helm",
"headSpecialFall2024RogueNotes": "Ob du nun geschmeidig oder gerissen bist, wenn du das trägst, wirst du nicht übersehen! Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe Herbstausrüstung 2024.",
"headMystery202312Notes": "Diese ausgefallene Frisur erinnert an die frostigen Farben der Saison. Gewährt keinen Attributbonus. Dezember 2023 Abonnentengegenstand.",
"headSpecialSummer2024RogueNotes": "Dieser Helm mit seinen hornartigen Tentakeln hilft dir, dich zu verstecken, damit du zu deinen eigenen Bedingungen zuschlagen kannst. Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe Sommer 2024 Ausrüstung.",
"headSpecialSummer2024WarriorNotes": "Mit diesem hilfreichen Helm lassen sich knifflige Aufgaben in zwei Teile zerlegen. Erhöht Stärke um <%= str %>. Limitierte Ausgabe Sommer 2024 Ausrüstung.",
"headSpecialFall2024HealerNotes": "Ob du deinen Planeten verteidigst oder einen neuen erkundest, wenn du das trägst, wirst du nicht übersehen! Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe Herbstausrüstung 2024.",
"headSpecialWinter2025WarriorText": "Elchkrieger-Helm",
"headSpecialWinter2025WarriorNotes": "Also, hör zu: Jetzt siehst du aus wie ein Elch. Trag dieses Geweih mit Stolz. Erhöht Stärke um <%= str %>. Limitierte Ausgabe Winterausrüstung 2024-2025.",
"headSpecialFall2024RogueText": "Schwarze Katzenmaske",
"headSpecialFall2024HealerText": "Space Invader-Maske",
"headSpecialWinter2025HealerNotes": "Es ist nicht nötig, sie zu entwirren, da sie bereits die Form eines Hutes haben. Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe Winterausrüstung 2024-2025.",
"headSpecialWinter2025MageText": "Aurorahut",
"headSpecialWinter2025MageNotes": "Dieser Hut ist mehr als nur ein schicker Fascinator, er lässt dich wie das Polarlicht selbst aussehen. Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe Winterausrüstung 2024-2025.",
"headSpecialSummer2024MageText": "Seeanemonen-Hut",
"headSpecialSummer2024HealerText": "Seeschneckenhaus",
"headSpecialFall2024WarriorText": "Feurige Koboldmaske",
"headSpecialFall2024WarriorNotes": "Egal, ob du schelmisch oder bedrohlich bist, wenn du das trägst, wirst du nicht übersehen! Erhöht Stärke um <%= str %>. Limitierte Ausgabe Herbstausrüstung 2024.",
"headSpecialWinter2025RogueText": "Schneemaske",
"headSpecialWinter2025HealerText": "Lichterketten-Wirrwarr",
"headMystery202402Notes": "Diese hübsche rosa Mähne ist das perfekte Accessoire für den Februar und darüber hinaus. Gewährt keinen Attributbonus. Februar 2024 Abonnentengegenstand.",
"headMystery202402Text": "Paradiesisches Rosa Haar",
"headMystery202301Notes": "Dein Gehör wird so scharf sein, dass du das Hereinbrechen des Morgens und das Glitzern des Taus hören wirst. Gewährt keinen Attributbonus. Jänner 2023 Abonnentengegenstand.",
"headMystery202304Text": "Tiptop Teekannen-Deckel",
"headMystery202304Notes": "Dieser Helm gewährt dir Immuni-Tee-t. April 2023 Abonnentengegenstand.",
"headMystery202310Text": "Narrenkappe",
"headMystery202311Text": "Zauberweberhut",
"headMystery202311Notes": "Verwebe sogar Raum und Zeit mit deinem Willen. Gewährt keinen Attributbonus. November 2023 Abonnentengegenstand.",
"headMystery202310Notes": "Sie verbirgt dein Gesicht und verleiht deinen Augen dennoch einen beunruhigenden und gespenstischen Glanz. Gewährt keinen Attributbonus. Oktober 2023 Abonnentengegenstand.",
"headMystery202303Text": "Künstlermähnen-Haar",
"headMystery202303Notes": "Wie könnte man besser zeigen, dass man der Star dieser Geschichte ist, als mit blauem und unwahrscheinlich stacheligem Haar? Gewährt keinen Attributbonus. März 2023 Abonnentengegenstand.",
"headMystery202308Text": "Lila Protagonistenhaar",
"headMystery202308Notes": "Steht die widerspenstige Kutte, die aus der Mitte deines Kopfes ragt, für deine Hartnäckigkeit oder deinen Hang zum Unfug? Gewährt keinen Attributbonus. August 2023 Abonnentengegenstand.",
"headMystery202407Notes": "Mit diesen magischen Kiemen kannst du unter Wasser atmen! Gewährt keinen Attributbonus. Juli 2024 Abonnentengegenstand.",
"headMystery202411Notes": "Dieser Helm ist für deine Aufgaben ziemlich einschüchternd, wenn du dich kopfüber in die Arbeit stürzt! Gewährt keinen Attributbonus. November 2024 Abonnentengegenstand.",
"headMystery202501Notes": "Dieser glitzernde Hut erzeugt ständig ein leichtes und festliches Gewusel um dich herum. Gewährt keinen Attributbonus. Jänner 2025 Abonnentengegenstand.",
"headArmoireBeaniePropellerHatText": "Propeller-Beaniemütze",
"headMystery202409Text": "Sonnwend-Magierhut",
"headMystery202409Notes": "Die verzauberten Sonnenblumen auf diesem Hut sind mehr als nur eine fröhliche Dekoration, sie erfüllen den Träger mit mächtiger magischer Energie. Gewährt keinen Attributbonus. September 2024 Abonnentengegenstand.",
"headMystery202407Text": "Sympathische Axolotl-Haube",
"headMystery202411Text": "Borstenhelm",
"headMystery202412Text": "Zuckerstangen-Kaninchenhaube",
"headMystery202412Notes": "Warm und gemütlich, wie eine Tasse heißer Kakao mit Minze in einer Winternacht! Gewährt keinen Attributbonus. Dezember 2024 Abonnentengegenstand.",
"headMystery202501Text": "Frostbinder-Hut",
"headMystery202406Notes": "Die geisterhaften Federn, die diesen Hut zieren, leuchten schwach, wie die Wellen eines gespenstischen Meeres. Gewährt keinen Attributbonus. Juni 2024 Abonnentengegenstand.",
"headArmoireTeaHatText": "Teepartyhut",
"headArmoirePaintersBeretText": "Malermütze",
"headArmoireAdmiralsBicorneText": "Admirals-Zweispitz",
"headArmoireAdmiralsBicorneNotes": "Hut ab! Wenn du diesen Zweispitz trägst, wirst du weiser, klüger, mutiger... und größer sein. Erhöht Intelligenz und Wahrnehmung um jeweils <%= attrs %>. Verzauberter Schrank: Admiralsset (Gegenstand 1 von 2).",
"headArmoireBeaniePropellerHatNotes": "Jetzt ist nicht die Zeit, um am Boden zu bleiben! Drehe diesen kleinen Propeller und erhebe dich so hoch, wie dein Ehrgeiz dich tragen wird. Erhöht alle Eigenschaften um <%= attrs %>. Verzauberter Schrank: Unabhängiger Gegenstand.",
"headArmoirePaintersBeretNotes": "Mit dieser flotten Baskenmütze siehst du die Welt mit einem künstlerischen Auge. Erhöht Wahrnehmung um <%= per %>. Verzauberter Schrank: Malerset (Gegenstand 2 von 4).",
"headArmoireTeaHatNotes": "Dieser elegante Hut ist so schick wie funktional. Erhöht Wahrnehmung um <%= per %>. Verzauberter Schrank: Teepartyset (Gegenstand 2 von 3).",
"headArmoirePurpleSpookySorceryHatText": "Gespenstischer Lila Magierhut",
"headArmoirePurpleSpookySorceryHatNotes": "Purpurrot wie die Dämmerung und voller Geheimnisse, ist dieser Hut für all deine zauberhaften Bedürfnisse geeignet. Erhöht Wahrnehmung um <%= per %> und Ausdauer um <%= con %>. Verzauberter Schrank: Gespenstisches Magie-Set (Gegenstand 2 von 3).",
"headArmoireBlackSpookySorceryHatText": "Gespenstischer Schwarzer Magierhut",
"headArmoireBlackSpookySorceryHatNotes": "Schwarz wie die Nacht und voller Geheimnisse, ist dieser Hut für all deine zauberhaften Bedürfnisse geeignet. Erhöht Intelligenz um <%= per %> und Ausdauer um <%= con %>. Verzauberter Schrank: Gespenstisches Magie-Set (Gegenstand 3 von 3).",
"headArmoireDragonKnightsHelmText": "Drachenritterhelm",
"headArmoireCorsairsBandanaText": "Piratenbandana",
"headArmoireFunnyFoolCapText": "Lustige Narrenkappe",
"headArmoireWhiteFloppyHatNotes": "Viele Zaubersprüche wurden in diesen einfachen Hut eingenäht und verleihen ihm eine wundersame weiße Farbe. Erhöht Stärke, Intelligenz und Ausdauer um jeweils <%= attrs %>. Verzauberter Schrank: Weißes Loungewear -Set (Gegenstand 1 von 3).",
"headArmoireCorsairsBandanaNotes": "Egal, ob du deinen Kopf bedecken willst, falls eine Möwe über dich hinwegfliegt, oder ob du sicherstellen willst, dass deine Feinde dich nicht schwitzen sehen, dieses Tuch ist unverzichtbar. Füge einfach eine Zierperle für jedes Abenteuer hinzu, das du bestehst. Erhöht Intelligenz um <%= int %>. Verzauberter Schrank: Korsaren-Set (Gegenstand 2 von 3)",
"headArmoireFunnyFoolCapNotes": "Die Glöckchen an diesem Hut könnten deine Gegner zum Kichern bringen, aber dir helfen sie nur, dich zu konzentrieren. Erhöht Ausdauer um <%= con %>. Verzauberter Schrank: Lustiges Narren-Set (Gegenstand 1 von 3)",
"headArmoireDragonKnightsHelmNotes": "Mit den feurigen Elementen auf diesem Helm könnten Drachen dich für einen der ihren halten. Erhöht Intelligenz um <%= int %>. Verzauberter Schrank: Drachenritter-Set (Gegenstand 1 von 3)",
"headArmoireStormKnightHelmText": "Sturmritterhelm",
"headArmoireGreenTrapperHatText": "Grüne Trappermütze",
"headArmoireGreenTrapperHatNotes": "Alle sagen, dass deine Mütze so warm aussieht! Und das ist sie tatsächlich. Achte nur darauf, dass du die Klappen von deinen Ohren ziehst, wenn die Leute mit dir reden, sonst hört sich das Ganze eher nach „dne ütze sht ss wrrm ss!“ an. Erhöht Ausdauer und Wahrnehmung um jeweils <%= attrs %> . Verzauberter Schrank: Trappermützen-Set (Gegenstand 1 von 2).",
"headArmoireStormKnightHelmNotes": "Nutze die Blitze dieses Geweihs, wenn du die Burg stürmst. Erhöht Ausdauer um <%= con %>. Verzauberter Schrank: Sturmritter-Set (Gegenstand 1 von 3)",
"shieldSpecialWinter2024HealerText": "Salzstreuer",
"shieldMystery202408Text": "Geheimnisvolles Glitzern",
"shieldArmoireTrustyPencilText": "Treuer Bleistift",
"shieldSpecialWinter2024WarriorText": "Keksschild",
"shieldSpecialFall2024WarriorText": "Flammenschild",
"shieldArmoireSaucepanText": "Kochtopf",
"shieldArmoireBuoyantBeachBallText": "Strandball",
"shieldSpecialSummer2023WarriorText": "Goldfischseele",
"shieldSpecialFall2024HealerText": "Weltraumschild",
"shieldMystery202409Text": "Sonnwendmagierstab",
"shieldArmoireSafetyFlashlightText": "Sicherheitstaschenlampe",
"headArmoireFestiveHelperHatText": "Festlicher Helferhut",
"headArmoireSnowyTrapperHatText": "Verschneiter Trapperhut",
"headArmoireSnowyTrapperHatNotes": "Blaue, erfrorene Ohren gehören der Vergangenheit an. Freue Dich auf kuschelige Wärme mit Stil! Erhöht Ausdauer und Wahrnehmung um jeweils <%= attrs %> . Verzauberter Schrank: Verschneiter Trapperhut-Set (Gegenstand 1 von 2).",
"shieldSpecialSummer2024WarriorText": "Walhaiflosse",
"shieldSpecialSummer2024HealerText": "Meeresschneckenschild",
"shieldSpecialFallRogue2024Text": "Bänderstab",
"shieldSpecialWinter2025WarriorText": "Elchkriegerschild",
"shieldMystery202501Text": "Frostbinderstab",
"shieldSpecialWinter2023WarriorText": "Austernschild",
"shieldSpecialWinter2023WarriorNotes": "„Die Zeit ist reif“, das Walroß sprach, „Von mancherlei zu reden Von Austernschal'n und Schneegeläut Von Liedern die da schweben. Und wohin die Perle des Schilds verschwunden ist oder wie wir im neuen Jahr leben. Erhöht Ausdauer um <%= con %>.Limitierte Ausgabe 2022-2023 Winterausrüstung.",
"shieldSpecialSpring2023WarriorText": "Blumenstrauß",
"shieldSpecialSummer2023HealerText": "Seeigel",
"shieldArmoireTeaKettleText": "Teekessel",
"shieldSpecialFall2023RogueText": "Verhexte Flasche",
"shieldSpecialFall2023WarriorText": "Bequemes Kissen",
"shieldSpecialFall2023HealerText": "Moosiger Felsen",
"shieldArmoireBucketText": "Eimer",
"shieldArmoireBasketballText": "Basketball",
"backMystery202301Text": "Fünf Schweife der Tapferkeit",
"shieldArmoirePaintersPaletteText": "Malerpalette",
"shieldSpecialSpring2023HealerText": "Lilienmieder",
"shieldSpecialWinter2023HealerNotes": "Dein Lied von Frost und Schnee besänftigt die Geister aller, die es hören. Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe 2022-2023 Winterausrüstung.",
"shieldMystery202409Notes": "Der leuchtende Rubin auf diesem Stab bezieht seine Kraft aus der Spätsommersonne. Gewährt keinen Attributbonus. September 2024 Abonnentengegenstand.",
"backMystery202410Text": "Kandiszucker-Schweif",
"headAccessoryMystery202410Text": "Kandiszucker-Ohren",
"headAccessoryMystery202410Notes": "Sind das die Geräusche von „Süßes-oder-Saures“-Kindern an deiner Tür? Gewährt keinen Attributbonus. Oktober 2024 Abonnentengegenstand.",
"bodyMystery202411Text": "Stachelige Schulterplatten",
"headArmoireFestiveHelperHatNotes": "Urlaubstipp Nr. 27: Halten Sie einen Helferhut bereit. Dieser ist groß genug, um ein Notfallspielzeug darunter zu verstecken! Erhöht Intelligenz um <%= int %>. Verzauberter Schrank: Festliches Helferset (Gegenstand 1 von 2)",
"shieldMystery202501Notes": "Dekoriere jede Außenumgebung mit einer diamantenen Schicht aus schimmerndem Frost. Gewährt keinen Attributbonus. Jänner 2025 Abonnentengegenstand.",
"shieldSpecialWinter2025WarriorNotes": "Blocke alle unerwünschten Ablenkungen mit diesem Schild, das so stark wie ein Elch ist. Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe Winterausrüstung 2024-2025.",
"backMystery202410Notes": "Dieser Schweif wird bei der Erwähnung von gruseligen Leckereien aktiv. Gewährt keinen Attributbonus. Oktober 2024 Abonnentengegenstand.",
"shieldArmoireSafetyFlashlightNotes": "Warte, hast du das Geräusch gehört? Schnell! Leuchte mit deiner Taschenlampe in den Schatten dort drüben. Hmmm. Sieht aus, als wäre es nur der Wind gewesen. Oder war es...? Erhöht Ausdauer um <%= con %>. Verzauberter Schrank: Gruselnacht-Set (Gegenstand 1 von 2)",
"bodyMystery202411Notes": "Die furchterregenden Stacheln auf diesen Schulterplatten sind perfekt, um deine Aufgabenliste in Angriff zu nehmen. Gewährt keinen Attributbonus. November 2024 Abonnentengegenstand.",
"shieldSpecialSpring2023WarriorNotes": "Sammle die schönsten Blumen des Frühlings in diesem farbenfrohen Blumenstrauß. Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe 2023 Frühlingsausrüstung.",
"shieldSpecialWinter2023HealerText": "Coole Lieder",
"shieldSpecialSpring2023HealerNotes": "Ein Beitrag zu einem Genesungsbesuch oder Teil eines Rituals für einen Frühlingstanz! Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe 2023 Frühlingsausrüstung.",
"shieldSpecialWinter2024WarriorNotes": "Du bist ein tougher Keks, der niemals bröselt! Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe Winter 2023-2024 Ausrüstung.",
"shieldSpecialSummer2023HealerNotes": "Du verbirgst und beschützt es. Es hält neugierige Monster davon ab, zu nahe zu kommen. Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe 2023 Sommerausrüstung.",
"shieldSpecialFall2023RogueNotes": "Mit den stärksten Zaubern verstärkt, um mächtige Tränke zu halten. Erhöht Stärke um <%= str %>. Limitierte Ausgabe 2023 Herbstausrüstung.",
"shieldSpecialFall2023WarriorNotes": "Perfekt, um es dir bequem zu machen, während du einen Horrorfilm genießt... Aber wir verraten es niemand, wenn du es bei den grusligen Szenen in den Arm nehmen musst! Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe 2023 Herbstausrüstung.",
"shieldSpecialSummer2023WarriorNotes": "Beschwöre diesen Goldfischgeist für einen extra Schub Bestärkung und Begleitung während eines Kampfes. Ausdauer um <%= con %>. Limitierte Ausgabe 2023 Sommerausrüstung.",
"shieldSpecialWinter2024HealerNotes": "Wie praktisch, dass du beim Einfrieren eisschmelzende Materialien dabei hattest! Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe Winter 2023-2024 Ausrüstung.",
"shieldSpecialSummer2024WarriorNotes": "Zu denen, die behaupten, du könntest deine Ziele nicht erreichen, sag einfach: Sprich zu meiner Hand, äh, Flosse! Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe Sommer 2024 Ausrüstung.",
"shieldSpecialSummer2024HealerNotes": "Dieses glänzende Schild ist sogar stärker als ein Meeresschneckenstab. Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe Sommer 2024 Ausrüstung.",
"shieldSpecialFall2023HealerNotes": "Mit seinem festen Kern und dem weichen Bezug ist er ideal, um ihn auf Feinde zu schleudern oder um sich darauf zu setzen, wenn man eine Pause von seinen Abenteuern braucht. Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe 2023 Herbstausrüstung.",
"shieldSpecialFall2024HealerNotes": "Neue Aufgaben, die nach deiner Aufmerksamkeit greifen, prallen ab, bis du deine aktuelle Mission erledigt hast. Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe Herbstausrüstung 2024.",
"shieldSpecialFall2024WarriorNotes": "Komplikationen bei Aufgaben werden von deinem Schild absorbiert und machen dich entschlossener. Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe Herbstausrüstung 2024.",
"shieldSpecialFallRogue2024Notes": "Die Aufgaben selbst werden von den Wirbeln und Spiralen dieser hypnotischen Waffe überwältigt. Erhöht Stärke um <%= str %>. Limitierte Ausgabe Herbstausrüstung 2024.",
"headAccessoryMystery202212Notes": "Mit dieser verschnörkelten goldenen Tiara werden deine Herzlichkeit und Freundschaft neue Höhen erreichen. Gewährt keinen Attributbonus. Dezember 2022 Abonnentengegenstand.",
"headAccessoryMystery202212Text": "Eis-Tiara"
}
+7 -7
View File
@@ -291,13 +291,13 @@
"worldBossBullet4": "Besuche regelmäßig die Taverne um den Fortschritt des Weltbosses und seine Raserei-Angriffe zu prüfen",
"worldBoss": "Weltboss",
"groupPlanTitle": "Brauchst Du mehr Leute für Deine Crew?",
"groupPlanDesc": "Ein kleines Team leiten oder Hausarbeiten organisieren? Unsere Gruppenpläne gewähren Dir exklusiven Zugang zu einem privaten Task-Board und Chat-Bereich, der Dir und Deinen Gruppenmitgliedern gewidmet ist!",
"groupPlanDesc": "Hausarbeiten organisieren oder ein kleines Klassenprojekt leiten? Habiticas Gruppenpläne bieten gemeinsame Aufgaben und einen eigenen Chat-Bereich, damit du und dein Team motiviert bleiben.",
"billedMonthly": "*verrechnet als monatliches Abonnement",
"teamBasedTasksList": "Gruppenbasierte Aufgabenliste",
"teamBasedTasksListDesc": "Richte eine übersichtliche, gemeinsame Aufgabenliste für die Gruppe ein. Weise Deinen Gruppenmitgliedern Aufgaben zu oder lasse sie ihre eigenen Aufgaben beanspruchen, um deutlich zu machen, woran alle arbeiten!",
"groupManagementControls": "Gruppen-Management-Steuerungen",
"groupManagementControlsDesc": "Zeige den Aufgabenstatus an, um zu überprüfen, ob eine Aufgabe abgeschlossen wurde, füge Gruppen-Manager hinzu, um Verantwortlichkeiten zu teilen, und genieße einen privaten Gruppenchat für alle Gruppenmitglieder.",
"inGameBenefits": "Vorteile im Spiel",
"teamBasedTasksList": "Gemeinsame Aufgabenliste",
"teamBasedTasksListDesc": "Alle Gruppenmitglieder können an derselben Aufgabenliste arbeiten, um sicherzustellen, dass die Gruppe immer auf dem Laufenden bleibt. Erledige Aufgaben auf der gemeinsamen Aufgabenliste oder kopiere sie zu deinen persönlichen Aufgaben, um sie unterwegs zu erledigen.",
"groupManagementControls": "Flexible Verantwortlichkeit",
"groupManagementControlsDesc": "Teile Verantwortlichkeiten auf, indem du Aufgaben einer beliebigen Anzahl von Mitgliedern zuweist, oder stelle Aufgaben als Herausforderung ein, um zu sehen, wer sie zuerst erledigen kann. Die Gruppenmitglieder können sich über den Fortschritt der Aufgaben informieren, indem sie den Status aller Aufgaben einsehen.",
"inGameBenefits": "Alle Vorteile!",
"inGameBenefitsDesc": "Gruppenmitglieder erhalten ein exklusives Wolpertinger-Reittier sowie volle Abonnementvorteile, einschließlich spezieller monatlicher Ausrüstungssets und der Möglichkeit, Edelsteine mit Gold zu kaufen.",
"letsMakeAccount": "Lass uns Dir als erstes einen Account erstellen",
"nameYourGroup": "Wähle als nächstes einen Namen für Deine Gruppe",
@@ -378,7 +378,7 @@
"descriptionOptional": "Beschreibung",
"descriptionOptionalText": "Füge eine Beschreibung hinzu",
"nameStarText": "Füge einen Titel hinzu",
"nextPaymentMethod": "Weiter: Zahlungsmethode",
"nextPaymentMethod": "Weiter: Zahlung",
"dayStart": "<strong>Tageswechsel</strong>: <%= startTime %>",
"viewStatus": "Status",
"newGroupsWhatsNew": "Schau nach, was neu ist:",
+6 -2
View File
@@ -255,7 +255,7 @@
"dayTen": "Tag 10",
"birthdaySet": "Geburtstags-Set",
"fourForFreeText": "Um die Party am Laufen zu halten, verschenken wir Party Gewänder, 20 Edelsteine, und eine limitierte Geburtstags-Hintergrund Ausgabe und ein Gegenstände Set, das ein Cape, ein Schulterstück und eine Augenmaske enthält.",
"partyRobes": "Party Gewänder",
"partyRobes": "Party-Roben",
"twentyGems": "20 Edelsteine",
"dayOne": "Tag 1",
"summer2024WhaleSharkWarriorSet": "Walhai Set (Krieger)",
@@ -266,5 +266,9 @@
"fall2024UnderworldSorcerorMageSet": "Unterwelt Hexer Set (Magier)",
"fall2024SpaceInvaderHealerSet": "Space Invader Set (Heiler)",
"fall2024BlackCatRogueSet": "Schwarzes Katzen Set (Schurke)",
"gemSaleLimitationsText": "Dieses Angebot gilt nur während der zeitlich beschränkten Aktion. Diese Aktion startet am <%= eventStartMonth %> <%= eventStartOrdinal %> um <%= eventStartTime %> lokale Zeit (<%= eventStartUTC %> UTC) und endet am <%= eventEndMonth %> <%= eventEndOrdinal %> um <%= eventEndTime %> lokale Zeit (<%= eventEndUTC %> UTC). Das Aktionsangebot ist nur verfügbar, wenn du Edelsteine für dich selbst kaufst."
"gemSaleLimitationsText": "Dieses Angebot gilt nur während der zeitlich beschränkten Aktion. Diese Aktion startet am <%= eventStartMonth %> <%= eventStartOrdinal %> um <%= eventStartTime %> <%= timeZone %> und endet am <%= eventEndMonth %> <%= eventEndOrdinal %> um <%= eventEndTime %> <%= timeZone %>. Das Aktionsangebot ist nur verfügbar, wenn du Edelsteine für dich selbst kaufst.",
"winter2025StringLightsHealerSet": "Lichterketten Heiler Set",
"winter2025SnowRogueSet": "Schneeschurken Set",
"winter2025MooseWarriorSet": "Elchkrieger Set",
"winter2025AuroraMageSet": "Aurora Magier Set"
}
+6 -5
View File
@@ -19,11 +19,11 @@
"sleepDescription": "Brauchst Du eine Pause? Pausiere Schaden (unter Einstellungen), um ein paar der kniffligeren Habitica-Spielmechanismen zu pausieren:",
"sleepBullet1": "Deine verpassten Tagesaufgaben werden Dir nicht schaden (Bosse werden dennoch Deiner Party Schaden zufügen, wenn andere Partymitglieder ihre Täglichen Aufgaben verpassen)",
"sleepBullet2": "Deine Aufgaben-Strähnen und Gewohnheits-Zähler werden nicht zurückgesetzt",
"sleepBullet3": "Dein Schaden gegen Quest-Bosse oder Deine gefundenen Sammelgegenstände bleiben pausiert, bis Du Schaden wieder aktivierst.",
"sleepBullet3": "Dein Schaden gegen Quest-Bosse oder Deine gefundenen Sammelgegenstände bleiben pausiert, bis Du Schaden wieder aktivierst",
"pauseDailies": "Schaden pausieren",
"unpauseDailies": "Schaden wieder aktivieren",
"staffAndModerators": "Mitarbeiter und Moderatoren",
"communityGuidelinesIntro": "Habitica versucht, eine einladende Umgebung für Benutzer aller Alterstufen zu schaffen, vor allem an Plätzen wie Gruppen und Parties. Wenn Du unsicher bist oder noch Fragen hast, lies bitte unsere <a href='/static/community-guidelines' target='_blank'>Community-Richtlinien</a>.",
"communityGuidelinesIntro": "Habitica versucht, eine einladende Umgebung für Benutzer aller Alterstufen zu schaffen, vor allem an Plätzen wie Gruppen und Parties. Wenn Du unsicher bist oder noch Fragen hast, lies bitte unsere <a href='/static/community-guidelines' target='_blank'>Community-Richtlinien</a>.",
"acceptCommunityGuidelines": "Ich stimme zu, mich an die Community-Richtlinien zu halten",
"worldBossEvent": "Weltboss-Ereignis",
"worldBossDescription": "Weltboss-Beschreibung",
@@ -79,7 +79,7 @@
"newBaileyUpdate": "Neues Update von Bailey!",
"tellMeLater": "Erzähl es mir später",
"dismissAlert": "Als gelesen markieren",
"donateText3": "Als Open-Source-Projekt ist Habitica auf die Hilfe unserer Benutzer angewiesen. Das Geld, was Du für Edelsteine ausgibst, hilft uns dabei unsere Server am Laufen zu halten, ein paar Mitarbeiter zu bezahlen, neue Features zu entwickeln und unseren ehrenamtlichen Helferlein Anreize zu bieten.",
"donateText3": "Als Open-Source-Projekt ist Habitica auf die Hilfe unserer Benutzer angewiesen. Das Geld, was Du für Edelsteine ausgibst, hilft uns dabei unsere Server am Laufen zu halten, ein paar Mitarbeiter zu bezahlen, neue Features zu entwickeln und unseren ehrenamtlichen Helferlein Anreize zu bieten",
"card": "Kreditkarte",
"paymentMethods": "Kauf mit",
"paymentSuccessful": "Die Zahlung war erfolgreich!",
@@ -117,7 +117,7 @@
"paymentAutoRenew": "Dieses Abonnement wird automatisch erneuert bis es gekündigt wird. Wenn Du dieses Abonnement kündigen musst, kannst Du dies in Deinen Einstellungen tun.",
"paymentCanceledDisputes": "Wir haben eine Bestätigung der Kündigung an Deine E-Mailadresse gesendet. Falls Du die E-Mail nicht erhältst, kontaktiere uns bitte um zu verhindern, dass es zu Zahlungsstreitigkeiten kommt.",
"cannotUnpinItem": "Dieser Gegenstand kann nicht von der Pinnwand entfernt werden.",
"paymentSubBillingWithMethod": "Dein Abonnement wird in Höhe von <strong>$<%= amount %></strong> alle <strong><%= months %> Monat(e)</strong> per <strong><%= paymentMethod %></strong> abgerechnet.",
"paymentSubBillingWithMethod": "Dein Abonnement wird in Höhe von <br><strong>$<%= amount %>.00 USD</strong> alle <strong><%= months %> Monat(e)</strong> per <strong><%= paymentMethod %></strong> abgerechnet",
"invalidUnlockSet": "Dieses Set an Gegenständen ist abgelaufen und kann nicht freigeschaltet werden.",
"nGems": "<%= nGems %> Edelsteine",
"nMonthsSubscriptionGift": "<%= nMonths %> Monat(e) Abonnement (Geschenk)",
@@ -131,5 +131,6 @@
"groupsPaymentAutoRenew": "Dieses Abonnement läuft automatisch weiter, bis es gekündigt wird. Du kannst es im Gruppen-Abrechnungs-Tab kündigen.",
"sellItems": "Items verkaufen",
"customizationsShopText": "Willst du deinen Style ändern? Hier bist du richtig! Wir haben die frischesten Looks, passend zur Saison, auf Lager.",
"notAvailable": "Dieser Gegenstand ist nicht verfügbar."
"notAvailable": "Dieser Gegenstand ist nicht verfügbar.",
"paymentYouSentSubscriptionG1G1": "Du hast <strong><%- name %></strong><br> ein <%= months %>-Monat(e)-Abo für Habitica geschickt und dasselbe Abo wurde deinem Account im Zuge der \"Schenk' Eins, Bekomm' Eins\"-Aktion gutgeschrieben!"
}
+4 -4
View File
@@ -1,5 +1,5 @@
{
"stable": "Stall",
"stable": "Haus- und Reittiere",
"pets": "Haustiere",
"activePet": "Aktives Haustier",
"noActivePet": "Kein aktives Haustier",
@@ -57,11 +57,11 @@
"mountMasterText2": " und hat alle 90 Reittiere <%= count %> mal freigelassen",
"triadBingoName": "Triaden-Bingo",
"triadBingoText": "Hat alle 90 Haustiere gesammelt, alle 90 Reittiere gezähmt, und WIEDER alle 90 Haustiere gefunden (WIE HAST DU DAS GESCHAFFT?!)",
"triadBingoText2": " und hat seinen kompletten Stall <%= count %> mal freigelassen",
"triadBingoText2": " und hat alle Haus- und Reittiere <%= count %> mal freigelassen",
"triadBingoAchievement": "Du hast den Erfolg \"Triaden-Bingo\" erhalten, da Du alle Haustiere gefunden, alle Reittiere gezähmt und wieder alle Haustiere gefunden hast!",
"hatchedPet": "Du hast ein neues <%= potion %> <%= egg %> ausgebrütet!",
"hatchedPetGeneric": "Du hast ein neues Haustier ausgebrütet!",
"hatchedPetHowToUse": "Geh in den [Stall](<%= stableUrl %>) um Dein neuestes Haustier zu füttern und auszurüsten!",
"hatchedPetHowToUse": "Geh zu den [Haus- und Reittieren](<%= stableUrl %>) um Dein neuestes Haustier zu füttern und auszurüsten!",
"petNotOwned": "Du besitzt dieses Haustier nicht.",
"mountNotOwned": "Du besitzt dieses Reittier nicht.",
"feedPet": "<%= text %> an <%= name %> verfüttern?",
@@ -83,7 +83,7 @@
"petsReleased": "Haustiere freigelassen.",
"mountsAndPetsReleased": "Reit- und Haustiere freigelassen",
"mountsReleased": "Reittiere freigelassen",
"welcomeStable": "Willkommen im Stall!",
"welcomeStable": "Willkommen bei deinen Haus- und Reittieren!",
"welcomeStableText": "Willkommen im Stall! Ich bin Matt, der Bestienmeister. Jedes Mal, wenn Du eine Aufgabe erledigst, besteht die Chance, zufällig ein Ei oder ein Schlüpfelixier zu erhalten, mit deren Hilfe Haustiere ausgebrütet werden können. Wenn Du ein Haustier ausgebrütet hast, taucht es hier auf! Klicke auf ein Haustier damit es sich zu Deinem Avatar gesellt. Füttere sie mit dem Futter, das Du findest, und sie wachsen zu kräftigen Reittieren heran.",
"petLikeToEat": "Was frisst mein Haustier gern?",
"petLikeToEatText": "Haustiere wachsen, egal welches Futter Du ihnen gibst, aber sie wachsen schneller, wenn Du ihnen ihre Lieblingsspeise fütterst. Experimentiere herum, um das Muster zu finden, oder sieh hier nach: <br/> <a href=\"https://habitica.fandom.com/de/wiki/Futter#Bevorzugtes_Futter\" target=\"_blank\">https://habitica.fandom.com/de/wiki/Futter#Bevorzugtes_Futter</a>",
+45 -20
View File
@@ -404,7 +404,7 @@
"questDustBunniesBoss": "Ungezähmte Staubmäuse",
"questGroupMoon": "Mondschlacht",
"questMoon1Text": "Mondkampf, Teil 1: Finde die geheimnisvollen Scherben",
"questMoon1Notes": "Die Bevölkerung von Habitica wurde durch etwas seltsames von ihren Aufgaben abgelenkt: Gewundene Steinsplitter erscheinen überall im Land. Besorgt ruft Dich die Seherin, @Starsystemic, zu ihrem Turm. Sie sagt: \"Ich erkenne ein besorgniserregendes Omen in diesen Splittern, die sich über das Land vereiteln und die hartarbeitende Bevölkerung ablenken. Ich kann die Quelle zurückverfolgen, aber dazu muss ich diese Steinsplitter zuerst untersuchen. Kannst Du einige davon zu mir bringen?\"",
"questMoon1Notes": "Die Bevölkerung von Habitica wurde durch etwas seltsames von ihren Aufgaben abgelenkt: Gewundene Steinsplitter erscheinen überall im Land. Besorgt ruft Dich die Seherin, @Starsystemic, zu ihrem Turm. Sie sagt: \"Ich erkenne ein besorgniserregendes Omen in diesen Splittern, die sich über das Land verteilen und die hartarbeitende Bevölkerung ablenken. Ich kann die Quelle zurückverfolgen, aber dazu muss ich diese Steinsplitter zuerst untersuchen. Kannst Du einige davon zu mir bringen?\"",
"questMoon1Completion": "@Starsystemic verschwindet in ihren Turm, um die Splitter zu begutachten, die Du gesammelt hast. \"Das könnte komplizierter werden, als wir dachten,\" meint @Beffymaroo, ihre treue Gehilfin. \"Es wird etwas dauern, bis wir die Ursache herausgefunden haben. Schau täglich vorbei und, sobald wir mehr wissen, werden wir Dir die nächste Questschriftrolle zukommen lassen.\"",
"questMoon1CollectShards": "Mondscherben",
"questMoon1DropHeadgear": "Mondkriegerhelm (Kopfbedeckung)",
@@ -497,7 +497,7 @@
"questMayhemMistiflying3DropShield": "Verwegene Regenbogenbotschaft (Schildhand-Gegenstand)",
"questMayhemMistiflying3DropWeapon": "Verwegene Regenbogenbotschaft (Haupthand-Gegenstand)",
"featheredFriendsText": "\"Gefiederte Freunde\" Quest-Paket",
"featheredFriendsNotes": "Beinhaltet \"Hilfe! Harpyien!\", \"Die Nachteule\" und \"Die Zeitraubvögel\".",
"featheredFriendsNotes": "Beinhaltet Quests, um Eier für das Eulen-Haustier, Papageien-Haustier und Falken-Haustier und Die Zeitraubvögel zu erhalten.",
"questNudibranchText": "Befall mit NurSofort-Nacktkiemern",
"questNudibranchNotes": "An einem faulen Tag in Habitica kommst Du endlich dazu, Deine To-Dos anzugehen. An Deiner dunkelrötlichsten Aufgabe leuchtet eine Horde glänzend blauer Seeschnecken. Du bist entzückt! Ihre saphirblaue Farbe lässt Deine einschüchterndsten Aufgaben so leicht wie Deine besten Gewohnheiten aussehen. In fieberhaftem Wahn machst Du Dich an die Arbeit, packst in unaufhörlicher Raserei eine Aufgabe nach der anderen an...<br><br>Das nächste, an das Du Dich erinnerst, ist wie @LilithofAlfheim Dich mit kaltem Wasser übergießt. \"Die NurSofort-Nacktkiemer haben Dich total zerstochen! Du musst eine Pause machen!\" <br><br>Schockiert stellst Du fest, dass Deine Haut genauso rot leuchtet, wie einst Deine To-Do-Liste. \"Produktiv zu sein ist eine Sache\", sagt @beffymaroo, \"aber Du musst auch auf Dich selbst achten. Beeilung, lass sie uns loswerden!\"",
"questNudibranchCompletion": "Du siehst, wie die letzte NurSofort-Nacktkiemerschnecke von einem Stapel erledigter Aufgaben rutscht, als @amadshade sie wegwäscht. Eine lässt einen Kleidersack zurück, und als Du ihn öffnest, findest Du etwas Gold ein paar kleine Ellipsoiden, von denen Du annimmst, dass es Eier sind.",
@@ -505,7 +505,7 @@
"questNudibranchDropNudibranchEgg": "Nacktkiemerschnecke (Ei)",
"questNudibranchUnlockText": "Schaltet den Kauf von Nacktkiemerschneckeneiern auf dem Marktplatz frei",
"splashyPalsText": "\"Spritzige Kumpel\" Quest-Paket",
"splashyPalsNotes": "Beinhaltet 'Das Dilatory-Rennen', 'Führe die Schildkröte' und 'Jammern des Wals'.",
"splashyPalsNotes": "Beinhaltet Quests, um Eier für das Schildkröten-Haustier, Wal-Haustier und Seepferdchen-Haustier zu erhalten: Führe die Schildkröte, Jammern des Wals und Das Dilatory-Rennen.",
"questHippoText": "Was für ein heuchlerisches Hippo",
"questHippoNotes": "Du und @awesomekitty kollabiert vor Erschöpfung in dem Schatten einer Palme. Die Sonne glüht über der Schleichendstetigen Savanne und verbrennt den Grund unter ihr. Bis jetzt ist dies ein produktiver Tag gewesen, an dem Du Deine Tagesaufgaben besiegt hast. Und nun sieht diese Oase wie schönes Plätzchen aus, an dem man eine erfrischende Pause machen kann. Du beugst dich in der Nähe des Wassers herunter um etwas zu trinken, doch Du stolperst sogleich geschockt zurück, als sich ein riesiges Nilpferd vor dir erhebt. \"Ruhst Du dich jetzt schon aus? Sei nicht so faul und geh zurück zu deiner Arbeit.\" Du versuchst ihm zu widersprechen und zu sagen, dass Du sehr hart gearbeitet hast und eine Pause brauchst, aber das Hippo wollte nichts davon wissen. <br><br> @khdarkwolf flüstert dir zu, \"Fällt dir auf wie es den ganzen Tag faulenzt, aber die Frechheit besitzt dich faul zu nennen? Dies ist das heuchlerische Hippo!\" <br><br> Dein Freund @jumorales nickt. \"Kommt, wir zeigen ihm wie es ist, hart zu arbeiten!\"",
"questHippoCompletion": "Das Hippo verbeugt sich kapitulierend. “Ich habe Dich unterschätzt. Es sieht so aus, als ob Du gar nicht faul gewesen bist. Ich entschuldige mich. Um die Wahrheit zu sagen, ich habe vielleicht einiges auf Dich projiziert. Vielleicht sollte ich selbst auch einige meiner Aufgaben erledigen. Hier, nimm diese Eier als ein Zeichen meiner Dankbarkeit.” Nachdem Du sie genommen hast, lässt Du Dich beim Wasser nieder, um endlich zu entspannen.",
@@ -513,9 +513,9 @@
"questHippoDropHippoEgg": "Nilpferd (Ei)",
"questHippoUnlockText": "Schaltet den Kauf von Nilpferdeiern auf dem Marktplatz frei",
"farmFriendsText": "\"Farmfreunde\" Quest-Paket",
"farmFriendsNotes": "Beinhaltet 'Die Muhtantische Kuh', 'Reite die Nacht-Mähre', und 'Der Donner-Bock'.",
"farmFriendsNotes": "Beinhaltet Quests, um Eier für das Pferde-Haustier, Schaf-Haustier und Kuh-Haustier zu erhalten: Reite die Nacht-Mähre, Der Donner-Bock und Die Muhtantische Kuh.",
"witchyFamiliarsText": "\"Hexenhafte Haustiere\" Quest-Paket",
"witchyFamiliarsNotes": "Beinhaltet 'Der Rattenkönig', 'Die eisige Arachnoide', und 'Sumpf des Chaos-Froschs'.",
"witchyFamiliarsNotes": "Beinhaltet Quests, um Eier für das Frosch-Haustier, Spinnen-Haustier und Ratten-Haustier zu erhalten: Sumpf des Chaos-Froschs, Die eisige Arachnoide und Der Rattenkönig.",
"questGroupLostMasterclasser": "Geheimnis der Klassenmeister",
"questUnlockLostMasterclasser": "Um diese Quest freizuschalten, musst Du die finalen Quests der Questreihen 'Dilatory in Gefahr', 'Chaos in Mistiflying', 'Stoïstilles Unglück' und 'Schrecken in den Aufgabenwäldern' abgeschlossen haben.",
"questLostMasterclasser1Text": "Das Geheimnis der Klassenmeister, Teil 1: Lies zwischen den Zeilen",
@@ -559,7 +559,7 @@
"questYarnDropYarnEgg": "Wollknäuel (Ei)",
"questYarnUnlockText": "Schaltet den Kauf von Wollknäueleiern auf dem Marktplatz frei",
"winterQuestsText": "\"Winter\" Quest-Paket",
"winterQuestsNotes": "Beinhaltet 'Wildernder Weihnachtswichtel', 'Finde das Jungtier' und 'Der Federvieh-Frost'. Beachte, dass Wildernder Weihnachtswichtel und Finde das Jungtier stapelbare Questerfolge haben, aber nur einmalig ein seltenes Haus- und Reittier verleihen.",
"winterQuestsNotes": "Beinhaltet Quests, um Eier für das Eisbären-Haustier, das Eisbären-Reittier und das Pinguin-Haustier zu erhalten: Finde das Jungtier, Wildernder Weihnachtswichtel und Der Federvieh-Frost.",
"questPterodactylText": "Der Pterror-Dactylus",
"questPterodactylNotes": "Du machst einen Spaziergang entlang der friedlichen Stoïstillen Klippen, als ein böses Kreischen die Luft zerreißt. Du drehst Dich um, siehst eine schreckliche Kreatur auf Dich zufliegen und wirst von einem mächtigen Schrecken überwältigt. Als Du Dich zur Flucht wendest, packt Dich @Lilith of Alfheim. \"Keine Panik! Es ist nur ein Pterror-Dactylus.\"<br><br>@Procyon P nickt. \"Sie nisten in der Nähe, aber sie fühlen sich angezogen vom Geruch negativer Gewohnheiten und unerledigter Tagesaufgaben.\"<br><br>Keine Sorge\", sagt @Katy133. \"Wir müssen nur besonders produktiv sein, um ihn zu besiegen!\" Du bist erfüllt von einem erneuerten Sinn für Zielstrebigkeit und wendest Dich Deinem Feind zu.",
"questPterodactylCompletion": "Mit einem letzten Kreischen stürzt der Pterror-Dactylus über die Klippe. Du rennst nach vorn, um zu sehen, wie er über die entfernten Steppen hinwegfliegt. \"Puh, ich bin froh, dass das vorbei ist\", sagst Du. \"Ich auch\", antwortet @GeraldThePixel. \"Aber seht doch! Er hat ein paar Eier für uns zurückgelassen.\" @Edge gibt Dir drei Eier, und Du gelobst, sie in friedlicher Ruhe aufzuziehen, umgeben von positiven Gewohnheiten und blauen Tagesaufgaben.",
@@ -594,7 +594,7 @@
"questDysheartenerDropHippogriffMount": "Hoffnungsfroher Hippogreif (Reittier)",
"dysheartenerArtCredit": "Artwork von @AnnDeLune",
"hugabugText": "\"Knuddel den Käfer\" Quest-Paket",
"hugabugNotes": "Beinhaltet 'Der KRITISCHE BUG', 'Die Schnecke der Schlamm-Schinderei' und 'Flieg' weiter, Funkenfalter!'.",
"hugabugNotes": "Beinhaltet Quests, um Eier für das Käfer-Haustier, das Raupen-Haustier und das Schnecken-Haustier zu erhalten: Der KRITISCHE BUG, Flieg' weiter, Funkenfalter! und Die Schnecke der Schlamm-Schinderei.",
"questSquirrelText": "Das Raffinierte Eichhörnchen",
"questSquirrelNotes": "Du wachst auf und bemerkst, dass Du verschlafen hast! Warum hat Dein Wecker nicht geklingelt? .... Wie ist eine Eichel in die Klingel geraten?<br><br>Als Du versuchst, Frühstück zu machen, ist der Toaster mit Eicheln gefüllt. Als Du Dein Reittier holen willst, ist @Shtut da und versucht erfolglos, den Stall aufzusperren. Du schaust in das Schlüsselloch. “Ist das eine Eichel da drin?”<br><br>@randomdaisy ruft: “Oh nein! Ich wusste, dass meine Haustier-Eichhörnchen ausgebüxt sind, aber ich wusste nicht, dass sie solche Schwierigkeiten gemacht haben! Kannst Du mir helfen, sie zusammenzutreiben, bevor sie noch mehr Chaos anrichten?”<br><br>Den Spuren der schelmisch platzierten Eichennüsse folgend, fängst Du die eigensinnigen Nager, wobei @Cantras hilft sie sicher zu Hause unterzubringen. Aber gerade als Du denkst, dass Deine Aufgabe fast erledigt ist, prallt eine Nuss von Deinem Helm ab! Du schaust auf, um ein mächtiges Exemplar eines Eichhörnchens zu sehen, das zur Verteidigung eines wunderbaren Haufens von Eicheln zusammengekauert dasitzt.<br><br>“Oh je”, sagt @randomdaisy leise. “Sie war schon immer eine Art Ressourcenschützerin. Wir müssen sehr vorsichtig vorgehen!” Ihr kreist das Tier langsam ein, bereit für Ärger!",
"questSquirrelCompletion": "Mit einer sanften Herangehensweise, Tauschangeboten und ein paar beruhigenden Zaubersprüchen kannst Du das Eichhörnchen von seinem Schatz weglocken und zurück zu den Ställen bringen, die @Shtut gerade erst enteichelt hat. Ein paar der Eicheln siehst Du auf einem Arbeitstisch beiseite gelegt. “Das sind Eichhörncheneier! Vielleicht kannst Du welche aufziehen, die nicht so viel mit ihrem Essen spielen.”",
@@ -602,9 +602,9 @@
"questSquirrelDropSquirrelEgg": "Eichhörnchen (Ei)",
"questSquirrelUnlockText": "Schaltet den Kauf von Eichhörncheneiern auf dem Marktplatz frei",
"cuddleBuddiesText": "\"Kuschelkumpel\" Quest-Paket",
"cuddleBuddiesNotes": "Beinhaltet 'Das Killerkaninchen', 'Das Ruchlose Frettchen' und 'Die Meerschweinchen Gang'.",
"cuddleBuddiesNotes": "Beinhaltet Quests, um Eier für das Hasen-Haustier, das Frettchen-Haustier und das Meerschweinchen-Haustier zu erhalten: Das Killerkaninchen, Das Ruchlose Frettchen und Die Meerschweinchen Gang.",
"aquaticAmigosText": "\"Feuchte Freunde\" Quest-Paket",
"aquaticAmigosNotes": "Beinhaltet 'Der magische Axolotl', 'Der Kraken von Unfertik' und 'Der Ruf des Octothulu'.",
"aquaticAmigosNotes": "Beinhaltet Quests, um Eier für das Tintenfisch-Haustier, das Oktopus-Haustier und das Axolotl-Haustier zu erhalten: Der Kraken von Unfertik, Der Ruf des Octothulu und Der magische Axolotl.",
"questSeaSerpentText": "Gefahr in der Tiefe: Seeschlangen-Angriff!",
"questSeaSerpentNotes": "Du fühlst Deine Glückssträhne - es ist die perfekte Zeit für einen Ausflug zur Seepferdchen-Rennstrecke. Du steigst in das U-Boot bei Diligent Docks ein und machst Dich bereit für die Reise nach Dilatory, aber kaum bist Du untergetaucht, erschüttert ein Aufprall das U-Boot und lässt seine Insassen stolpern. “Was ist los?” schreit @AriesFaries.<br><br>Du schaust durch ein nahegelegenes Bullauge und bist schockiert von der Wand aus schimmernden Schuppen, die an ihm vorbeizieht. “Seeschlange!” ruft Captain @Witticaster über die Gegensprechanlage aus. “Haltet euch fest, sie kommt schon wieder!” Während Du Dich an die Armlehnen Deines Sitzes klammerst, ziehen Deine unerledigten Aufgaben vor Deinen Augen vorüber. “Vielleicht, wenn wir zusammen arbeiten und sie erledigen”, denkst Du, “können wir dieses Monster vertreiben!”",
"questSeaSerpentCompletion": "Von Deiner Hingabe angeschlagen, flieht die Seeschlange und verschwindet in den Tiefen. Als Du in Dilatory ankommst, entfährt Dir ein Seufzer der Erleichterung, bevor Du bemerkst, dass @*~Seraphina~ sich mit drei durchsichtigen Eiern in ihren Armen nähert. “Hier, die hier sollst Du haben”, sagt sie. “Du weißt, wie man mit einer Seeschlange umgeht!” Als Du die Eier annimmst, gelobst Du von neuem, standhaft bei der Erfüllung Deiner Aufgaben zu bleiben, um sicherzustellen, dass es nicht zu einer Wiederholung kommt.",
@@ -618,7 +618,7 @@
"questKangarooDropKangarooEgg": "Känguru (Ei)",
"questKangarooUnlockText": "Schaltet den Kauf von Känguru-Eiern auf dem Marktplatz frei",
"forestFriendsText": "\"Waldfreunde\" Quest-Paket",
"forestFriendsNotes": "Beinhaltet 'Die Seele des Frühlings', 'Das Igelmonster' und 'Das Baumgewirr'.",
"forestFriendsNotes": "Beinhaltet Quests, um Eier für das Baumling-Haustier, das Reh-Haustier und das Igel-Haustier zu erhalten: Das Baumgewirr, Die Seele des Frühlings und Das Igelmonster.",
"questAlligatorText": "Der Insta-Gator",
"questAlligatorNotes": "“Verflixt!” ruft @gully aus. “Ein Insta-Gator in seinem natürlichen Lebensraum! Vorsichtig, er lenkt seine Beute mit Dingen ab, die dringend erscheinen, JETZT SOFORT, und er ernährt sich von den daraus resultierenden liegengebliebenen Tagesaufgaben.” Du verstummst um nicht aufzufallen, aber ohne Erfolg. Der Insta-Gator entdeckt Dich und stürmt los! Aus den Sümpfen der Stagnation erheben sich ablenkende Stimmen, die nach Deiner Aufmerksamkeit greifen: “Lies diesen Beitrag! Sieh Dir dieses Foto an! Achte auf mich, JETZT SOFORT!” Du reißt Dich zusammen um einen Gegenangriff zu starten, vervollständigst Deine Tagesausgaben und stärkst Deine guten Gewohnheiten, um den gefürchteten Insta-Gator zu bekämpfen.",
"questAlligatorCompletion": "Du konzentrierst Dich auf das Wesentliche und nicht auf die Ablenkungen des Insta-Gators, und so flieht der Insta-Gator. Sieg! “Sind das Eier? Sie sehen für mich wie Alligatoreier aus”, fragt @mfonda. “Wenn wir uns richtig um sie kümmern, werden sie treue Haustiere oder Reittiere sein”, antwortet @UncommonCriminal und übergibt Dir drei, um sich um sie zu kümmern. Lasst es uns hoffen, sonst könnte der Insta-Gator zurückkehren…",
@@ -626,9 +626,9 @@
"questAlligatorDropAlligatorEgg": "Alligator (Ei)",
"questAlligatorUnlockText": "Schaltet den Kauf von Alligatoreneiern auf dem Marktplatz frei",
"oddballsText": "\"Sonderlinge\" Quest-Paket",
"oddballsNotes": "Beinhaltet 'Der Glibberkönig', 'Entkomme dem Höhlenungetüm' und 'Ein verheddertes Knäuel'.",
"oddballsNotes": "Beinhaltet Quests, um Eier für das Schleim-Haustier, das Garn-Haustier und das Felsen-Haustier zu erhalten: Der Glibberkönig, Ein verheddertes Knäuel und Entkomme dem Höhlenungetüm.",
"birdBuddiesText": "\"Vogel-Freunde\" Quest-Paket",
"birdBuddiesNotes": "Beinhaltet 'Der Federvieh-Frost', 'Der Hahnenkampf' und 'Der Für-und-Wider-Pfau'.",
"birdBuddiesNotes": "Beinhaltet Quests, um Eier für das Pfauen-Haustier, das Pinguin-Haustier und das Hahn-Haustier zu erhalten: Der Für-und-Wider-Pfau, Der Federvieh-Frost und Der Hahnenkampf.",
"questVelociraptorText": "Der Veloci-Rapper",
"questVelociraptorNotes": "Du teilst Honigkuchen mit @*~Seraphina~*, @Procyon P, and @Lilith of Alfheim an einem See in den Stoïstille Steppen. Plötzlich unterbricht eine traurige Stimme Dein Picknick.<br><br><em>Meine Gewohnheiten vergessen, die Tagesaufgaben verpasst,<br>Ich hab nachgelassen, das ist mir verhasst,<br>Alles lief rund, ich fühlte mich gut,<br>Doch jetzt herrscht Fälligkeitstermine-Flut.</em><br><br>@*~Seraphina~* guckt hinter einen Grasbüschel. “Das ist Veloci-Rapper. Es scheint... verzweifelt?” <br><br>Du ballst entschlossen Deine Faust. “Da gibt es nur eine Lösung. Zeit für eine Rap Battle!”",
"questVelociraptorCompletion": "Du springst durch das Gras und stellst Veloci-Rapper.<br><br><em>Hör mir zu, Rapper, gib nicht so schnell auf,<br>Schlechten Gewohnheiten raubst Du doch den Schnauf!<br>Hak' ab die To-Dos mit neuer Lust,<br>Jammer nicht lang über Deinen Patzer-Frust!</em><br><br>Voll neuem Selbstvertrauen hüpft es davon um ein ander mal zu freestylen und hinterlässt drei Eier, wo es gesessen hat.",
@@ -636,7 +636,7 @@
"questVelociraptorDropVelociraptorEgg": "Velociraptor (Ei)",
"questVelociraptorUnlockText": "Schaltet den Kauf von Velociraptoreiern auf dem Marktplatz frei",
"mythicalMarvelsText": "Mythische Wunder Quest-Paket",
"mythicalMarvelsNotes": "Beinhaltet \"Überzeuge die Einhornkönigin\", \"Der Feuergreif\" und \"Gefahr in der Tiefe: Seeschlangen-Angriff!\".",
"mythicalMarvelsNotes": "Beinhaltet Quests, um Eier für das Einhorn-Haustier, das Greifen-Haustier und das Seeschlangen-Haustier zu erhalten: Überzeuge die Einhornkönigin Der Feuergreif und Gefahr in der Tiefe: Seeschlangen-Angriff!",
"questBronzeDropBronzePotion": "Bronzenes Schlüpfelixier",
"questDolphinText": "Der Delfin des Zweifels",
"questDolphinBoss": "Delfin des Zweifels",
@@ -659,7 +659,7 @@
"questSilverUnlockText": "Schaltet den Kauf von Silbernen Schlüpfelixieren auf dem Marktplatz frei",
"questRobotCompletion": "Als @Rev und der Rechenschafts-Buddy die letzte Schraube einsetzen, erwacht die Zeitmaschine zum Leben. @FolleMente und @McCoyly springen an Bord. „Danke für die Hilfe! Wir sehen uns in der Zukunft! Übrigens, die hier sollen Dir bei Deiner nächsten Erfindung helfen!\" Damit verschwinden die Zeitreisenden, aber im Wrack des alten Produktivitätsstabilisators verbleiben drei Eier mit Uhrwerken. Vielleicht sind das die entscheidenden Komponenten für eine neue Produktionslinie von Rechenschafts-Buddys!",
"questRobotNotes": "Im Max Kapazitäten-Labor verleiht @Rev der neuesten Erfindung, einem robotischen Rechenschafts-Buddy , den letzten Schliff, als plötzlich ein seltsames Metallfahrzeug in einer Rauchwolke erscheint, nur wenige Zentimeter vom Fluktuationsdetektor des Roboters entfernt! Die Insassen, zwei seltsame, in Silber gekleidete Gestalten, verlassen ihr Gefährt und nehmen ihre Weltraumhelme ab, wobei sie sich als @FolleMente und @McCoyly offenbaren. <br><br>„Ich postuliere, dass unsere Produktivitätsimplementierung eine Anomalie aufwies“, meint @FolleMente verlegen. <br><br>@ McCoyly verschränkt ihre Arme. „Das bedeutet, dass sie es versäumt haben, ihre Tagesaufgaben zu erledigen, was, wie ich postuliere, zur Zersetzung unseres Produktivitätsstabilisators geführt hat. Dabei handelt es sich um eine wesentliche Komponente für Zeitreisen, die zwingend Konsistenz benötigt, um richtig funktionieren zu können. Unsere Leistungen befeuern unsere Bewegung durch Zeit und Raum! Ich habe keine Zeit, um es genauer zu erklären, @Rev. Du wirst es in 37 Jahren entdecken oder vielleicht auch Deine Verbündeten, die Mysteriösen Zeitreisenden. Kannst Du uns vorerst dabei helfen, unsere Zeitmachine zu reparieren?\"",
"rockingReptilesNotes": "Beinhaltet den \"Insta-Gator\", \"Die Schlange der Ablenkung\" und den \"Veloci-Rpper\".",
"rockingReptilesNotes": "Beinhaltet Quests, um Eier für das Alligator-Haustier, das Velociraptor-Haustier und das Schlangen-Haustier zu erhalten: Der Insta-Gator, Der Veloci-Rapper und Die Schlange der Ablenkung.",
"rockingReptilesText": "\"Rockendes Reptilien\"-Quest-Bundle",
"questRobotUnlockText": "Schaltet den Kauf von Robotereiern auf dem Markplatz frei",
"questRobotDropRobotEgg": "Roboter (Ei)",
@@ -667,7 +667,7 @@
"questRobotCollectGears": "Zahnräder",
"questRobotCollectBolts": "Schrauben",
"questRobotText": "Mysteriöse Mechanische Merkwürdigkeiten!",
"delightfulDinosNotes": "Enthält den \"Pterror-dactyl\", \"Trampelnden Triceratops\" und \"Ausgegrabenen Dinosaurier\".",
"delightfulDinosNotes": "Beinhaltet Quests, um Eier für das Triceratops-Haustier, das T-Rex-Haustier und das Pterodactyl-Haustier zu erhalten: Der Trampelnde Triceratops, Der Ausgegrabene Dinosaurier und Der Pterror-Dactyl.",
"delightfulDinosText": "\"Dufte Dinos\" Quest-Paket",
"questAmberCompletion": "\"Trerezin?\" sagt @-Tyr- mit ruhiger Stimme. \"Würdest Du @Vikte loslassen? Ich glaube nicht, dass es ihm so hoch oben wohl ist.\"<br><br>Trerezins Haut wird hochrot und sie setzt @Vikte sanft auf dem Boden ab. \"Bitte entschuldigt! Es ist schon so lange her, dass ich Gäste hatte. Dabei habe ich meine guten Manieren vergessen!\" Sie gleitet vorwärts um euch standesgemäss zu begrüssen, bevor sie in ihrem Baumhaus verschwindet. Gleich darauf kehrt Sie zurück mit einem Arm voll Bernsteinfarbener Schlüpfelixiere als Dankeschön!<br><br>\"Magische Tränke!\" haucht @Vikte.<br><br>\"Ach, diese alten Dinger?\" Trerezins Zunge zittert während sie nachdenkt. \"Wie wär's damit: Ich gebe euch den ganzen Stapel, wenn ihr versprecht, mich ab und zu besuchen zu kommen...\"<br><br>So lasst ihr die Aufgabenwälder hinter euch, um allen über die neuen Schlüpfelixieren zu berichten und natürlich über eure neue Freundin!",
"questAmberNotes": "Du sitzt mit @beffymaroo und @-Tyr- in der Taverne als @Vikte zur Tür hereinplatzt und aufgeregt von Gerüchten über eine neue Art von Magischem Schlüpfelixier erzählt, die in den Aufgabenwälder versteckt seien. Da Deine Tagesaufgaben bereits erledigt sind, beschliesst ihr drei ohne zu zögern, @Vikte bei der Suche zu helfen. Was kann ein kleines Abenteuer schon schaden?<br><br>Nach stundenlangem Marsch durch die Aufgabenwälder fängst Du an, den spontanen Aufbruch zur Jagd zu bereuen. Ihr seid gerade am umkehren als ihr einen überraschten Ausruf hört. Ihr dreht euch um und erblickt eine riesige Echse mit glänzenden, bernsteinfarbenen Schuppen, die sich um einen Baum windet, @Vikte in ihren Krallen haltend. @beffymaroo greift nach ihrem Schwert.<br><br>\"Wartet!\" ruft @-Tyr-. \"Das ist Trerezin! Sie ist nicht gefährlich, nur gefährlich anhänglich!\"",
@@ -693,7 +693,7 @@
"questWaffleText": "An die Waffe(l) gegen den Scherzkeks: Desaster-Frühstück!",
"questWaffleRageEffect": "`Fürchterliche Waffel setzt AHORNSUMPF ein!` Schmieriger saftiger Sirup lässt Deine Schläge und Sprüche stocken! Anstehender Schaden wird reduziert.",
"questWaffleCompletion": "Angeschlagen und reich bebuttert, aber trotzdem triumphierend, genießt Ihr den süßen Sieg über die fürchterliche Waffel, die in eine klebrig-schleimige Pfütze zusammensinkt.<br><br>\"Wow, dieses Monster habt Ihr gründlich eingeschmiert\", sagt Lady Glaciate beeindruckt.<br><br>\"Ein Zuckerschlecken!\" strahlt der April-Scherzkeks.<br><br>\"Trotzdem irgendwie schade,\" findet @beffymaroo. \"Die sah irgendwie lecker aus.\"<br><br>Der Scherzkeks zaubert einen Satz Schlüpfelixier-Flaschen aus seinem Cape, füllt sie mit der sirupartigen Masse der Waffel-Überreste und mischt eine Prise glitzernden Staub hinein. Farben wirbeln durch die Flüssigkeit neue Schlüpfelixiere! Er wirft sie Euch in die Arme. \"Das ganze Abenteuer hat mir Appetit gemacht. Wer kommt mit zum Frühstück?\"",
"jungleBuddiesNotes": "Beinhaltet 'Monströser Mandrill und die Albernen Affen', 'Das verschlafene Faultier' und 'Das Baumgewirr'.",
"jungleBuddiesNotes": "Beinhaltet Quests, um Eier für das Affen-Haustier, das Baumling-Haustier und das Faultier-Haustier zu erhalten: Monströser Mandrill und die Albernen Affen, Das Baumgewirr und Das verschlafene Faultier.",
"jungleBuddiesText": "\"Jungle Freunde\" Quest-Paket",
"questFluoriteUnlockText": "Schaltet den Kauf von Fluorit-Schlüpfelixieren auf dem Marktplatz frei",
"questFluoriteDropFluoritePotion": "Fluorit-Schlüpfelixier",
@@ -715,7 +715,7 @@
"questTurquoiseCollectSagittariusRunes": "Schütze-Runen",
"questTurquoiseCompletion": "Heiß und verschwitzt hält Dein Team endlich inne und macht eine verdiente Pause neben dem umgegrabenen Dreck und einem Haufen Runen und Edelsteine, die ihr gefunden habt.<br><br>“Unglaublich”, murmelt @QuartzFox. “Das wird Geschichte schreiben.”<br><br>“Lasst mich diese Materialien zur Habitica-Universität nehmen um sie zu analysieren”, sagt @gawrone. “Da müsste es viel zu studieren geben und auch einige türkise Elixiere für uns alle abwerfen! Wer weiß was wir hier sonst noch alles begraben finden könnten?”<br><br>@starsystemic stimmt ein: “Einfach bewundernswert, was man mit harter Arbeit erreichen kann!”",
"questTurquoiseNotes": "@gawrone rennt in Dein Zimmer mit ihrem Habiticaner-Diplom in der einen Hand und einem außerordentlich großen und staubigen, ledergebundenen Folianten in der anderen.<br><br>“Du wirst nie erraten, was ich entdeckt habe!”, sagen sie. “Die Blühenden Felder sind so fruchtbar weil sie früher mal von einem riesigen Ozean bedeckt waren. Man munkelt dass ein uraltes Volk den Boden diesen Ozeans in magischen Städten bewohnt hat. Ich habe mithilfe längst vergessen geglaubter Karten herausgefunden, wo das höchstwahrscheinlich war! Hol Deine Schaufel!”<br><br>Schon am nächsten Abend trefft ihr euch mit @QuartzFox und @starsystemic, um eine Party zu gründen und die Grabungen zu starten. Tief im Boden findet Ihr eine Rune neben einem Türkis!<br><br>“Grabt weiter!”, drängt @gawrone. “Wenn wir genug finden, können wir eines ihrer uralten Elixiere nachbrauen und somit Geschichte schreiben!”",
"sandySidekicksNotes": "Beinhaltet 'Das gutmütige Gürteltier', 'Die Schlange der Ablenkung' und 'Die eisige Arachnoide'.",
"sandySidekicksNotes": "Beinhaltet Quests, um Eier für das Spinnen-Haustier, das Gürteltier-Haustier und das Schlangen-Haustier zu erhalten: Die eisige Arachnoide, Das gutmütige Gürteltier und Die Schlange der Ablenkung.",
"sandySidekicksText": "\"Sandige Seelenverwandte\" Quest-Paket",
"questBlackPearlText": "Sternstunde - Ein Fall von Einfall",
"questBlackPearlNotes": "In letzter Zeit hast Du einfach keinen Schwung. Du vermisst deine Kreativität. Als @jjgame83 also vorschlägt zusammen zum Lively Lake zu gehen, ergreifst du die Chance für einen Tapetenwechsel. Während @QuarzFox das Picknick am Seeufer vorbereitet, siehst du etwas im flachen Wasser glitzern. Eine seltsame, schwarze Perle. <br><br>\"Ich wünschte, mir würde was neues einfallen\", seufzt Du.<br><br>Eine kalte Brise, scheinbar aus dem Nirgendwo, scheint deine Worte am Ufer entlang zu tragen und das Wasser kräuselt sich leicht. Der See wird schwarz wie Tinte, Sterne leuchten am Firmament auf und innerhalb eines Herzschlages wird der Tag zu tiefster Nacht.<br><br>\"Das sind keine guten Vorboten\", sagt @PixelStormArt.<br><br>Die Luft.. schmeckt nach Salz? Plötzlich bricht eine gigantische Masse an Fangarmen in einem Sprühregen aus Meeresschaum aus dem See hervor. Du kannst gerade eine Art Schnabel in der Mitte ausmachen, als dieser sich öffnet und dröhnend erschallt: \"HÜTET EUCH VOR ASTEROIDEE, DER EINFALL VON JENSEITS DER STERNE!\"<br><br>Ein Tentakel donnert nieder auf den Korb mit dem Picknick. Gute Idee oder nicht, jetzt ist Handeln gefragt.",
@@ -779,11 +779,36 @@
"questGiraffeUnlockText": "Schält Giraffen Eier zum Kauf im Marktplatz frei.",
"questChameleonUnlockText": "Schält Chamäleon Eier zum Kauf im Marktplatz frei",
"questGiraffeText": "Die Gear-affe",
"questCrabRageTitle": "Ablenkendes Gefummel",
"questCrabRageTitle": "Ablenkender Zeitvertreib",
"questCrabText": "Die fummelnde Krabbe",
"questCrabBoss": "Fummelnde Krabbe",
"questCrabBoss": "Herumtrödelnde Krabbe",
"questGiraffeNotes": "Du schlenderst durch das hohe Gras der Sloenstedi Savanne und genießt einen netten Spaziergang in der Natur als Auszeit von deinen Aufgaben. Als du die hügelige Landschaft durchstreifst, fällt dir eine Ansammlung von Gegenständen in der Ferne auf. Es ist ein Stapel aus Musikinstrumenten, Kunstzubehör, elektronischer Ausrüstung und mehr! Du wagst dich näher für einen besseren Blick.<br><br>“Hey, was glaubst du, was du da machst?“ ruft eine Stimme hinter einer Akazie hervor. Eine große und imposante Giraffe, die eine modische Sonnenbrille, eine Gitarre und eine ausgefallene Kamera um ihren langen Hals trägt, taucht auf. „Das ist alles meine Ausrüstung, sei vorsichtig und berühre nichts!“<br><br>Du bemerkst Staub auf vielen der Gegenstände. „Wow, du hast echt eine Menge Hobbies!“ sagst du. „Kannst du mir einige Kunstwerke zeigen oder ein Lied auf der Gitarre spielen?“<br><br>Die Giraffe zieht die Mundwinkel herunter, als sie all ihr Zubehör anschaut. „Ich habe so viel von diesem Zeug, aber ich weiß nicht, wo ich anfangen soll! Warum gibst du mir nicht ein bisschen von deiner Motivation, um mir die produktive Energie zu verleihen, die ich brauche, um endlich starten zu können!“",
"questChameleonNotes": "Es ist ein schöner Tag in einer warmen, regnerischen Ecke der Aufgabenwälder. Du bist auf der Jagd nach Neuzugängen für deine Blattsammlung, als ein Ast vor dir ohne Vorwarnung seine Farbe ändert! Und dann bewegt er sich!<br><br>Rückwärts stolpernd realisierst du, dass dies überhaupt kein Ast ist, sondern ein großes Chamäleon! Jeder Teil seines Körpers wechselt andauernd seine Farbe, während seine Augen in unterschiedliche Richtungen zucken.<br><br>“Geht es dir gut?“ fragst du das Chamäleon.<br><br>“Ahhh, na ja,“ sagt es und wirkt ein wenig durcheinander. „Ich habe versucht, mich anzupassen… aber es ist so überwältigend… die Farben kommen und gehen ständig! Es ist schwer, sich auf nur eine zu konzentrieren….“<br><br>“Aha,“ sagst du, „Ich glaube, ich kann helfen. Wir schärfen deine Konzentration mit einer kleinen Herausforderung! Halte deine Farben bereit!“<br><br>“Die Wette gilt!“ erwidert das Chamäleon.",
"questGiraffeBoss": "Gear-affe",
"questGiraffeCompletion": "Nachdem du der Gear-affe mit ein bisschen grundlegender Organisation ihres Stapels geholfen hast, fühlt ihr euch beide energiegeladener und motivierter!<br><br>Sie nimmt ihre Gitarre und ein Heft mit Anfängerübungen und spielt ein paar Noten. \"Es fühlt sich gut an, einen Schritt in die richtige Richtung zu machen, selbst wenn es nur ein kleiner ist. Vielen Dank, dass du mir geholfen hast! Nimm diese hier, ich habe gehört, du hast einige Haustiere und diese Kameraden könnten eine nette Ergänzung sein!\""
"questGiraffeCompletion": "Nachdem du der Gear-affe mit ein bisschen grundlegender Organisation ihres Stapels geholfen hast, fühlt ihr euch beide energiegeladener und motivierter!<br><br>Sie nimmt ihre Gitarre und ein Heft mit Anfängerübungen und spielt ein paar Noten. \"Es fühlt sich gut an, einen Schritt in die richtige Richtung zu machen, selbst wenn es nur ein kleiner ist. Vielen Dank, dass du mir geholfen hast! Nimm diese hier, ich habe gehört, du hast einige Haustiere und diese Kameraden könnten eine nette Ergänzung sein!\"",
"questCrabDropCrabEgg": "Kabbe (Ei)",
"questCrabUnlockText": "Schaltet Krabbeneier zum Kauf auf dem Marktplatz frei.",
"questChameleonCompletion": "Nach ein paar lebhaften Drehungen durchlief das Chamäleon alle Farben des Regenbogens und traf perfekt alle Farben, die du verlangt hattest.<br><br>\"Wow,\" sagt es, \"zusammenzuarbeiten, und es zu einem Spiel zu machen, hat mir wirklich geholfen, mich zu konzentrieren! Bitte nimm diese als Belohnung, du hast sie verdient! Bring diesen kleinen Jungen bei, wie man in alle Regenbogenfarben wechselt, wenn sie schlüpfen.\"",
"questCrabNotes": "Es ist ein warmer, sonniger Morgen, und Du genießt einen Besuch am Strand, um ein paar Bücher von Deiner Sommerleseliste zu lesen. Du schreckst auf, als du fast auf einen glänzenden Kristall in der Nähe eines flachen Lochs im Sand trittst.<br><br>„Ey, pass auf, wo du hingehst! Ich baue hier eine Wohnhöhle!“, sagt eine Stimme. Eine überraschend große Krabbe mit einem dekorativen Panzer buddelt sich vor Deinen Zehen aus dem Loch und schnappt mit ihrer Schere, während sie spricht.<br><br>„Hm, ist das eine Höhle?“, fragst Du und betrachtest die flache Vertiefung. Es sind Muscheln und Kristalle um sie herum angeordnet, aber es deutet nicht viel auf einen Rückzugsort hin.<br><br>Die Krabbe stottert. „Ey, das ist eine vorurteilsfreie Zone! Ich komme schon noch dazu, ich komme schon noch dazu... Ich bin gerade beim Dekorieren hängen geblieben. Manchmal muss eine Krabbe eben ein wenig Zeit vertrödeln“, sagt sie und rückt eine Schale zurecht.<br><br>„Warum hilfst Du nicht mit, wenn Du schon so großartige Vorstellungen davon hast, wie eine Höhle aussehen soll?“",
"questCrabCompletion": "Du und die Krabbe schafft es gemeinsam, alles an der richtigen Stelle zu platzieren, damit ein feiner Sandbau entsteht. Die Krabbe kuschelt sich fröhlich hinein.<br><br>„Danke!“, sagt sie und macht es sich gemütlich. „Das ist eine Höhle, die nur für mich gemacht ist. Endlich kann ich all meine perfekt platzierten Dekorationen genießen. Hier, nimm diese kleinen Kerlchen als Zeichen meiner Wertschätzung. Das ist ein Angebot, das du nicht ablehnen kannst!“",
"questCrabRageDescription": "Diese Leiste füllt sich, wenn du deine Tagesaufgaben nicht erledigst. Wenn sie voll ist, nimmt die Herumtrödelnde Krabbe einen Teil der MP deiner Party weg!",
"questCrabRageEffect": "Die Herumtrödelnde Krabbe lenkt dich mit Dekorationen ab, verlangsamt deine Arbeit beim Graben und entzieht dir einen Teil deiner Magie. Die MP der Party sind reduziert!",
"questRaccoonText": "Waschbär-Tycoon",
"questRaccoonCompletion": "„Ich glaube, es gibt wirklich genug schöne Steine für uns beide“, sagst du, während du die letzten deiner Gegenstände einsammelst. „Hier sind ein paar, die du von dem haben kannst, was ich gesammelt habe, ich habe genug zum Teilen!“<br><br>„Oh, das ist aber nett von dir“, sagt der Waschbär. „Hier sind auch ein paar nette kleine Geschenke für dich!“",
"questRaccoonBoss": "Gieriger Waschbär",
"questRaccoonRageTitle": "Schmuck-Tsunami",
"questRaccoonRageDescription": "Diese Leiste füllt sich, wenn du deine Tagesaufgaben nicht erledigst. Wenn sie voll ist, erhält der Waschbär-Tycoon einen Teil seiner Gesundheit zurück!",
"questRaccoonRageEffect": "Der Gierige Waschbär nimmt einige von dir gerettete Gegenstände an sich und stopft sie in den Baumstamm zurück. Der Boss erhält 30% seiner Gesundheit zurück!",
"questRaccoonDropRaccoonEgg": "Waschbär (Ei)",
"questRaccoonUnlockText": "Schaltet Waschbären-Eier zum Kauf am Marktplatz frei.",
"questRaccoonNotes": "Es ist ein warmer Herbsttag in Habitica und du machst einen langsamen Spaziergang entlang des Conquest Creek. Am Ufer siehst du ein paar hübsche Halbedelsteine, die sich perfekt für ein Projekt eignen, das du schon lange geplant hast.<br><br>Du fängst an, deine besten Funde in einem Haufen unter einem Baum zu sammeln. Seltsamerweise scheint der Haufen jedes Mal, wenn du zurückkommst, kleiner zu werden, nicht größer...<br><br>Da stimmt doch was nicht. Du blickst dich um, aber es fällt dir nichts Merkwürdiges auf. Gerade als du dich umdrehst, um zum Bach zurückzukehren, bemerkst du eine handähnliche Pfote, die aus einer Vertiefung im Baumstamm herausragt und dir einige deiner Steine entreißt!<br><br>„Hey!“, rufst du, “ich habe hart gearbeitet, um die Steine zu sammeln. Es ist nicht in Ordnung, sie zu nehmen, ohne zu fragen!“<br><br>Ein maskiertes Gesicht taucht aus dem Loch auf und grinst dich an. „Wer's findet, dem gehört's!“, sagt der Waschbär. Er schlüpft zurück in den Baum, die Säcke mit den Steinen in der Hand. Du springst ihm hinterher! Für diese Steine lohnt es sich zu kämpfen.",
"questDogText": "Dreifache Hundeprüfung!",
"questDogBoss": "Shiberus",
"questDogRageTitle": "Dreifacher Spielzeugwurf",
"questDogRageDescription": "Diese Leiste füllt sich, wenn du deine Tagesaufgaben nicht erledigst. Wenn sie voll ist, nimmt Shiberus einen Teil der MP deiner Party weg!",
"questDogRageEffect": "Shiberus wirft mit Spielzeug nach dir und blockiert deine Zaubersprüche! Die MP der Party werden reduziert!",
"questDogDropDogEgg": "Hund (Ei)",
"questDogUnlockText": "Schaltet den Kauf von Hundeeiern auf dem Marktplatz frei.",
"questDogNotes": "Du wurdest für eine Expedition ausgewählt, um die unterirdischen Höhlensysteme von Habitica zu kartieren! Forscher in Habit City vermuten, dass es in diesen Tiefen neue Werkzeuge für die Bewältigung von Aufgaben oder sogar unentdeckte Kreaturen geben könnte.<br><br>Während du felsige Tunnel in der Nähe der Ausläufer des Wandernden Gebirges erkundest, bemerkst du ein Leuchten, das von einem zerklüfteten Eingang vor dir ausgeht. Als du näher kommst, siehst du... Spielzeug? Plüschtiere und Gummibälle liegen auf dem Höhlenboden verstreut. Hörst du da ein Bellen?<br><br>Ein riesiger, dreiköpfiger Hund springt heraus und stürzt sich auf das Spielzeug, das du gerade aufheben wolltest! Du erstarrst und verlierst dabei fast deinen Arm! Aber... die Mäuler des Hundes scheinen zu sehr mit Spielzeug beschäftigt zu sein, um anzugreifen?<br><br>„Wuff!“, bellt eines der Hundemäuler und lässt einen zerrissenen Spielzeugwaschbären fallen. „Bist du hier, um mir beim Aufräumen zu helfen? Ich muss wirklich aufräumen, aber jedes Mal, wenn ich ein Spielzeug in die Hand nehme, spiele ich nur damit... Hier, denk schnell!!!“<br><br> Der Hund wirft dir einen Ball zu, und dann noch einen und noch einen. Diese zusätzlichen Köpfe machen das Ausweichen zu einem echten Training!",
"questDogCompletion": "Nachdem du alle Spielzeuge eingesammelt hast, denen du (zum Glück) ausgewichen bist, gibst du Shiberus einen sanften Klaps auf seinen mittleren Kopf.<br><br>„Es ist schön, sich auf eine große Aufgabe zu freuen, aber es könnte hilfreich sein, mit einem Plan vorzugehen. Vielleicht solltest du das nächste Mal am Eingang anfangen und dich rückwärts vorarbeiten? Oder 30 Minuten am Stück arbeiten und dann eine kurze Spielpause einschieben.\"<br><br>„Das ist eine gute Idee“, meldet sich der linke Kopf des Hundes zu Wort. Der rechte Kopf legt ein paar Gegenstände in deine Nähe, darunter auch etwas, das aussieht wie Eier... „Ich habe ein paar Dinge gefunden, die dir gefallen könnten, während wir gespielt haben. Danke für deine Hilfe!“"
}
+1 -1
View File
@@ -8,7 +8,7 @@
"rebirthOrb": "Hat eine Sphäre der Wiedergeburt verwendet um noch einmal von vorne zu beginnen, nachdem Level <%= level %> erreicht wurde.",
"rebirthOrb100": "Hat eine Sphäre der Wiedergeburt verwendet um noch einmal von vorne zu beginnen, nachdem Level 100 oder höher erreicht wurde.",
"rebirthOrbNoLevel": "Hat eine Sphäre der Wiedergeburt verwendet um noch einmal von vorne zu beginnen.",
"rebirthPop": "Beginne sofort von vorn mit einem Charakter auf Level 1, aber behalte Erfolge, Sammelgegenstände und Ausrüstung. Deine Aufgaben und ihre Verläufe bleiben erhalten, werden aber auf gelb zurückgesetzt. Deine Strähnen verfallen, außer für Aufgaben, die von aktiven Herausforderungen oder Gruppenplänen stammen. Gold, Erfahrung, Mana und alle Effekte von Fähigkeiten werden entfernt. All das wird sofort in Kraft treten. Für mehr Informationen, schau im Wiki auf der Seite <a href='https://habitica.fandom.com/de/wiki/Sphäre_der_Wiedergeburt' target='_blank'>Sphäre der Wiedergeburt</a> nach.",
"rebirthPop": "Beginne sofort von vorn mit einem Charakter auf Level 1, aber behalte Erfolge, Sammelgegenstände und Ausrüstung. Deine Aufgaben und ihre Verläufe bleiben erhalten, werden aber auf gelb zurückgesetzt. Deine Strähnen verfallen, außer für Aufgaben, die von aktiven Herausforderungen oder Gruppenplänen stammen. Gold, Erfahrung, Mana und alle Effekte von Fähigkeiten werden entfernt. All das wird sofort in Kraft treten.",
"rebirthName": "Sphäre der Wiedergeburt",
"rebirthComplete": "Du wurdest wiedergeboren!",
"nextFreeRebirth": "<strong><%= days %> Tage</strong> bis zur <strong>KOSTENLOSEN</strong> Sphäre der Wiedergeburt"
+22 -21
View File
@@ -2,7 +2,7 @@
"settings": "Einstellungen",
"language": "Sprache",
"americanEnglishGovern": "Im Fall von Bedeutungsunterschieden gilt die englische Version.",
"helpWithTranslation": "Möchtest Du bei der Übersetzung von Habitica helfen? Toll! Dann besuche doch die <a href=\"/groups/guild/7732f64c-33ee-4cce-873c-fc28f147a6f7\">Aspiring Linguists Guild</a>!",
"helpWithTranslation": "Hast du Interesse, bei der Übersetzung von Habitica helfen? Toll! Dann besuche doch die <a href=\"/groups/guild/7732f64c-33ee-4cce-873c-fc28f147a6f7\">Aspiring Linguists Guild</a>!",
"stickyHeader": "Kopfzeile anheften",
"newTaskEdit": "Neue Aufgaben im Bearbeiten-Modus öffnen",
"reverseChatOrder": "Zeige die Chat-Nachrichten in umgekehrter Reihenfolge",
@@ -18,7 +18,7 @@
"resetAccPop": "Starte neu, dabei werden alle Level, Gold, Ausrüstung, Verlauf und Aufgaben entfernt.",
"deleteAccount": "Konto löschen",
"deleteAccPop": "Kündige und entferne Dein Habitica-Konto.",
"feedback": "Wenn Du uns Feedback geben möchtest, gib es bitte unten ein - wir freuen uns darauf zu erfahren, was Dir an Habitica gefällt - oder auch nicht gefällt! Und falls Du Schwierigkeiten mit Englisch hast? Kein Problem! Schreib' in der Sprache, die Dir liegt.",
"feedback": "Wenn Du uns Feedback geben möchtest, gib es bitte unten ein - wir freuen uns darauf deine Meinung zu hören! Und falls Du Schwierigkeiten mit Englisch hast? Kein Problem! Schreib' in der Sprache, die Dir liegt.",
"dataExport": "Daten exportieren",
"saveData": "Hier sind ein paar Möglichkeiten, Deine Daten zu sichern.",
"habitHistory": "Habitica-Verlauf",
@@ -27,8 +27,8 @@
"userData": "Benutzerdaten",
"exportUserData": "Benutzerdaten exportieren:",
"export": "Exportieren",
"xml": "(XML)",
"json": "(JSON)",
"xml": "XML",
"json": "JSON",
"customDayStart": "Tageswechsel einstellen",
"sureChangeCustomDayStartTime": "Bist Du sicher, dass Du Deinen individuellen Tageswechsel umstellen willst? Deine Tagesaufgaben werden das nächste Mal zurückgesetzt, wenn Du Habitica nach <%= time %> verwendest. Stelle sicher, dass Du bis dahin Deine Aufgaben erledigt hast!",
"customDayStartHasChanged": "Dein persönlicher Tagesstart wurde geändert.",
@@ -45,10 +45,10 @@
"confirmPass": "Neues Passwort bestätigen",
"newUsername": "Neuer Benutzername",
"dangerZone": "Gefahrenzone",
"resetText1": "WARNUNG! Es werden große Teile Deines Accounts zurückgesetzt. Wir raten dringend davon ab. Jedoch finden einige Spieler diese Funktion sinnvoll, um nach einem anfänglichen Testen der Seite neu beginnen zu können.",
"resetText2": "Du verlierst alle Deine Level, Dein Gold und Deine Erfahrungspunkte. Alle Deine Aufgaben (außer Aufgaben aus Herausforderungen) werden permanent gelöscht, und Du verlierst alle ihre historischen Daten. Du verlierst Deine gesamte Ausrüstung außer Abonnement-Überraschungsgegenstände und gratis Erinnerungsgegenstände. Du wirst die Möglichkeit haben, alle gelöschten Gegenstände zurückzukaufen, inklusive allen Gegenständen limitierter Ausgabe (Du musst für klassenspezifische Ausrüstung der richtigen Klasse angehören, um sie zurückzukaufen). Du behältst Deine aktuelle Klasse, Deine Erfolge, und Deine Haus- und Reittiere. Möglicherweise möchtest Du lieber die Sphäre der Wiedergeburt nutzen, die eine weit sicherere Option darstellt und Deine Aufgaben und Ausrüstung beibehält.",
"deleteLocalAccountText": "Bist Du sicher? Dies wird Dein Konto für immer löschen und es kann nicht wiederhergestellt werden! Wenn Du Habitica wieder verwenden möchtest, musst Du ein neues Konto registrieren. Gesparte oder verbrauchte Edelsteine werden nicht ersetzt. Wenn Du absolut sicher bist, dann tippe Dein Passwort in das Textfeld unten ein.",
"deleteSocialAccountText": "Bist Du sicher? Dies wird Dein Konto für immer löschen und es kann nicht wiederhergestellt werden! Wenn Du Habitica wieder verwenden möchtest, musst Du ein neues Konto registrieren. Gesparte oder verbrauchte Edelsteine werden nicht ersetzt. Wenn Du absolut sicher bist, dann tippe \"<%= magicWord %>\" in das Textfeld unten ein.",
"resetText1": "Sei vorsichtig! Es werden große Teile Deines Accounts zurückgesetzt. Wir raten dringend davon ab. Jedoch finden einige Spieler diese Funktion sinnvoll, um nach einem anfänglichen Testen der Seite neu beginnen zu können.",
"resetText2": "Eine andere Möglichkeit ist die Verwendung einer <b>Sphäre der Wiedergeburt</b>, die alles andere zurücksetzt, während deine Aufgaben und Ausrüstung erhalten bleiben.",
"deleteLocalAccountText": "<b>Bist Du sicher?</b> Dies wird Dein Konto für immer löschen und es kann nicht wiederhergestellt werden! Wenn Du Habitica wieder verwenden möchtest, musst Du ein neues Konto registrieren. Gesparte oder verbrauchte Edelsteine werden nicht ersetzt. Wenn Du absolut sicher bist, dann tippe Dein Passwort in das Textfeld unten ein.",
"deleteSocialAccountText": "<b>Bist Du sicher?</b> Dies wird Dein Konto für immer löschen und es kann nicht wiederhergestellt werden! Wenn Du Habitica wieder verwenden möchtest, musst Du ein neues Konto registrieren. Gesparte oder verbrauchte Edelsteine werden nicht ersetzt. Wenn Du absolut sicher bist, dann tippe <b>\"<%= magicWord %>\"</b> in das Textfeld unten ein.",
"API": "API",
"APIv3": "API v3",
"APIText": "Kopiere sie zur Anwendung in Applikationen von Drittanbietern. Sieh Dein API-Token aber als Passwort an und verbreite es nicht. Du wirst vielleicht gelegentlich nach Deiner Benutzer-ID gefragt, aber poste niemals Dein API-Token öffentlich wo es andere sehen können, auch nicht auf GitHub.",
@@ -60,8 +60,8 @@
"resetDo": "Ja, setzt mein Konto jetzt zurück!",
"resetComplete": "Zurückgesetzt!",
"fixValues": "Werte reparieren",
"fixValuesText1": "Wenn Du Opfer eines Bugs geworden bist oder einen Fehler gemacht hast, der Deinen Charakter unfair beeinflusst hat (Schaden, den Du nicht hättest erleiden dürfen, Gold das Du nicht verdient hast, usw.), dann kannst Du das hier manuell korrigieren. Ja, das eröffnet die Möglichkeit zu cheaten: Verwende dieses Feature mit Bedacht, oder Du verdirbst Dir das Ausbilden Deiner Gewohnheiten!",
"fixValuesText2": "Beachte, dass Du hier keine Strähnen einzelner Aufgaben wiederherstellen kannst. Um das zu tun, bearbeite eine Tagesaufgabe unter erweiterte Optionen. Dort wirst Du ein \"Strähne wiederherstellen\"-Feld finden.",
"fixValuesText1": "Wenn Du etwas bemerkst, das Deinen Charakter unfair beeinflusst hat (Schaden, den Du nicht hättest erleiden dürfen, Gold das Du nicht verdient hast, usw.), dann kannst Du das hier manuell korrigieren. Ja, das eröffnet die Möglichkeit zu cheaten: Verwende dieses Feature mit Bedacht, oder Du verdirbst Dir das Ausbilden Deiner Gewohnheiten!",
"fixValuesText2": "<b>Aufgepasst</b>: Um Strähnen einzelner Aufgaben wiederherzustellen, bearbeite die Aufgabe und verwende das \"Strähne wiederherstellen\"-Feld.",
"fix21Streaks": "21-Tage-Strähnen",
"discardChanges": "Änderungen verwerfen",
"deleteDo": "Ja, löscht jetzt mein Konto!",
@@ -86,26 +86,26 @@
"giftedSubscriptionInfo": "<%= name %> hat Dir ein <%= months %>-monatiges Abonnement geschenkt",
"giftedSubscriptionFull": "Hallo <%= username %>, <%= sender %> hat Dir <%= monthCount %> Monate Abonnement geschickt!",
"invitedParty": "Du wurdest in eine Party eingeladen",
"invitedGuild": "Du wurdest in eine Gilde eingeladen",
"invitedGuild": "Du wurdest in eine Gruppe eingeladen",
"importantAnnouncements": "Erinnerungen zur Anmeldung, um Aufgaben zu komplettieren und Preise zu erhalten",
"weeklyRecaps": "Zusammenfassung Deiner Account-Aktivitäten in dieser Woche (Notiz: Ist zurzeit wegen Performance-Problemen deaktiviert. Wir hoffen, dass es bald wieder zurück ist und werden demnächst wieder E-Mails verschicken!)",
"onboarding": "Hilfe, um Dein Habitica-Konto einzurichten",
"majorUpdates": "Wichtige Ankündigungen",
"questStarted": "Dein Quest hat begonnen",
"invitedQuest": "Zu einem Quest eingeladen",
"kickedGroup": "Aus der Gruppe rausgeworfen",
"kickedGroup": "Aus der Gruppe entfernt",
"remindersToLogin": "Erinnerungen, bei Habitica reinzuschauen",
"unsubscribedSuccessfully": "Erfolgreich abgemeldet!",
"unsubscribedTextUsers": "Du hast Dich erfolgreich von allen Habitica Emails abgemeldet. Du kannst die Emails, die Du erhalten möchtest, unter <a href=\"/user/settings/notifications\">Einstellungen>&gt; Mitteilungen</a> freischalten (erfordert Anmeldung).",
"unsubscribedTextOthers": "Du wirst keine weitere E-Mails von Habitica erhalten.",
"unsubscribeAllEmails": "Häkchen setzen, um keine weiteren E-Mails zu erhalten",
"unsubscribeAllEmailsText": "Indem ich hier ein Häkchen gesetzt habe, bestätige ich, dass ich verstanden habe, dass ich aus allen Habitica-E-Mail-Listen ausgetragen wurde. Habitica kann mir keine E-Mails mehr zu wichtigen Änderungen der Seite oder meines Accounts schicken.",
"unsubscribeAllPush": "Abhaken um keine weiteren Push-Nachrichten zu erhalten",
"unsubscribeAllEmails": "Keine weiteren E-Mails erhalten",
"unsubscribeAllEmailsText": "Habitica wird dir keine E-Mails mehr zu wichtigen Änderungen der Seite oder deinem Account schicken können.",
"unsubscribeAllPush": "Keine weiteren Push-Nachrichten erhalten",
"correctlyUnsubscribedEmailType": "Erfolgreich \"<%= emailType %>\"-E-Mails abbestellt.",
"subscriptionRateText": "Abonnement über <strong>$<%= price %> USD</strong> erneuert jede(n) <strong><%= months %> Monat(e)</strong>",
"benefits": "Vorteile",
"coupon": "Gutschein",
"couponText": "Manchmal verteilen wir auf Events Promo-Codes für spezielle Ausrüstung (z. B. an unserem WonderCon-Stand)",
"couponText": "Manchmal verteilen wir auf Events Promo-Codes für spezielle Ausrüstung.",
"apply": "Anwenden",
"promoCode": "Aktionscode",
"promoCodeApplied": "Promo-Code aktiviert! Überprüfe Dein Inventar",
@@ -117,7 +117,7 @@
"generate": "Erstelle",
"getCodes": "Codes erhalten",
"webhooks": "WebHooks",
"webhooksInfo": "Habitica stellt WebHooks zur Verfügung, damit bei bestimmten Aktionen in Deinem Konto Informationen an ein Skript auf einer anderen Website gesendet werden können. Du kannst diese Skripte hier anführen. Sei vorsichtig mit dieser Funktion, denn die Angabe einer falschen URL kann in Habitica zu Fehlern oder Verzögerungen führen. Weitere Informationen findest Du auf der <a target=\"_blank\" href=\"https://habitica.fandom.com/wiki/Webhooks\">WebHooks-Seite</a> des Wikis.",
"webhooksInfo": "WebHooks bieten Entwicklern die Möglichkeit, Benachrichtigngen zu erhalten, wenn eine bestimmte Aktion durchgeführt wird, z. B. das Bewerten oder Aktualisieren einer Aufgabe oder das Senden einer Nachricht in einer Gruppe. Indem du einen WebHook erstellst, kannst du Änderungen in Habitica wahrnehmen und Anwendungen entwickeln, die auf diese Änderungen reagieren. <br><br> Weitere Informationen und Beispiele findest Du bei den <a target=\"_blank\" href=\"https://habitica.fandom.com/wiki/Webhooks\">API Docs</a>.",
"enabled": "Aktiviert",
"webhookURL": "WebHook-URL",
"invalidUrl": "Ungültige URL",
@@ -188,16 +188,16 @@
"transaction_release_pets": "Haustiere freigelassen",
"transaction_release_mounts": "Reittiere freigelassen",
"addPasswordAuth": "Passwort hinzufügen",
"nextHourglassDescription": "Abonnierende erhalten Mystische Sanduhren\ninnerhalb der ersten drei Tages des Monats.",
"nextHourglassDescription": "Abonnierende erhalten eine Mystische Sanduhr, ein Mystisches Ausrüstungsset und Edelsteine, die innerhalb der ersten zwei Tage des Monats auf dem Markt wieder aufgefüllt werden.",
"gemCap": "Edelsteinobergrenze",
"nextHourglass": "Nächste Sanduhr",
"nextHourglass": "Nächste Lieferung einer Mystischen Sanduhr",
"adjustment": "Änderung",
"dayStartAdjustment": "Änderung des Tageswechsel",
"passwordSuccess": "Passwort erfolgreich geändert",
"giftSubscriptionRateText": "<strong>$<%= price %> $(USD)</strong> für <strong><%= months %> Monate</strong>",
"transaction_admin_update_balance": "<b>Admin</b> gegeben",
"transaction_admin_update_hourglasses": "<b>Admin</b> aktualisiert",
"transaction_create_bank_challenge": "Herausforderung mit Edelsteinen des Gildenbankkontos erstellt",
"transaction_create_bank_challenge": "Mit Edelsteinen des Gildenbankkontos <b>erstellte Herausforderungen</b>",
"passwordIssueLength": "Passwörter müssen zwischen 8 und 64 Zeichen lang sein.",
"timestamp": "Zeitstempel",
"amount": "Menge",
@@ -257,5 +257,6 @@
"connect": "Verbinden",
"changeClassDisclaimer": "Bei Änderung deiner Klasse bekommst du alle deine vorhandenen Attributspunkte erstattet. Passe deine Attributspunkte im Attributwerte-Abschnitt deines Profils an, sobald du eine neue Klasse gewählt hast.",
"APITokenDisclaimer": "<b>Dein API Token ist wie ein Passwort. Teile es nicht öffentlich.</b>Es kann sein, daß du gelegentlich nach deiner User ID gefragt wirst, aber poste niemals dein API Token, wo andere es sehen können, einschließlich Github.<br><br><b>Hinweis:</b> Wenn du ein neues API Token brauchst (z.B., wenn du es aus Versehen geteilt hast), schreib eine Email an <a href='mailto:admin@habitica.com' target='_blank'>admin@habitica.com</a> mit deiner User ID und deinem aktuellen Token. Wenn es dann zurückgesetzt ist, musst du alles wieder neu authorisieren, indem du dich auf der Website und der mobilen App abmeldest und das neue Token bei allen anderen Habitica Tools, die du nutzt, angibst.",
"thirdPartyTools": "Drittanbieter Apps, Erweiterungen, und alle möglichen anderen Tools, die du mit deinem Account nutzen kannst, findest du im <a href='https://habitica.fandom.com/wiki/Extensions,_Add-Ons,_and_Customizations' target='_blank'>Habitica Wiki</a>."
"thirdPartyTools": "Drittanbieter Apps, Erweiterungen, und alle möglichen anderen Tools, die du mit deinem Account nutzen kannst, findest du im <a href='https://habitica.fandom.com/wiki/Extensions,_Add-Ons,_and_Customizations' target='_blank'>Habitica Wiki</a>.",
"transaction_subscription_bonus": "<b>Abonnement</b>-Bonus"
}
+40 -16
View File
@@ -2,12 +2,12 @@
"subscription": "Abonnement",
"subscriptions": "Abonnements",
"sendGems": "Verschicke Edelsteine",
"buyGemsGold": "Kaufe Edelsteine mit Gold",
"buyGemsGold": "Kostenlose Monatliche Edelsteine",
"mustSubscribeToPurchaseGems": "Du musst ein Abonnement abschließen, um Edelsteine mit Gold kaufen zu können",
"reachedGoldToGemCapQuantity": "Deine angeforderte Menge von <%= quantity %> übersteigt den Betrag, den Du diesen Monat noch kaufen darfst (<%= convCap %>). Der volle Betrag wird innerhalb der ersten drei Tage eines Monats verfügbar gemacht. Danke, dass Du ein Abonnement hast!",
"mysteryItem": "Exklusive monatliche Gegenstände",
"mysteryItemText": "Du wirst jeden Monat einen einzigartigen kosmetischen Gegenstand für Deinen Avatar erhalten! Zusätzlich gewähren Dir die Mysteriösen Zeitreisenden für je drei aufeinanderfolgende Abonnement-Monate Zugang zu historischen (oder futuristischen) kosmetischen Gegenständen.",
"exclusiveJackalopePet": "Exklusives Haustier",
"exclusiveJackalopePet": "Besonderes Haustier",
"giftSubscription": "Willst Du jemand anderem die Vorteile eines Abonnements schenken?",
"giftSubscriptionText4": "Danke, dass Du Habitica unterstützt!",
"groupPlans": "Gruppen-Pläne",
@@ -91,7 +91,7 @@
"mysterySet301703": "Pfauen-Steampunk-Set",
"mysterySet301704": "Fasanen-Steampunk-Set",
"mysterySetwondercon": "Wondercon",
"subUpdateCard": "Aktualisiere Deine Kreditkarte",
"subUpdateCard": "Bearbeite Deine Kreditkarte",
"subUpdateTitle": "Aktualisiere",
"notEnoughHourglasses": "Du hast nicht genügend mystische Sanduhren.",
"petsAlreadyOwned": "Bereits im Besitz dieses Haustieres.",
@@ -120,14 +120,14 @@
"gemBenefit2": "Hintergründe, die Deinen Avatar in die Welt von Habitica eintauchen lassen!",
"gemBenefit3": "Aufregende Questlinien, welche Haustier-Eier zurücklassen.",
"gemBenefit4": "Die Attributspunkte Deines Avatars zurücksetzen und seine Klasse ändern.",
"subscriptionBenefit1": "Alexander der Händler wird Dir von nun an auf dem Marktplatz Edelsteine für 20 Goldmünzen das Stück verkaufen!",
"subscriptionBenefit3": "Finde noch mehr Gegenstände in Habitica mit der verdoppelten Obergrenze für Beutefunde.",
"subscriptionBenefit4": "Einzigartiger Verkleidungsgegenstand für Deinen Avatar jeden Monat.",
"subscriptionBenefit5": "Erhalte das Königlich purpurfarbene Wolpertinger Haustier, indem Du ein Abonnement abschließt.",
"subscriptionBenefit6": "Verdiene Dir Mystische Sanduhren, um im Laden der Mysteriösen Zeitreisenden Gegenstände zu erwerben!",
"subscriptionBenefit1": "Erhalte nun bis zu 50 mit Gold kaufbare Edelsteine auf dem Marktplatz, um Quests, Individualisierungen, Haustiere und vieles mehr zu kaufen!",
"subscriptionBenefit3": "Finde die doppelte Anzahl an Eiern, Schlüpfelixieren und Futter am Tag, um deine Haustiersammlung zu erweitern!",
"subscriptionBenefit4": "Staffiere dich mit der neuesten exklusiven Ausrüstung aus. Abonniere jetzt, um <%= month %>s <%= currentMysterySetName %> zu erhalten!",
"subscriptionBenefit5": "Erhalte den exklusiven Königlich purpurfarbenen Wolpertinger, wenn Du heute ein Abonnement abschließt!",
"subscriptionBenefit6": "Verpasse nie wieder einen Gegenstand mit einer Mystischen Sanduhr pro Monat, die du im Laden der Mysteriösen Zeitreisenden benutzen kannst!",
"purchaseAll": "Set kaufen",
"gemsRemaining": "Verbleibende Edelsteine",
"notEnoughGemsToBuy": "Du kannst die gewünschte Anzahl Edelsteine nicht kaufen",
"gemsRemaining": "verbleibende",
"notEnoughGemsToBuy": "Keine weiteren Edelsteine zum Kauf in diesem Monat erhältlich. Mehr werden innerhalb der ersten 3 Tage jedes Monats verfügbar sein.",
"mysterySet201903": "Ei-nzigartiges Set",
"mysterySet201902": "Geheimnisvolles Verliebten-Set",
"confirmCancelSub": "Bist Du sicher, dass Du Dein Abonnement kündigen willst? Du verlierst alle Vorteile des Abonnements.",
@@ -147,12 +147,12 @@
"backgroundAlreadyOwned": "Hintergrund bereits im Besitz.",
"mysticHourglassNeededNoSub": "Dieser Gegenstand erfordert eine Mystische Sanduhr. Du erhältst Mystische Sanduhren durch Abschluss eines Habitica-Abonnements.",
"mysterySet202002": "Stilvolles Schätzchen-Set",
"cancelYourSubscription": "Abonnement aufheben?",
"subscriptionInactiveDate": "Deine Abonnementvorteile werden ab dem <strong><%= date %></strong> deaktiviert",
"cancelYourSubscription": "Möchtest Du Dein Abonnement beenden?",
"subscriptionInactiveDate": "Deine Abonnementvorteile werden ab dem <br><strong><%= date %></strong> deaktiviert",
"subscriptionCanceled": "Dein Abonnement ist aufgehoben",
"youAreSubscribed": "Du hast Habitica abonniert",
"monthlyMysteryItems": "Monatliche Überraschungsgegenstände",
"subscribersReceiveBenefits": "Abonnenten erhalten diese nützlichen Vorteile!",
"monthlyMysteryItems": "Limitierte Monatliche Ausrüstungs-Sets",
"subscribersReceiveBenefits": "Bleibe mit noch mehr Belohnungen motiviert, wenn Du abonnierst",
"giftASubscription": "Schenke ein Abonnement",
"cancelSubAlternatives": "Solltest Du technische Probleme haben oder Habitica bei Dir nicht richtig funktionieren, bitte <a href='mailto:admin@habitica.com'>kontaktiere uns</a>. Wir möchten Dir helfen, Habitica optimal zu nutzen.",
"readyToResubscribe": "Bereit, erneut zu abonnieren?",
@@ -170,7 +170,7 @@
"usuallyGems": "Normalerweise <%= originalGems %>",
"supportHabitica": "Unterstütze Habitica",
"cancelSubInfoApple": "Bitte folge der <a href=\"https://support.apple.com/de-de/HT202039\">offiziellen Anleitung von Apple</a>, um Dein Abonnement zu kündigen oder um das Kündigungsdatum zu sehen, wenn Du das Abonnement bereits gekündigt hast. Diese Ansicht kann Dir nicht anzeigen, ob Dein Abonnement beendet wurde.",
"cancelSubInfoGoogle": "Bitte gehe zum Abschnitt \"Account\" > \"Abonnements\" im Google Play Store, um Dein Abonnement zu kündigen oder um das Kündigungsdatum zu sehen, wenn Du das Abonnement bereits gekündigt hast. Diese Ansicht kann Dir nicht anzeigen, ob Dein Abonnement beendet wurde.",
"cancelSubInfoGoogle": "Um Dein Abonnement zu kündigen oder um das Kündigungsdatum zu sehen, wenn Du das Abonnement bereits gekündigt hast, gehe zum <a href='https://play.google.com/store/account/subscriptions'>Google Play Store</a>. Alle verbleibenden Monate an Abonnement-Credits werden Deinem Enddatum nach der Kündigung hinzugefügt.",
"organization": "Organisation",
"mysterySet202010": "Verführerisches Fledermaus-Set",
"dropCapExplanation": "Morgen, wenn Deine Tagesaufgaben zurückgesetzt werden, wird es auch wieder Beute zu finden geben. Bis dahin machst Du aber auch weiterhin Questfortschritte und verdienst Goldstücke und Erfahrung, wenn Du Aufgaben abschließt.",
@@ -235,5 +235,29 @@
"mysterySet202407": "Liebenswertes Axolotl Set",
"mysterySet202408": "Arkanes Aegis Set",
"mysterySet202409": "Heliotrop Magier Set",
"mysterySet202410": "Candy Corn Fuchs Set"
"mysterySet202410": "Candy Corn Fuchs Set",
"subscribeTo": "Abonniere",
"monthlyMysticHourglass": "Monatliche Mystische Sanduhr",
"recurringMonthly": "Monatlich wiederkehrend",
"recurringNMonthly": "Alle <%= length %> Monate wiederkehrend",
"unlockNGems": "Schalte <strong><%= count %> Edelsteine</strong> pro Monat im Markt frei",
"maxGemCap": "Starte automatisch mit der maximalen <strong>Edelsteinobergrenze</strong>",
"monthlyGemsLabel": "Monatliche Edelsteine",
"popular": "Beliebt",
"immediate12Hourglasses": "Erhalte <strong>12 Mystische Sanduhren</strong> unmittelbar nach deinem ersten 12-Monats-Abonnement!",
"subscribe": "Abonniere",
"selectPayment": "Wähle Deine Bezahlmethode",
"giftSubscriptionLeadText": "Wähle unten das Abonnement aus, das du verschenken willst! Dieser Kauf erneuert sich nicht automatisch.",
"oneMonthGift": "Für 1 Monat",
"nMonthsGift": "Für <%= months %> Monate",
"unlockNGemsGift": "Sie schalten <strong><%= count %> Edelsteine</strong> pro Monat im Markt frei",
"earn2GemsGift": "Sie verdienen <strong>+2 Edelsteine</strong> für jeden Monat, in dem sie abonniert haben",
"maxGemCapGift": "Sie werden die maximale <strong>Edelsteinobergrenze</strong> haben",
"mysterySet202412": "Zuckerstangen-Waldkaninchen-Set",
"resubscribeToPickUp": "Abonniere erneut, um dort weiterzumachen, wo Du aufgehört hast!",
"subscriptionChangeAnnouncement": "<strong>Abonnementvorteile und die Art und Weise, wie sie ausgeschüttet werden, ändert sich am 19. November. </strong> <%= linkStart %>Klicke hier</a>, um mehr über diese Änderung zu lesen.",
"earn2Gems": "Verdiene <strong>+2 Edelsteine</strong> für jeden Monat, in dem du abonniert hast",
"subscribeAgainContinueHourglasses": "Erneuere Dein Abonnement, um weiterhin Mystische Sanduhren zu erhalten",
"mysterySet202411": "Borstenkämpfer Set",
"mysterySet202501": "Frostbinder-Set"
}
@@ -1003,6 +1003,14 @@
"backgroundCastleHallWithHearthText": "Castle Hall with Hearth",
"backgroundCastleHallWithHearthNotes": "Bask in the warmth of a Castle Hall with a Hearth.",
"backgrounds122024": "SET 127: Released December 2024",
"backgroundFirstSnowForestText": "First Snow in the Forest",
"backgroundFirstSnowForestNotes": "Step into the First Snow in the Forest.",
"backgrounds012025": "SET 128: Released January 2025",
"backgroundWinterLandscapeWithCabinText": "Winter Landscape with Cabin",
"backgroundWinterLandscapeWithCabinNotes": "Stay cozy in a Winter Landscape with a Cabin.",
"timeTravelBackgrounds": "Steampunk Backgrounds",
"backgroundAirshipText": "Airship",
"backgroundAirshipNotes": "Become a sky sailor on board your very own Airship.",
+1
View File
@@ -335,6 +335,7 @@
"hatchingPotionRoseGold": "Rose Gold",
"hatchingPotionFungi": "Fungi",
"hatchingPotionKoi": "Koi",
"hatchingPotionGingerbread": "Gingerbread",
"hatchingPotionNotes": "Pour this on an egg, and it will hatch as a <%= potText(locale) %> Pet.",
"premiumPotionUnlimitedNotes": "Not usable on Quest Pet eggs.",
+1 -1
View File
@@ -51,7 +51,7 @@
"webFaqAnswer40": "Gems are Habiticas in-app paid currency used to purchase Equipment, Avatar Customizations, Backgrounds, and more! Gems can be purchased in bundles or with Gold if youre a Habitica subscriber. You can also win Gems by being selected as the winner of a Challenge.",
"faqQuestion41": "What are Mystic Hourglasses, and how do I get them?",
"webFaqAnswer41": "Mystic Hourglasses are Habiticas exclusive Subscriber currency used in the Time Travelers Shop! Hourglasses are delivered on a set schedule based on your subscription plan.\n\nHourglass delivery schedule:\n * 1-Month subscribers get 1 Hourglass at the start of the month after the 3rd consecutive payment.\n * 3-Month subscribers get 1 Hourglass immediately after subscribing, then 1 more Hourglass at the start of the month after each renewal.\n * 6-Month subscribers get 2 Hourglasses immediately after subscribing, then 2 more Hourglasses at the start of the month after each renewal.\n * 12-Month subscribers get 4 Hourglasses immediately after subscribing, then 4 more Hourglasses at the start of the month after each renewal.",
"webFaqAnswer41": "Mystic Hourglasses are Habiticas exclusive Subscriber currency used in the Time Travelers Shop. Subscribers receive a Mystic Hourglass at the start of each month they have subscription benefits, along with a bunch of other perks. Be sure to check out our subscription options if youre interested in the special Backgrounds, Pets, Quests, and Equipment offered in the Time Travelers Shop!",
"faqQuestion42": "What can I do to increase accountability?",
"webFaqAnswer42": "One of the best ways to motivate yourself and hold yourself accountable for accomplishing your tasks is to join a Party! Partying with other Habitica players is a great way to take on Quests to receive Pets and Equipment, receive buffs from Party members Skills, and boost your motivation.\n\nAnother way to increase accountability is to join a Challenge. Challenges automatically add tasks related to a specific goal to your lists! They also add an element of competition against other Habitica players that may give you a motivation boost as you strive for the Gem prize. There are official Challenges created by the Habitica Team as well Challenges made by other players.",
+49
View File
@@ -533,6 +533,15 @@
"weaponSpecialFall2024MageText": "Staff of the Underworld",
"weaponSpecialFall2024MageNotes": "Task steps will instantly become simplified with one touch of this shining weapon. Increases Intelligence by <%= int %> and Perception by <%= per %>. Limited Edition Fall 2024 Gear.",
"weaponSpecialWinter2025WarriorText": "Moose Warrior Axe",
"weaponSpecialWinter2025WarriorNotes": "A mighty axe for a mighty moose! Youll be unstoppable! Increases Strength by <%= str %>. Limited Edition Winter 2024-2025 Gear.",
"weaponSpecialWinter2025RogueText": "Snowflake Burst",
"weaponSpecialWinter2025RogueNotes": "Thump and dazzle those difficult tasks into submission! Youll be unstoppable! Increases Strength by <%= str %>. Limited Edition Winter 2024-2025 Gear.",
"weaponSpecialWinter2025HealerText": "Star Wand",
"weaponSpecialWinter2025HealerNotes": "What you need now are more lights and a glowing star to go on top! You'll be unstoppable! Increases Intelligence by <%= int %>. Limited Edition Winter 2024-2025 Gear.",
"weaponSpecialWinter2025MageText": "Northern Lights Display",
"weaponSpecialWinter2025MageNotes": "This stunning, colorful show provides the perfect backdrop! Youll be unstoppable! Increases Intelligence by <%= int %> and Perception by <%= per %>. Limited Edition Winter 2024-2025 Gear.",
"weaponMystery201411Text": "Pitchfork of Feasting",
"weaponMystery201411Notes": "Stab your enemies or dig in to your favorite foods - this versatile pitchfork does it all! Confers no benefit. November 2014 Subscriber Item.",
"weaponMystery201502Text": "Shimmery Winged Staff of Love and Also Truth",
@@ -1304,6 +1313,16 @@
"armorSpecialFall2024MageText": "Underworld Sorceror Armor",
"armorSpecialFall2024MageNotes": "Be one with the underworld and embrace the power of mages whove come before you in this armor. Increases Intelligence by <%= int %>. Limited Edition Fall 2024 Gear.",
"armorSpecialWinter2025WarriorText": "Moose Warrior Armor",
"armorSpecialWinter2025WarriorNotes": "Everyones going to step aside and make way for you when you wear this armor. Increases Constitution by <%= con %>. Limited Edition Winter 2024-2025 Gear.",
"armorSpecialWinter2025RogueText": "Snow Costume",
"armorSpecialWinter2025RogueNotes": "Although you look like youre covered in cold snow, you are toasty, warm, jolly, and happy when you wear this costume. Increases Perception by <%= per %>. Limited Edition Winter 2024-2025 Gear.",
"armorSpecialWinter2025HealerText": "Robe of String Lights",
"armorSpecialWinter2025HealerNotes": "Twinkle your way through your tasks. Just be careful—if one bulb goes out, they all go out. Increases Constitution by <%= con %>. Limited Edition Winter 2024-2025 Gear.",
"armorSpecialWinter2025MageText": "Aurora Cloak",
"armorSpecialWinter2025MageNotes": "Wonder, whimsy, enchantment, and splendor will fill your days when you dance in this cloak. Increases Intelligence by <%= int %>. Limited Edition Winter 2024-2025 Gear.",
"armorMystery201402Text": "Messenger Robes",
"armorMystery201402Notes": "Shimmering and strong, these robes have many pockets to carry letters. Confers no benefit. February 2014 Subscriber Item.",
"armorMystery201403Text": "Forest Walker Armor",
@@ -1432,6 +1451,8 @@
"armorMystery202406Notes": "Haunt your enemies with style and flair! Confers no benefit. June 2024 Subscriber Item.",
"armorMystery202407Text": "Amiable Axolotl Suit",
"armorMystery202407Notes": "Glide through lakes and canals with your sweeping pink tail! Confers no benefit. July 2024 Subscriber Item.",
"armorMystery202412Text": "Candy Cane Cottontail Coat",
"armorMystery202412Notes": "A fun and fluffy look to keep you snug on a winter day. Confers no benefit. December 2024 Subscriber Item.",
"armorMystery301404Text": "Steampunk Suit",
"armorMystery301404Notes": "Dapper and dashing, wot! Confers no benefit. February 3015 Subscriber Item.",
@@ -1656,6 +1677,10 @@
"armorArmoireFunnyFoolCostumeNotes": "Dum-de-dum! Surely you jest. This colorful outfit looks amazing on you! Increases Strength by <%= str %>. Enchanted Armoire: Funny Fool Set (Item 2 of 3)",
"armorArmoireStormKnightArmorText": "Storm Knight Armor",
"armorArmoireStormKnightArmorNotes": "In this armor, you are nearly invincible. Your enemies will never see the storms end. Increases Perception by <%= per %>. Enchanted Armoire: Storm Knight Set (Item 2 of 3)",
"armorArmoireFestiveHelperOverallsText": "Festive Helper Overalls",
"armorArmoireFestiveHelperOverallsNotes": "Durable and comfortable, these overalls are great for working, playing, and assisting others. Plus, it has pockets! Increases Constitution by <%= con %>. Enchanted Armoire: Festive Helper Set (Item 2 of 2)",
"armorArmoireSnowyFluffTrimmedCoatText": "Snowy Fluff-Trimmed Coat",
"armorArmoireSnowyFluffTrimmedCoatNotes": "As the first flakes fall around you, this coat will not only keep you toasty but also help you blend in perfectly with your snowy surroundings. Glide along the ice in style! Increases Strength and Intelligence by <%= attrs %> each. Enchanted Armoire: Snowy Trapper Hat Set (Item 2 of 2).",
"headgear": "helm",
"headgearCapitalized": "Headgear",
@@ -2163,6 +2188,15 @@
"headSpecialFall2024MageText": "Underworld Sorcerer Mask",
"headSpecialFall2024MageNotes": "Whether youre mysterious or whimsical, you wont be missed when you wear this! Increases Perception by <%= per %>. Limited Edition Fall 2024 Gear.",
"headSpecialWinter2025WarriorText": "Moose Warrior Helmet",
"headSpecialWinter2025WarriorNotes": "So, get this: now you look just like a moose. Wear those antlers with pride. Increases Strength by <%= str %>. Limited Edition Winter 2024-2025 Gear.",
"headSpecialWinter2025RogueText": "Snow Mask",
"headSpecialWinter2025RogueNotes": "There is definitely some magic in this hat, because it transforms you into a snow person. Just dont let the bunny get too close to your carrot nose. Increases Perception by <%= per %>. Limited Edition Winter 2024-2025 Gear.",
"headSpecialWinter2025HealerText": "Tangle of String Lights",
"headSpecialWinter2025HealerNotes": "Dont bother untangling these because they are already in the shape of a hat. Increases Intelligence by <%= int %>. Limited Edition Winter 2024-2025 Gear.",
"headSpecialWinter2025MageText": "Aurora Hat",
"headSpecialWinter2025MageNotes": "More than just a fancy fascinator, this hat makes you look like the aurora borealis itself. Increases Perception by <%= per %>. Limited Edition Winter 2024-2025 Gear.",
"headSpecialGaymerxText": "Rainbow Warrior Helm",
"headSpecialGaymerxNotes": "In celebration of the GaymerX Conference, this special helmet is decorated with a radiant, colorful rainbow pattern! GaymerX is a game convention celebrating LGTBQ and gaming and is open to everyone.",
@@ -2334,6 +2368,10 @@
"headMystery202409Notes": "More than just jaunty decorations, the enchanted sunflowers on this hat fill the wearer with powerful magic energy. Confers no benefit. September 2024 Subscriber Item.",
"headMystery202411Text": "Bristled Helm",
"headMystery202411Notes": "This helm is quite intimidating to your tasks when you dive in headfirst! Confers no benefit. November 2024 Subscriber Item.",
"headMystery202412Text": "Candy Cane Cottontail Hood",
"headMystery202412Notes": "Warm and cozy, just like a cup of minty hot cocoa on a winter night! Confers no benefit. December 2024 Subscriber Item.",
"headMystery202501Text": "Frostbinders Hat",
"headMystery202501Notes": "This sparkling hat generates a light and festive flurry around you at all times. Confers no benefit. January 2025 Subscriber Item.",
"headMystery301404Text": "Fancy Top Hat",
"headMystery301404Notes": "A fancy top hat for the finest of gentlefolk! January 3015 Subscriber Item. Confers no benefit.",
@@ -2538,6 +2576,10 @@
"headArmoireFunnyFoolCapNotes": "The bells on this hat might make your opponents burst into giggles, but they just help you concentrate. Increases Constitution by <%= con %>. Enchanted Armoire: Funny Fool Set (Item 1 of 3)",
"headArmoireStormKnightHelmText": "Storm Knight Helm",
"headArmoireStormKnightHelmNotes": "Harness lightning through these antlers as you storm the castle. Increases Constitution by <%= con %>. Enchanted Armoire: Storm Knight Set (Item 1 of 3)",
"headArmoireFestiveHelperHatText": "Festive Helper Hat",
"headArmoireFestiveHelperHatNotes": "Holiday tip #27: have a helper hat handy. This one is big enough to keep an emergency toy underneath! Increases Intelligence by <%= int %>. Enchanted Armoire: Festive Helper Set (Item 1 of 2)",
"headArmoireSnowyTrapperHatText": "Snowy Trapper Hat",
"headArmoireSnowyTrapperHatNotes": "Blue, frostbitten ears will be a thing of the past. Embrace cozy warmth in style! Increases Constitution and Perception by <%= attrs %> each. Enchanted Armoire: Snowy Trapper Hat Set (Item 1 of 2).",
"offhand": "off-hand item",
"offHandCapitalized": "Off-Hand Item",
@@ -2826,6 +2868,11 @@
"shieldSpecialFall2024HealerText": "Space Shield",
"shieldSpecialFall2024HealerNotes": "New tasks wanting your attention bounce right off until youve completed your current mission. Increases Constitution by <%= con %>. Limited Edition Fall 2024 Gear.",
"shieldSpecialWinter2025WarriorText": "Moose Warrior Shield",
"shieldSpecialWinter2025WarriorNotes": "Block out any unwanted distractions with this shield as strong as a moose. Increases Constitution by <%= con %>. Limited Edition Winter 2024-2025 Gear.",
"shieldSpecialWinter2025HealerText": "The Perfect Gift",
"shieldSpecialWinter2025HealerNotes": "The perfect gift is just waiting to be opened. What could be inside? Increases Constitution by <%= con %>. Limited Edition Winter 2024-2025 Gear.",
"shieldMystery201601Text": "Resolution Slayer",
"shieldMystery201601Notes": "This blade can be used to parry away all distractions. Confers no benefit. January 2016 Subscriber Item.",
"shieldMystery201701Text": "Time-Freezer Shield",
@@ -2846,6 +2893,8 @@
"shieldMystery202408Notes": "Magic lights will illuminate the inside of your bubble hideout, or anywhere else you need a little light! Confers no benefit. August 2024 Subscriber Item.",
"shieldMystery202409Text": "Heliotrope Magus Staff",
"shieldMystery202409Notes": "The glowing ruby on this staff draws its power from the late summer sun. Confers no benefit. September 2024 Subscriber Item.",
"shieldMystery202501Text": "Frostbinder's Staff",
"shieldMystery202501Notes": "Decorate any outdoor scenery with a diamond coat of shimmering frost. Confers no benefit. January 2025 Subscriber Item.",
"shieldMystery301405Text": "Clock Shield",
"shieldMystery301405Notes": "Time is on your side with this towering clock shield! Confers no benefit. June 3015 Subscriber Item.",
+6 -3
View File
@@ -30,7 +30,7 @@
"user": "User",
"market": "Market",
"newSubscriberItem": "You have new <span class=\"notification-bold-blue\">Mystery Items</span>",
"subscriberItemText": "Each month, subscribers will receive a mystery item. It becomes available at the beginning of the month. See the wiki's 'Mystery Item' page for more information.",
"subscriberItemText": "Subscribers receive a new mystery gear set at the beginning of each month!",
"all": "All",
"none": "None",
"more": "<%= count %> more",
@@ -207,7 +207,8 @@
"dismissAll": "Dismiss All",
"messages": "Messages",
"emptyMessagesLine1": "You don't have any messages",
"emptyMessagesLine2": "You can send a new message to a user by visiting their profile and clicking the \"Message\" button.",
"emptyMessagesLine2": "Send a message to start a conversation with your Party members or another Habitica player",
"newMessage": "New Message",
"userSentMessage": "<span class=\"notification-bold\"><%- user %></span> sent you a message",
"letsgo": "Let's Go!",
"selected": "Selected",
@@ -238,5 +239,7 @@
"submitQuestion": "Submit Question",
"whyReportingPlayer": "Why are you reporting this player?",
"whyReportingPlayerPlaceholder": "Reason for report",
"playerReportModalBody": "You should only report a player who violates the <%= firstLinkStart %>Community Guidelines<%= linkEnd %> and/or <%= secondLinkStart %>Terms of Service<%= linkEnd %>. Submitting a false report is a violation of Habiticas Community Guidelines."
"playerReportModalBody": "You should only report a player who violates the <%= firstLinkStart %>Community Guidelines<%= linkEnd %> and/or <%= secondLinkStart %>Terms of Service<%= linkEnd %>. Submitting a false report is a violation of Habiticas Community Guidelines.",
"targetUserNotExist": "Target User: '<%= userName %>' does not exist.",
"rememberToBeKind": "Please remember to be kind, respectful, and follow the <a href='/static/community-guidelines' target='_blank'>Community Guidelines</a>."
}
+2 -4
View File
@@ -114,9 +114,7 @@
"whyReportingPostPlaceholder": "Reason for report",
"optional": "Optional",
"needsTextPlaceholder": "Type your message here.",
"copyMessageAsToDo": "Copy message as To Do",
"copyAsTodo": "Copy as To Do",
"messageAddedAsToDo": "Message copied as To Do.",
"messageCopiedToClipboard": "Message copied to clipboard.",
"leaderOnlyChallenges": "Only group leader can create challenges",
"sendGift": "Send a Gift",
"selectGift": "Select Gift",
@@ -288,7 +286,7 @@
"guildSummaryPlaceholder": "Write a short explanation of your Group. What is the main purpose of the Group and what will its members do?",
"groupDescription": "Description",
"guildDescriptionPlaceholder": "Use this section to go into more detail about everything that members should know about your Group. Useful tips, helpful links, and encouraging statements all go here!",
"markdownFormattingHelp": "[Markdown formatting help](https://habitica.fandom.com/wiki/Markdown_Cheat_Sheet)",
"markdownFormattingHelp": "[Markdown formatting help](https://github.com/HabitRPG/habitica/wiki/Markdown-in-Habitica)",
"partyDescriptionPlaceholder": "This is our Party's description. It describes what we do in this Party. If you want to learn more about what we do in this Party, read the description. Party on.",
"guildGemCostInfo": "A Gem cost promotes high quality Guilds and is transferred into your Guild's bank.",
"noGuildsTitle": "You aren't a member of any Guilds.",
+4
View File
@@ -223,6 +223,10 @@
"fall2024UnderworldSorcerorMageSet": "Underworld Sorceror Set (Mage)",
"fall2024SpaceInvaderHealerSet": "Space Invader Set (Healer)",
"fall2024BlackCatRogueSet": "Black Cat Set (Rogue)",
"winter2025MooseWarriorSet": "Moose Warrior Set",
"winter2025AuroraMageSet": "Aurora Mage Set",
"winter2025StringLightsHealerSet": "String Lights Healer Set",
"winter2025SnowRogueSet": "Snow Rogue Set",
"winterPromoGiftHeader": "GIFT A SUBSCRIPTION, GET ONE FREE!",
"winterPromoGiftDetails1": "Until January 6th only, when you gift somebody a subscription, you get the same subscription for yourself for free!",
"winterPromoGiftDetails2": "Please note that if you or your gift recipient already have a recurring subscription, the gifted subscription will only start after that subscription is cancelled or has expired. Thanks so much for your support! <3",
-2
View File
@@ -51,8 +51,6 @@
"messageNotAbleToBuyInBulk": "This item cannot be purchased in quantities above 1.",
"notificationsRequired": "Notification ids are required.",
"unallocatedStatsPoints": "You have <span class=\"notification-bold-blue\"><%= points %> unallocated Stat Points</span>",
"beginningOfConversation": "This is the beginning of your conversation with <%= userName %>.",
"beginningOfConversationReminder": "Remember to be kind, respectful, and follow the Community Guidelines!",
"messageDeletedUser": "Sorry, this user has deleted their account.",
"messageMissingDisplayName": "Missing display name.",
"reportedMessage": "You have reported this message to moderators.",
+1
View File
@@ -96,6 +96,7 @@
"paymentYouReceived": "You received:",
"paymentYouSentGems": "You sent <strong><%- name %></strong>:",
"paymentYouSentSubscription": "You sent <strong><%- name %></strong><br> a <%= months %> month(s) Habitica subscription.",
"paymentYouSentSubscriptionG1G1": "You sent <strong><%- name %></strong><br> a <%= months %> month(s) Habitica subscription, and the same subscription was applied to your account for our Gift One Get One promotion!",
"paymentSubBilling": "Your subscription will be billed <strong>$<%= amount %></strong> every <strong><%= months %> months</strong>.",
"groupsPaymentSubBilling": "Your next billing date is <strong><%= renewalDate %></strong>.",
"paymentSubBillingWithMethod": "Your subscription will be billed<br><strong>$<%= amount %>.00 USD</strong> every <strong><%= months %> months</strong> via <strong><%= paymentMethod %></strong>",

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