Habitica Stats on your Account Profile
-
Habitica Stats
This mod allows you to see the stats (hp, exp, mana) of your habitica profile by clicking on your profile icon!
What is Habitica ?
Habitica is a tasks-management-like app, with RPG elements built into it to help the user stay motivated ( eg: gaining exp when completing tasks you planned, loosing hp when you "fail" tasks / daily objectives and stuff like that)
What does the mod do ?
This mod allows you to see your profile/character stats inside Vivaldi itself, by clicking on the account profile button.
It shows your character's class ( text and icon!), your level and pretty bars for hp, exp and mana.
To make this work with your account, you will need to know your user id and your account's api key (available on the apps' settings). You can add these values on the JS code, in the "init" function.
Since this mod needs to invoke habitica's api to get the data, I made it so it only calls it every T minutes (configurable, look for 'dataLifetimeInSecs'). When you click the account button, it uses the data already retrieved.Mod JS and CSS
class Habitica { #baseUrl = 'https://habitica.com/api/v3/'; #client = 'habitica_vivaldi' #dataLifetimeInSecs = 60 * 5; #dataFetchInterval = null; constructor(user, key) { this.user = user; this.key = key; //Get once now this.#getStats(); //Keep getting every T this.#dataFetchInterval = setInterval( () => this.#getStats(), this.#dataLifetimeInSecs*1000 ); } buildDisplay() { let statContainer = document.createElement('div'); statContainer.innerHTML = this.#buildStatDisplay(); return statContainer; } async #getStats() { let statsResponse = await fetch( `${this.#baseUrl}user`, { method: 'GET', headers:{ "Content-Type": "application/json", "x-api-user" : this.user, "x-api-key" : this.key, "x-client" : this.#client } } ); if (!statsResponse.ok){ console.log('[Habitica] Error getting user stats. Will try again next time'); this.class = ''; this.stats = this.#buildStats(); return; } let statsResult = await statsResponse.json(); this.class = statsResult.data.stats.class; this.stats = this.#buildStats( statsResult.data.stats.lvl, statsResult.data.stats.hp, statsResult.data.stats.mp, statsResult.data.stats.exp, statsResult.data.stats.maxHealth, statsResult.data.stats.maxMP, statsResult.data.stats.toNextLevel, ); return this.stats; } #buildStats(lvl = 1, hp = 1, mp = 1, exp = 0, maxHp = 1, maxMp = 1, maxExp = 1) { return { lvl : lvl, hp : hp, mp : mp, exp: exp, maxhp : maxHp, maxmp : maxMp, maxexp: maxExp }; } #buildStatDisplay() { return ` <div class="class-display"> ${this.#buildClassIcon()} ${this.#buildClassLabel()} </div> <div class="stats-display"> ${this.#buildStatItem(this.stats.hp, this.stats.maxhp, 'bg-health')} ${this.#buildStatItem(this.stats.exp, this.stats.maxexp, 'bg-experience')} ${this.#buildStatItem(this.stats.mp, this.stats.maxmp, 'bg-mana')} </div> `; } #buildClassIcon(){ return `<div class="bg-class bg-${this.class}"></div>`; } #buildClassLabel() { return ` <div class="stat-label"> <span>${this.class}</span> <span>•</span> <span class="right">Level ${this.stats.lvl}</span> </div> `; } #buildStatItem(current, max, colorClass) { return` <div class="stat-item" data-current="${current}" data-max="${max}"> <div class="progress-bar"> <div class="progress ${colorClass}" style="width: ${current / max * 100}%"></div> </div> </div> `; } } function init() { const userId = '<habitica-user-id-here>'; const apiKey = '<habitica-user-api-key-here>'; var accountButton = document.querySelector('button[name="AccountButton"]'); if (accountButton == null) return; //Only init habitica if there's a place to put stuff into var myHabitica = new Habitica(userId, apiKey); var appenderId = null; function appendStatsToAccount(habitica) { var accountDialog = document.querySelector('div.account-dialog'); if (accountDialog == null) return; //Nowhere to append to let statsDisplay = habitica.buildDisplay(); let accountDialogHeader = accountDialog.querySelector('header'); accountDialog.insertBefore(statsDisplay, accountDialogHeader.nextSibling); } accountButton.addEventListener('click', () => { if (appenderId != null) { clearTimeout(appenderId); } appenderId = setTimeout(() => appendStatsToAccount(myHabitica), 300); }); } setTimeout(function loader(){ var brw = document.querySelector("#browser"); if (brw != null) { init(); } else { setTimeout(loader, 300); } }, 300);
.bg-health { background: #f74e52; } .bg-experience { background: #ffbe5d; } .bg-mana { background: #50b5e9; } .bg-warrior { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='48' height='48' viewBox='0 0 48 48'%3E%3Cdefs%3E%3Cpath id='a' d='M31.392 9.115l-6.791 7.124v6.314l6.791-6.791V9.115z'/%3E%3C/defs%3E%3Cg fill='none' fill-rule='evenodd' transform='translate(0 1)'%3E%3Cpath fill='%23F06166' d='M18.39 28.762l6.334 2.92c.526.243.868.732.999 1.297.219.948.883 3.156.937 4.33a.88.88 0 0 1-1.24.844l-10.588-5.07a1.781 1.781 0 0 1-.762-.763L9 21.733a.88.88 0 0 1 .844-1.24c1.173.054 3.335.683 4.33.937.56.142 1.054.472 1.296.998l2.92 6.334z'/%3E%3Cpath fill='%23C82B2B' d='M3.073 44.085l2.732 2.733 7.085-.557.364-4.656 4.069-4.067 7.401 3.522 5.536-1.49-2.322-9.99 15.514-14.477L46.422.741l-.007.002.003-.003V.734L32.057 3.702 17.58 19.218l-9.99-2.322L6.1 22.43l3.522 7.403L5.555 33.9l-4.654.367-.559 7.084 2.732 2.733z'/%3E%3Cpath fill='%23F06166' d='M8.927 41.769l-3.544-3.544 8.767-8.765 3.542 3.544z'/%3E%3Cpath fill='%23F06166' d='M3.377 40.231l.255-3.235 3.236-.255 3.544 3.546-.255 3.233-3.234.258z'/%3E%3Cpath fill='%23FFB6B8' d='M33.935 6.526l.3 6.391 8.108-8.108c-.15-.14-6.26.565-8.408 1.717'/%3E%3Cpath fill='%23F27B86' d='M33.787 6.602L16.66 24.568l4.39 1.538 13.186-13.189-.3-6.392c-.048.027-.148.077-.148.077'/%3E%3Cpath fill='%23F27B86' d='M16.66 24.567l-.148.164 1.864 4.045 2.67-2.67-4.386-1.539zM40.624 13.22l-6.392-.3 8.109-8.108c.14.15-.565 6.259-1.717 8.408'/%3E%3Cpath fill='%23E5414D' d='M40.548 13.368L22.582 30.496l-1.538-4.39L34.233 12.92l6.391.3a5.032 5.032 0 0 0-.076.148'/%3E%3Cpath fill='%23E5414D' d='M22.582 30.495l-.163.148-4.045-1.864 2.67-2.67 1.538 4.386z'/%3E%3Cpath fill='%23FFB6B8' d='M6.867 36.742l-.75 2.742-2.486-2.487zM10.406 40.28l-2.742.75 2.486 2.486z'/%3E%3Cpath fill='%23FFB6B8' d='M6.867 36.742l3.546 3.546-2.748.741-1.547-1.545z'/%3E%3Cpath fill='%23F27B86' d='M3.382 40.237l2.742-.75-2.486-2.486zM6.921 43.776l.75-2.742 2.486 2.486z'/%3E%3Cpath fill='%23F27B86' d='M3.382 40.237l3.547 3.546.74-2.748-1.545-1.547z'/%3E%3Cpath fill='%23E5414D' d='M14.701 36.01l-3.552-3.553 2.143-2.14 3.552 3.55z'/%3E%3Cpath fill='%23F06166' d='M12.56 38.151L9.008 34.6l2.142-2.14 3.552 3.55z'/%3E%3Cpath fill='%23E5414D' d='M10.418 40.293L6.866 36.74l2.142-2.14 3.552 3.55z'/%3E%3Cpath fill='%23FFB6B8' d='M18.395 28.764l-2.92-6.334a1.629 1.629 0 0 0-.46-.576 2.12 2.12 0 0 0-.836-.422c-.995-.254-3.157-.883-4.33-.937a.871.871 0 0 0-.727.336l4.258 3.634 3.13 6.192 1.89-1.89-.005-.003z'/%3E%3Cpath fill='%23F06166' d='M13.38 24.466L9.12 20.83a.871.871 0 0 0-.117.904l5.07 10.587c.085.165.197.313.327.444l2.109-2.108-3.13-6.192z'/%3E%3Cpath fill='%23F27B86' d='M26.674 37.312c-.054-1.173-.684-3.337-.937-4.33a2.12 2.12 0 0 0-.423-.836 1.629 1.629 0 0 0-.576-.46l-6.334-2.92-.002-.005-1.891 1.891 6.192 3.13 3.635 4.258a.874.874 0 0 0 .336-.728'/%3E%3Cpath fill='%23E5414D' d='M22.703 33.781l3.634 4.259a.871.871 0 0 1-.904.117l-10.587-5.07a1.766 1.766 0 0 1-.444-.327l2.109-2.108 6.192 3.13z'/%3E%3Cmask id='b' fill='%23fff'%3E%3Cuse xlink:href='%23a'/%3E%3C/mask%3E%3Cpath fill='%23FFB6B8' d='M29.472 23.28h.987V5.828h-.987zM24.601 27.692h2.92V10.24h-2.92z' mask='url(%23b)'/%3E%3C/g%3E%3C/svg%3E"); } .bg-wizard { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 0 48 48'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cpath fill='%231F6EA2' d='M24.462 1.151c-3.695 3.714-7.321 14.62-9.236 20.913-.84-1.062-1.799-2.076-3.158-3.326-4.806 3.514-7.357 7.25-10.646 11.816 8.916 7.926 11.233 9.256 22.995 16.005l.045-.025h.001l.045.025c11.76-6.749 14.079-8.08 22.994-16.005-3.287-4.566-5.841-8.302-10.645-11.816-1.361 1.25-2.317 2.264-3.158 3.326-1.915-6.294-5.543-17.2-9.236-20.913h-.001z'/%3E%3Cpath fill='%23278ABF' d='M24.464 32.108l3.561-1.265c6.075-.605 8.425-2.281 9.426-3.498l6.053 2.707.002.013a.45.45 0 0 1-.105.286 4.97 4.97 0 0 1-.32.33c-3.405 3.315-18.237 11.981-18.617 12.202V32.108z'/%3E%3Cpath fill='%2353B4E5' d='M36.406 23.041c.23-.188.292-.34.674-.336 1.183.067 5.169 5.175 6.064 6.461.194.278.366.61.36.885l-6.053-2.707c.236-.367.19-.92-.355-1.252-.818-.501-2.529.949-2.959.284-.599-.927 2.04-3.147 2.27-3.335'/%3E%3Cpath fill='%232AA0CF' d='M23.591 7.487c-5.39 15.419-8.227 23.817-8.227 23.817l9.097 4.76V6.839c-.36 0-.718.216-.87.648'/%3E%3Cpath fill='%23278ABF' d='M25.332 7.487c-.152-.432-.51-.648-.87-.648v29.225l9.097-4.76s-2.837-8.398-8.227-23.817'/%3E%3Cpath fill='%234DB2D6' d='M24.462 32.108L20.9 30.843c-6.075-.605-8.342-2.352-9.425-3.498L5.42 30.052l-.002.013a.45.45 0 0 0 .106.286c.09.104.197.215.318.33 3.406 3.315 18.238 11.981 18.619 12.202V32.108z'/%3E%3Cpath fill='%236BC4E9' d='M12.519 23.041c-.23-.188-.292-.34-.674-.336-1.183.067-5.169 5.175-6.063 6.461-.194.278-.367.61-.361.885l6.053-2.707c-.236-.367-.19-.92.356-1.252.817-.501 2.528.949 2.958.284.6-.927-2.039-3.147-2.27-3.335'/%3E%3Cpath fill='%23A9DBF6' d='M24.463 34.998v-5.101l-7.21-4.13-1.48 4.049z'/%3E%3Cpath fill='%2384CFF2' d='M24.463 34.998v-5.101l7.207-4.13 1.483 4.049z'/%3E%3C/g%3E%3C/svg%3E"); } .bg-healer { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 0 48 48'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cpath fill='%23CF8229' d='M24.61 47.604s-1.789-.735-2.585-1.138l-.183-.09c-5.13-2.58-10.54-5.782-13.881-12.108-3.777-7.15-3.05-18.565-2.955-19.843.075-1.003.378-3.464.378-3.464s1.941-.858 2.901-1.311l13.864-7.012c.764-.363 2.462-1.114 2.462-1.114s1.697.75 2.463 1.114l13.86 7.01c.966.457 3.05 1.315 3.05 1.315s.157 2.467.232 3.465c.094 1.275.822 12.69-2.955 19.84-3.343 6.33-8.755 9.53-13.876 12.103l-.19.096c-.795.402-2.584 1.137-2.584 1.137'/%3E%3Cpath fill='%23E29E45' d='M12.694 16.147l11.059-5.695c.27-.129.564-.192.858-.192V5.829c-.294 0-.588.063-.858.192L9.888 13.032a1.985 1.985 0 0 0-.727.603l3.533 2.523v-.011M24.612 10.259V5.827z'/%3E%3Cpath fill='%23FDC67E' d='M23.752 6.008L9.89 13.02c-.655.31-1.09.945-1.145 1.665-.034.466-.81 11.487 2.531 17.814 2.782 5.266 7.36 8.048 12.242 10.504l.19.096c.284.142.593.213.902.213V5.816c-.293 0-.585.064-.858.192'/%3E%3Cpath fill='%23FFA623' d='M25.512 43.099l.19-.096c4.885-2.454 9.462-5.238 12.244-10.505 3.341-6.326 2.565-17.347 2.53-17.813a2.009 2.009 0 0 0-1.143-1.665L25.468 6.008a1.999 1.999 0 0 0-.858-.192v37.496c.31 0 .618-.071.902-.213'/%3E%3Cpath fill='%23FFDDB5' d='M12.694 16.134l11.059-5.694c.27-.129.564-.192.858-.192V5.816c-.294 0-.587.064-.858.192L9.889 13.02a1.985 1.985 0 0 0-.728.603l3.533 2.523v-.012'/%3E%3Cpath fill='%23FDC67E' d='M39.333 13.02L25.468 6.008a1.999 1.999 0 0 0-.858-.192v4.431c.294 0 .588.065.858.192l11.065 5.702 3.527-2.519a1.973 1.973 0 0 0-.727-.602'/%3E%3Cpath fill='%23FFA623' d='M24.214 38.858c-4.197-2.128-7.383-4.438-9.389-8.235-2.239-4.238-2.229-11.63-2.131-14.477L9.16 13.623a2 2 0 0 0-.417 1.062c-.015.207-.174 2.498-.057 5.531.148 3.798.731 8.765 2.59 12.282 2.782 5.267 7.357 8.05 12.242 10.505l.19.096c.284.142.593.213.902.213v-4.33c-.098 0-.197-.04-.397-.124'/%3E%3Cpath fill='%23E59025' d='M34.395 30.623c-2.008 3.804-5.203 6.113-9.406 8.243-.188.078-.282.117-.378.117v4.33c.31 0 .618-.072.9-.214l.19-.096c4.885-2.455 9.462-5.238 12.244-10.504 1.857-3.518 2.443-8.485 2.59-12.282.118-3.034-.044-5.325-.06-5.532a1.995 1.995 0 0 0-.414-1.064l-3.527 2.521c.129 3.53-.07 10.566-2.139 14.481'/%3E%3Cpath fill='%23FFE4C9' d='M16.076 24.564l5.69-2.845 2.845 2.845zM24.61 33.098l-2.845-5.688 2.846-2.846z'/%3E%3Cpath fill='%23E59025' d='M33.145 24.564l-5.689 2.846-2.845-2.846zM24.61 16.03l2.846 5.689-2.845 2.845z'/%3E%3Cpath fill='%23E59025' d='M33.145 24.564l-5.689-2.845-2.845 2.845zM24.61 33.098l2.846-5.688-2.845-2.846z'/%3E%3Cpath fill='%23FFE4C9' d='M16.076 24.564l5.69 2.846 2.845-2.846zM24.61 16.03l-2.845 5.689 2.846 2.845z'/%3E%3C/g%3E%3C/svg%3E"); } .bg-rogue { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 0 48 48'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cpath fill='%234F2A93' d='M6.492 35.154l7.358-7.359c1.05-4.274 2.135-8.752 2.22-9.226.072-.495.235-1.597 1.132-2.653.453-.53 1.008-.966 1.707-1.35L39.353 3.301l6.69-1.557-1.494 6.599-11.334 20.542c-.359.655-.768 1.185-1.248 1.615l-.083.073c-1.065.906-2.133 1.064-2.707 1.15-.447.081-5.02 1.19-9.185 2.212l-7.36 7.36.868 4.688-9.87-1.826-1.828-9.871 4.69.868z'/%3E%3Cpath fill='%234F2A93' d='M36.05 41.079l-7.358-7.359c-4.274-1.05-8.753-2.135-9.226-2.22-.495-.071-1.597-.234-2.653-1.13-.53-.454-.966-1.01-1.35-1.708L4.197 8.218 2.641 1.527 9.24 3.021 29.78 14.355c.656.36 1.186.768 1.616 1.248l.073.084c.906 1.064 1.064 2.133 1.15 2.707.081.446 1.19 5.019 2.212 9.184l7.36 7.361 4.688-.868-1.826 9.87-9.871 1.827.868-4.689z'/%3E%3Cpath fill='%23C6B6E4' d='M18.141 27.193c.22.399.432.664.647.848l7.643-2.722L6.48 5.368c-.164.188.048.728.39 1.377'/%3E%3Cpath fill='%238966C7' d='M18.792 28.043c.39.332.78.386 1.181.447.622.091 10.277 2.468 10.277 2.468l.91-.91-4.73-4.728-7.638 2.723z'/%3E%3Cpath fill='%237A54C0' d='M28.306 17.029c.398.219.663.432.847.647l-2.721 7.642L6.482 5.37c.184-.163.714.036 1.353.363'/%3E%3Cpath fill='%236133B4' d='M29.155 17.68c.332.39.386.78.447 1.181.092.622 2.469 10.276 2.469 10.276l-.91.91-4.73-4.729 2.724-7.638z'/%3E%3Cpath fill='%238966C7' d='M35.402 36.111l-1.494-1.494.467-3.177 1.494 1.495zM38.39 39.1l-1.494-1.495.468-3.176 1.494 1.494zM32.07 29.137l.81.81-.467 3.174-2.164-2.162'/%3E%3Cpath fill='%236133B4' d='M33.908 34.617l-1.495-1.495.468-3.176 1.494 1.494zM36.896 37.605l-1.494-1.494.468-3.176 1.494 1.494zM39.885 40.594L38.39 39.1l.467-3.177 2.849 2.849z'/%3E%3Cpath fill='%23C6B6E4' d='M30.25 30.959l.162-1.657 1.66-.165-.165 1.659zM39.632 38.52l-.637 3.436 2.037-2.037zM43.069 37.882l-3.437.637 1.4 1.4zM41.032 39.92l-2.037 2.036 3.437-.636zM42.432 41.32l.637-3.437-2.037 2.037z'/%3E%3C/g%3E%3C/svg%3E"); } .bg-class { background-size: 24px; height: 24px; width: 24px; } .class-display{ padding: 4px 2px 4px 6px; display: inline-flex; align-items: center; gap: 6px; } .stats-display{ padding: 4px 2px 4px 6px; } .progress-bar{ background: #f9f9f9; width: 80%; margin: 6px 0; } .progress-bar, .progress-bar .progress{ border-radius: var(--radiusRound); height: 12px; display: inline-flex; } .stat-item::after{ content: attr(data-current) ' / ' attr(data-max); margin-left: 2px; font-size: 10px; } .stat-label{ font-weight: bold; text-transform: capitalize; }
Hope you like it!