@sjtdev/koishi-plugin-dota2tracker 2.5.5 → 2.5.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/changelog.md +16 -0
- package/lib/index.js +16 -109
- package/lib/queries/MatchInfo.graphql +0 -3
- package/lib/templates/hero/hero_1.ejs +4 -16
- package/lib/templates/images/lane_fail.svg +2 -1
- package/lib/templates/images/lane_jungle.svg +2 -1
- package/lib/templates/images/lane_stomp.svg +2 -1
- package/lib/templates/images/lane_stomped.svg +2 -1
- package/lib/templates/images/lane_tie.svg +2 -1
- package/lib/templates/images/lane_victory.svg +2 -1
- package/lib/templates/match/match_1/main.ejs +1 -1
- package/lib/templates/match/match_1/player.ejs +1 -1
- package/lib/templates/match/match_1/style.css +1 -1
- package/lib/templates/match/match_1.ejs +2 -11
- package/lib/templates/match/match_2/original.css +1 -1
- package/lib/templates/match/match_2/original.ejs +1 -1
- package/lib/templates/player/player_1.ejs +1 -1
- package/package.json +1 -1
- package/lib/queries/Constants.graphql +0 -16
package/changelog.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# 更新日志
|
|
2
2
|
|
|
3
|
+
### [2.5.7](https://github.com/sjtdev/koishi-plugin-dota2tracker/compare/v2.5.6...v2.5.7) (2026-03-25)
|
|
4
|
+
|
|
5
|
+
### 🚀 功能优化
|
|
6
|
+
|
|
7
|
+
* 跟进`DOTA2 7.41`移除命石系统更新,全面清理`facet`相关代码以优化性能与减小存储占用 ([5842fd0](https://github.com/sjtdev/koishi-plugin-dota2tracker/commit/5842fd0d9925c361b0bccf8c0db9ab861cc4c47d))
|
|
8
|
+
|
|
9
|
+
### 🐛 Bug 修复
|
|
10
|
+
|
|
11
|
+
* **template:** 修复因`2.4.0`重写ejs读取图片逻辑导致`match_1` `player_1`模板中对线结果图片显示错误的问题 ([d619b10](https://github.com/sjtdev/koishi-plugin-dota2tracker/commit/d619b10abd15a22eae052c725070b0db976ca097))
|
|
12
|
+
|
|
13
|
+
### [2.5.6](https://github.com/sjtdev/koishi-plugin-dota2tracker/compare/v2.5.5...v2.5.6) (2026-03-12)
|
|
14
|
+
|
|
15
|
+
### 🐛 Bug 修复
|
|
16
|
+
|
|
17
|
+
* **daily:** 修复了对于"LVP(头号战犯)"卡片判定的逻辑错误 ([1797209](https://github.com/sjtdev/koishi-plugin-dota2tracker/commit/17972098102dc0479dd9d3a9a3d33b041919cf1b))
|
|
18
|
+
|
|
3
19
|
### [2.5.5](https://github.com/sjtdev/koishi-plugin-dota2tracker/compare/v2.5.4...v2.5.5) (2026-03-08)
|
|
4
20
|
|
|
5
21
|
### 🐛 Bug 修复
|
package/lib/index.js
CHANGED
|
@@ -1144,55 +1144,8 @@ var HeroService = class _HeroService extends import_koishi2.Service {
|
|
|
1144
1144
|
}
|
|
1145
1145
|
static formatHeroDetails(rawHero) {
|
|
1146
1146
|
let hero = Object.assign({}, rawHero);
|
|
1147
|
-
hero.facet_abilities.forEach((fa, i) => {
|
|
1148
|
-
if (fa.abilities.length) {
|
|
1149
|
-
fa.abilities.forEach((ab) => {
|
|
1150
|
-
if (!hero.facets[i].abilities) hero.facets[i].abilities = [];
|
|
1151
|
-
if (hero.facets[i].description_loc !== ab.desc_loc)
|
|
1152
|
-
hero.facets[i].abilities.push({
|
|
1153
|
-
id: ab.id,
|
|
1154
|
-
name: ab.name,
|
|
1155
|
-
name_loc: ab.name_loc,
|
|
1156
|
-
description_ability_loc: this.formatHeroDesc(ab.desc_loc, ab.special_values, "facet" /* Facet */)
|
|
1157
|
-
});
|
|
1158
|
-
else hero.facets[i].description_loc = this.formatHeroDesc(hero.facets[i].description_loc, ab.special_values, "facet" /* Facet */);
|
|
1159
|
-
ab.ability_is_facet = true;
|
|
1160
|
-
ab.facet = hero.facets[i];
|
|
1161
|
-
hero.abilities.push(ab);
|
|
1162
|
-
});
|
|
1163
|
-
}
|
|
1164
|
-
});
|
|
1165
|
-
const all_special_values = [...hero.abilities.flatMap((ab) => ab.special_values), ...hero.facet_abilities.flatMap((fas) => fas.abilities.flatMap((fa) => fa.special_values))];
|
|
1166
1147
|
hero.abilities.forEach((ab) => {
|
|
1167
|
-
ab.
|
|
1168
|
-
i = i + (hero.facets.length - ab.facets_loc.length);
|
|
1169
|
-
if (i < 0) return;
|
|
1170
|
-
if (facet) {
|
|
1171
|
-
if (!hero.facets[i].abilities) hero.facets[i].abilities = [];
|
|
1172
|
-
hero.facets[i].abilities.push({
|
|
1173
|
-
id: ab.id,
|
|
1174
|
-
name: ab.name,
|
|
1175
|
-
name_loc: ab.name_loc,
|
|
1176
|
-
description_ability_loc: this.formatHeroDesc(facet, ab.special_values, "facet" /* Facet */),
|
|
1177
|
-
attributes: []
|
|
1178
|
-
});
|
|
1179
|
-
}
|
|
1180
|
-
});
|
|
1181
|
-
hero.facets.forEach((facet) => {
|
|
1182
|
-
const svs = ab.special_values.filter((sv) => sv.facet_bonus.name === facet.name);
|
|
1183
|
-
svs.forEach((sv) => {
|
|
1184
|
-
if (sv.heading_loc) {
|
|
1185
|
-
if (!facet.abilities) facet.abilities = [];
|
|
1186
|
-
facet.abilities.find((ability) => ab.id == ability.id)?.attributes.push({
|
|
1187
|
-
heading_loc: sv.heading_loc,
|
|
1188
|
-
values: [...sv.facet_bonus.values],
|
|
1189
|
-
is_percentage: sv.is_percentage
|
|
1190
|
-
});
|
|
1191
|
-
}
|
|
1192
|
-
});
|
|
1193
|
-
facet.description_loc = this.formatHeroDesc(facet.description_loc, svs, "facet" /* Facet */);
|
|
1194
|
-
});
|
|
1195
|
-
ab.desc_loc = this.formatHeroDesc(ab.desc_loc, ab.special_values, ab.ability_is_facet ? "facet" /* Facet */ : void 0);
|
|
1148
|
+
ab.desc_loc = this.formatHeroDesc(ab.desc_loc, ab.special_values);
|
|
1196
1149
|
ab.notes_loc = ab.notes_loc.map((note) => this.formatHeroDesc(note, ab.special_values));
|
|
1197
1150
|
if (ab.ability_has_scepter) ab.scepter_loc = this.formatHeroDesc(ab.scepter_loc, ab.special_values, "scepter" /* Scepter */);
|
|
1198
1151
|
if (ab.ability_has_shard) ab.shard_loc = this.formatHeroDesc(ab.shard_loc, ab.special_values, "shard" /* Shard */);
|
|
@@ -1245,9 +1198,6 @@ var HeroService = class _HeroService extends import_koishi2.Service {
|
|
|
1245
1198
|
if (specialValue) {
|
|
1246
1199
|
let valuesToUse = "";
|
|
1247
1200
|
switch (type) {
|
|
1248
|
-
case "facet" /* Facet */:
|
|
1249
|
-
valuesToUse = specialValue.facet_bonus.name ? specialValue.facet_bonus.values.join(" / ") : specialValue.values_float.join(" / ");
|
|
1250
|
-
break;
|
|
1251
1201
|
case "scepter" /* Scepter */:
|
|
1252
1202
|
valuesToUse = specialValue.values_scepter.length ? specialValue.values_scepter.join(" / ") : specialValue.values_float.join(" / ");
|
|
1253
1203
|
break;
|
|
@@ -1610,49 +1560,12 @@ var MatchService = class _MatchService extends import_koishi4.Service {
|
|
|
1610
1560
|
}
|
|
1611
1561
|
}
|
|
1612
1562
|
async formatMatchData(matchQuery, languageTag) {
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
let needsRefetch = false;
|
|
1617
|
-
if (!constantsQuery) {
|
|
1618
|
-
needsRefetch = true;
|
|
1619
|
-
} else if (!isFromOpenDota) {
|
|
1620
|
-
if (!matchQuery.constants?.gameVersions?.[0]?.id || !constantsQuery.constants?.gameVersions?.[0]?.id || matchQuery.constants.gameVersions[0].id !== constantsQuery.constants.gameVersions[0].id) {
|
|
1621
|
-
needsRefetch = true;
|
|
1622
|
-
}
|
|
1623
|
-
}
|
|
1624
|
-
if (needsRefetch) {
|
|
1625
|
-
constantsQuery = await this.ctx.dota2tracker.stratzAPI.queryConstants(languageTag);
|
|
1626
|
-
}
|
|
1627
|
-
const facetData = await _MatchService.constantsInjectFacetData(constantsQuery, matchQuery, languageTag, this.ctx.dota2tracker.hero);
|
|
1628
|
-
this.ctx.dota2tracker.cache.setFacetConstantsCache(languageTag, constantsQuery);
|
|
1629
|
-
const match = _MatchService.extendMatchData(matchQuery, facetData, this.ctx.dota2tracker.dotaconstants);
|
|
1630
|
-
this.recordMatchExtension(match);
|
|
1631
|
-
return match;
|
|
1632
|
-
} catch (error) {
|
|
1633
|
-
this.ctx.dota2tracker.cache.deleteFacetConstantsCache(languageTag);
|
|
1634
|
-
throw error;
|
|
1635
|
-
}
|
|
1636
|
-
}
|
|
1637
|
-
static async constantsInjectFacetData(constantsQuery, matchQuery, languageTag, heroService) {
|
|
1638
|
-
const facetData = {};
|
|
1639
|
-
for (let player of matchQuery.match?.players) {
|
|
1640
|
-
if (player.variant != null) {
|
|
1641
|
-
const constantsFacet = constantsQuery.constants.facets.find((facet) => facet.id === player.hero.facets[player.variant - 1]?.facetId || facet.name === player.hero.facets[player.variant - 1]?.name);
|
|
1642
|
-
let displayName = constantsFacet?.language?.displayName;
|
|
1643
|
-
if (!displayName && heroService) {
|
|
1644
|
-
const valveFacet = (await heroService.getHeroDetails(player.hero.id, languageTag)).facets.find((facet) => facet.index === player.variant - 1);
|
|
1645
|
-
constantsFacet.language.displayName = valveFacet.title_loc;
|
|
1646
|
-
constantsFacet.name = valveFacet.name;
|
|
1647
|
-
constantsFacet.icon = valveFacet.icon;
|
|
1648
|
-
}
|
|
1649
|
-
facetData[player.steamAccountId] = { id: constantsFacet.id, name: constantsFacet.name, icon: constantsFacet.icon, color: constantsFacet.color, displayName: constantsFacet.language?.displayName };
|
|
1650
|
-
}
|
|
1651
|
-
}
|
|
1652
|
-
return facetData;
|
|
1563
|
+
const match = _MatchService.extendMatchData(matchQuery, this.ctx.dota2tracker.dotaconstants);
|
|
1564
|
+
this.recordMatchExtension(match);
|
|
1565
|
+
return match;
|
|
1653
1566
|
}
|
|
1654
1567
|
// 对比赛数据进行补充以供生成模板函数使用
|
|
1655
|
-
static extendMatchData(matchQuery,
|
|
1568
|
+
static extendMatchData(matchQuery, dotaconstants) {
|
|
1656
1569
|
const match = matchQuery.match;
|
|
1657
1570
|
const matchParsed = _MatchService.isMatchParsed(matchQuery);
|
|
1658
1571
|
["radiant", "dire"].forEach((team) => {
|
|
@@ -1819,7 +1732,6 @@ var MatchService = class _MatchService extends import_koishi4.Service {
|
|
|
1819
1732
|
}
|
|
1820
1733
|
}
|
|
1821
1734
|
player.formattedNetworth = formatNumber(player.networth);
|
|
1822
|
-
player.facet = facetData[player.steamAccountId];
|
|
1823
1735
|
player.titles = [];
|
|
1824
1736
|
player.mvpScore = // 计算MVP分数
|
|
1825
1737
|
player.kills * 5 + player.assists * 3 + (player.stats.heroDamageReport?.dealtTotal.stunDuration ?? 0) / 100 * 0.1 + (player.stats.heroDamageReport?.dealtTotal.disableDuration ?? 0) / 100 * 0.05 + (player.stats.heroDamageReport?.dealtTotal.slowDuration ?? 0) / 100 * 0.025 + player.heroDamage * 1e-3 + player.towerDamage * 0.01 + player.heroHealing * 2e-3 + player.imp * 0.25 + player.utilityScore * 5e-3;
|
|
@@ -2294,15 +2206,6 @@ var CacheService = class extends import_koishi6.Service {
|
|
|
2294
2206
|
}
|
|
2295
2207
|
return sendedIds;
|
|
2296
2208
|
}
|
|
2297
|
-
async getFacetConstantsCache(languageTag) {
|
|
2298
|
-
return this.ctx.cache.get("dt_facets_constants", languageTag);
|
|
2299
|
-
}
|
|
2300
|
-
setFacetConstantsCache(languageTag, constants) {
|
|
2301
|
-
this.ctx.cache.set("dt_facets_constants", languageTag, constants, DAYS_30);
|
|
2302
|
-
}
|
|
2303
|
-
deleteFacetConstantsCache(languageTag) {
|
|
2304
|
-
this.ctx.cache.delete("dt_facets_constants", languageTag);
|
|
2305
|
-
}
|
|
2306
2209
|
};
|
|
2307
2210
|
|
|
2308
2211
|
// src/app/data/database.ts
|
|
@@ -2564,9 +2467,6 @@ var StratzAPI = class extends import_koishi8.Service {
|
|
|
2564
2467
|
async queryPlayersLastMatchRankInfo({ steamAccountIds }) {
|
|
2565
2468
|
return this.query("PlayersLastmatchRankinfo", { steamAccountIds }, (data) => !!data?.players);
|
|
2566
2469
|
}
|
|
2567
|
-
async queryConstants(languageTag) {
|
|
2568
|
-
return this.query("Constants", { language: this.ctx.dota2tracker.i18n.getGraphqlLanguageTag(languageTag) }, (data) => !!data?.constants);
|
|
2569
|
-
}
|
|
2570
2470
|
async queryMatchInfo(matchId) {
|
|
2571
2471
|
return this.query("MatchInfo", { matchId }, (data) => !!data?.match);
|
|
2572
2472
|
}
|
|
@@ -2751,7 +2651,6 @@ var import_node_path2 = __toESM(require("node:path"));
|
|
|
2751
2651
|
// src/app/common/types.ts
|
|
2752
2652
|
var ImageType = /* @__PURE__ */ ((ImageType2) => {
|
|
2753
2653
|
ImageType2["Icons"] = "icons";
|
|
2754
|
-
ImageType2["IconsFacets"] = "icons/facets";
|
|
2755
2654
|
ImageType2["Heroes"] = "heroes";
|
|
2756
2655
|
ImageType2["HeroIcons"] = "heroes/icons";
|
|
2757
2656
|
ImageType2["HeroStats"] = "heroes/stats";
|
|
@@ -4239,8 +4138,7 @@ var OpenDotaAdapter = class extends import_koishi17.Service {
|
|
|
4239
4138
|
hero: {
|
|
4240
4139
|
id: _player.hero_id,
|
|
4241
4140
|
name: this.ctx.dota2tracker.dotaconstants.heroes[_player.hero_id].name,
|
|
4242
|
-
shortName: this.ctx.dota2tracker.dotaconstants.heroes[_player.hero_id].name.match(/^npc_dota_hero_(.+)$/)[1]
|
|
4243
|
-
facets: [...this.ctx.dota2tracker.dotaconstants.hero_abilities[this.ctx.dota2tracker.dotaconstants.heroes[_player.hero_id].name].facets.map((f) => ({ id: -1, name: f.name }))]
|
|
4141
|
+
shortName: this.ctx.dota2tracker.dotaconstants.heroes[_player.hero_id].name.match(/^npc_dota_hero_(.+)$/)[1]
|
|
4244
4142
|
},
|
|
4245
4143
|
dotaPlus: null,
|
|
4246
4144
|
stats: {
|
|
@@ -4710,7 +4608,16 @@ var DailyReportService = class _DailyReportService extends import_koishi18.Servi
|
|
|
4710
4608
|
this.calculateImpactPercentages(impactData);
|
|
4711
4609
|
playerStats.sort((a, b) => b.maxMvpScore - a.maxMvpScore || b.avgKda - a.avgKda);
|
|
4712
4610
|
const mvpStat = playerStats[0];
|
|
4713
|
-
const
|
|
4611
|
+
const getWorstMatchScore = /* @__PURE__ */ __name((stat) => {
|
|
4612
|
+
const ext = extensions.find((e) => Number(e.matchId) === stat.worstMatchId);
|
|
4613
|
+
const playerExt = ext?.data?.players?.find((p) => p.steamAccountId === stat.steamId);
|
|
4614
|
+
return playerExt?.mvpScore ?? 0;
|
|
4615
|
+
}, "getWorstMatchScore");
|
|
4616
|
+
const lvpStat = playerStats.reduce((worst, curr) => {
|
|
4617
|
+
const worstScore = getWorstMatchScore(worst);
|
|
4618
|
+
const currScore = getWorstMatchScore(curr);
|
|
4619
|
+
return currScore < worstScore || currScore === worstScore && curr.avgKda < worst.avgKda ? curr : worst;
|
|
4620
|
+
});
|
|
4714
4621
|
const mvpPlayerData = squadPlayerData.find((p) => p.steamAccount.id === mvpStat.steamId);
|
|
4715
4622
|
const lvpPlayerData = squadPlayerData.find((p) => p.steamAccount.id === lvpStat.steamId);
|
|
4716
4623
|
playerRows.sort((a, b) => parseFloat(b.kda.ratio) - parseFloat(a.kda.ratio));
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
const base_damage = Math.floor((hero.str_base+hero.agi_base+hero.int_base)*0.45);
|
|
3
3
|
hero.damage_max+=base_damage;
|
|
4
4
|
hero.damage_min+=base_damage;
|
|
5
|
-
} %> <% const primary_attrs = { "3": "hero_universal", "0": "hero_strength", "1": "hero_agility", "2": "hero_intelligence" }; %> <% const hero_dc = dotaconstants.heroes[hero.id]; %> <div class="wrapper"><div class="hero" id="<%= hero.id %>"><img src="<%= getImageUrl(hero["name"].match(/^npc_dota_hero_(.+)$/)[1], ImageType.Heroes) %>"/> <img class="pri_attr" src="<%= getImageUrl(primary_attrs[hero.primary_attr], ImageType.Icons) %>"/><div class="info"><p class="name"><%= hero.name_loc %></p><p class="roles"> <% hero.role_levels.forEach((item, index) => { %> <% if (item > 0) { %> <span class="role level<%= item %>"><%= $t("dota2tracker.template.roles."+index) %></span> <% } %> <% }); %> </p><p class="attrs"><span class="str"><%= hero.str_base %> <span class="gain">+<%= hero.str_gain.toFixed(1) %></span></span><span class="agi"><%= hero.agi_base %> <span class="gain">+<%= hero.agi_gain.toFixed(1) %></span></span><span class="int"><%= hero.int_base %> <span class="gain">+<%= hero.int_gain.toFixed(1) %></span></span></p></div></div><div class="hype"><p class="npe"><%= hero.npe_desc_loc %></p> <%- hero.hype_loc %> </div><div class="details"><div class="talents"><div class="talent"><div class="left"><%= hero.talents[7].name_loc %></div><div class="level">25</div><div class="right"><%= hero.talents[6].name_loc %></div></div><div class="talent"><div class="left"><%= hero.talents[5].name_loc %></div><div class="level">20</div><div class="right"><%= hero.talents[4].name_loc %></div></div><div class="talent"><div class="left"><%= hero.talents[3].name_loc %></div><div class="level">15</div><div class="right"><%= hero.talents[2].name_loc %></div></div><div class="talent"><div class="left"><%= hero.talents[1].name_loc %></div><div class="level">10</div><div class="right"><%= hero.talents[0].name_loc %></div></div></div><div class="list"><div class="bars"><div class="health"><span class="number"><%= hero.max_health %></span><span class="suffix">+<%= hero.health_regen.toFixed(1) %></span></div><div class="mana<%= !hero.max_mana ? ' zero' : '' %>"><span class="number"><%= hero.max_mana %></span><span class="suffix">+<%= hero.mana_regen.toFixed(1) %></span></div></div><div class="stats"><div class="column"><p><%= $t("dota2tracker.template.attack") %></p><div class="stat"><img src="<%= getImageUrl("icon_damage", ImageType.HeroStats) %>"/> <span><%= hero.damage_min %>~<%= hero.damage_max %></span></div><div class="stat"><img src="<%= getImageUrl("icon_attack_time", ImageType.HeroStats) %>"/> <span><%= hero.attack_rate.toFixed(1) %></span></div><div class="stat"><img src="<%= getImageUrl("icon_attack_range", ImageType.HeroStats) %>"/> <span><%= hero.attack_range %></span></div> <% if (hero_dc.attack_type !== "Melee") { %> <div class="stat"><img src="<%= getImageUrl("icon_projectile_speed", ImageType.HeroStats) %>"/> <span><%= hero.projectile_speed %></span></div> <% } %> </div><div class="column"><p><%= $t("dota2tracker.template.defense") %></p><div class="stat"><img src="<%= getImageUrl("icon_armor", ImageType.HeroStats) %>"/> <span><%= hero.armor.toFixed(1) %></span></div><div class="stat"><img src="<%= getImageUrl("icon_magic_resist", ImageType.HeroStats) %>"/> <span><%= hero.magic_resistance %>%</span></div></div><div class="column"><p><%= $t("dota2tracker.template.mobility") %></p><div class="stat"><img src="<%= getImageUrl("icon_movement_speed", ImageType.HeroStats) %>"/> <span><%= hero.movement_speed %></span></div><div class="stat"><img src="<%= getImageUrl("icon_turn_rate", ImageType.HeroStats) %>"/> <span><%= hero.turn_rate.toFixed(1) %></span></div><div class="stat"><img src="<%= getImageUrl("icon_vision", ImageType.HeroStats) %>"/> <span><%= hero.sight_range_day %> / <%= hero.sight_range_night %></span></div></div></div></div></div><div class="
|
|
5
|
+
} %> <% const primary_attrs = { "3": "hero_universal", "0": "hero_strength", "1": "hero_agility", "2": "hero_intelligence" }; %> <% const hero_dc = dotaconstants.heroes[hero.id]; %> <div class="wrapper"><div class="hero" id="<%= hero.id %>"><img src="<%= getImageUrl(hero["name"].match(/^npc_dota_hero_(.+)$/)[1], ImageType.Heroes) %>"/> <img class="pri_attr" src="<%= getImageUrl(primary_attrs[hero.primary_attr], ImageType.Icons) %>"/><div class="info"><p class="name"><%= hero.name_loc %></p><p class="roles"> <% hero.role_levels.forEach((item, index) => { %> <% if (item > 0) { %> <span class="role level<%= item %>"><%= $t("dota2tracker.template.roles."+index) %></span> <% } %> <% }); %> </p><p class="attrs"><span class="str"><%= hero.str_base %> <span class="gain">+<%= hero.str_gain.toFixed(1) %></span></span><span class="agi"><%= hero.agi_base %> <span class="gain">+<%= hero.agi_gain.toFixed(1) %></span></span><span class="int"><%= hero.int_base %> <span class="gain">+<%= hero.int_gain.toFixed(1) %></span></span></p></div></div><div class="hype"><p class="npe"><%= hero.npe_desc_loc %></p> <%- hero.hype_loc %> </div><div class="details"><div class="talents"><div class="talent"><div class="left"><%= hero.talents[7].name_loc %></div><div class="level">25</div><div class="right"><%= hero.talents[6].name_loc %></div></div><div class="talent"><div class="left"><%= hero.talents[5].name_loc %></div><div class="level">20</div><div class="right"><%= hero.talents[4].name_loc %></div></div><div class="talent"><div class="left"><%= hero.talents[3].name_loc %></div><div class="level">15</div><div class="right"><%= hero.talents[2].name_loc %></div></div><div class="talent"><div class="left"><%= hero.talents[1].name_loc %></div><div class="level">10</div><div class="right"><%= hero.talents[0].name_loc %></div></div></div><div class="list"><div class="bars"><div class="health"><span class="number"><%= hero.max_health %></span><span class="suffix">+<%= hero.health_regen.toFixed(1) %></span></div><div class="mana<%= !hero.max_mana ? ' zero' : '' %>"><span class="number"><%= hero.max_mana %></span><span class="suffix">+<%= hero.mana_regen.toFixed(1) %></span></div></div><div class="stats"><div class="column"><p><%= $t("dota2tracker.template.attack") %></p><div class="stat"><img src="<%= getImageUrl("icon_damage", ImageType.HeroStats) %>"/> <span><%= hero.damage_min %>~<%= hero.damage_max %></span></div><div class="stat"><img src="<%= getImageUrl("icon_attack_time", ImageType.HeroStats) %>"/> <span><%= hero.attack_rate.toFixed(1) %></span></div><div class="stat"><img src="<%= getImageUrl("icon_attack_range", ImageType.HeroStats) %>"/> <span><%= hero.attack_range %></span></div> <% if (hero_dc.attack_type !== "Melee") { %> <div class="stat"><img src="<%= getImageUrl("icon_projectile_speed", ImageType.HeroStats) %>"/> <span><%= hero.projectile_speed %></span></div> <% } %> </div><div class="column"><p><%= $t("dota2tracker.template.defense") %></p><div class="stat"><img src="<%= getImageUrl("icon_armor", ImageType.HeroStats) %>"/> <span><%= hero.armor.toFixed(1) %></span></div><div class="stat"><img src="<%= getImageUrl("icon_magic_resist", ImageType.HeroStats) %>"/> <span><%= hero.magic_resistance %>%</span></div></div><div class="column"><p><%= $t("dota2tracker.template.mobility") %></p><div class="stat"><img src="<%= getImageUrl("icon_movement_speed", ImageType.HeroStats) %>"/> <span><%= hero.movement_speed %></span></div><div class="stat"><img src="<%= getImageUrl("icon_turn_rate", ImageType.HeroStats) %>"/> <span><%= hero.turn_rate.toFixed(1) %></span></div><div class="stat"><img src="<%= getImageUrl("icon_vision", ImageType.HeroStats) %>"/> <span><%= hero.sight_range_day %> / <%= hero.sight_range_night %></span></div></div></div></div></div><div class="skills"> <% hero.abilities.forEach((item) => {
|
|
6
6
|
const ability_dc = dotaconstants.abilities[item.name];
|
|
7
7
|
|
|
8
8
|
// 预先查找冷却和耗蓝数据,避免在HTML中反复find
|
|
@@ -12,24 +12,14 @@
|
|
|
12
12
|
// 预先计算是否需要显示冷却/耗蓝 (非空 且 不全为0)
|
|
13
13
|
const hasCd = cdStats?.values_float.length && !(cdStats.values_float.length === 1 && cdStats.values_float[0] === 0);
|
|
14
14
|
const hasMana = manaStats?.values_float.length && !(manaStats.values_float.length === 1 && manaStats.values_float[0] === 0);
|
|
15
|
-
%> <div class="skill
|
|
15
|
+
%> <div class="skill" data-innate="<%= item.ability_is_innate %>"><p class="title"><span class="name font-serif"><%= item.name_loc %></span> <% if (item.ability_is_innate) { %> <span class="is_innate"><%= $t("dota2tracker.template.innate") %></span> <% } %> <% if (item.ability_is_granted_by_scepter) { %> <img src="<%= getImageUrl("scepter") %>" class="scepter"> <% } %> <% if (item.ability_is_granted_by_shard) { %> <img src="<%= getImageUrl("shard") %>" class="shard"> <% } %> </p><div class="img_stats"><img src="<%= getImageUrl(item.name, ImageType.Abilities) %>" onerror="this.onerror=null; this.src='<%= getImageUrl(`innate_icon`, ImageType.Icons) %>';"/><div class="stats"><p class="behavior"> <%= $t("dota2tracker.template.ability") %> <%= [].concat(ability_dc?.behavior)
|
|
16
16
|
.filter((beh) => beh !== "Hidden" || !(item.ability_is_granted_by_shard || item.ability_is_granted_by_scepter))
|
|
17
|
-
.map((beh) => $t("dota2tracker.template.behavior." + beh)).join("/") %> </p> <% if (ability_dc?.target_team) { %> <p class="target_team"> <%= $t("dota2tracker.template.affects") %> <%= [].concat(ability_dc?.target_team).map((tt) => $t("dota2tracker.template.target_team." + tt)).join("/") %> </p> <% } %> <% if (!Array.isArray(ability_dc?.dmg_type) && ability_dc?.dmg_type) { %> <p class="dmg_type <%= ability_dc?.dmg_type %>"> <%= $t("dota2tracker.template.damage_type") %> <span><%= $t("dota2tracker.template.damage_type_" + ability_dc?.dmg_type) %></span></p> <% } %> <% if (ability_dc?.dispellable) { %> <p class="dispellable <%= ability_dc?.dispellable == 'Strong Dispels Only' ? 'Strong' : ability_dc?.dispellable %>"> <%= $t("dota2tracker.template.dispellable") %> <span><%= $t("dota2tracker.template." + (ability_dc?.dispellable == "Strong Dispels Only" ? "dispellable_Strong" : ability_dc?.dispellable)) %></span></p> <% } %> <% if (!Array.isArray(ability_dc?.bkbpierce) && ability_dc?.bkbpierce) { %> <p class="bkbpierce <%= ability_dc?.bkbpierce %>"> <%= $t("dota2tracker.template.bkbpierce") %> <span><%= $t("dota2tracker.template." + ability_dc?.bkbpierce) %></span></p> <% } %> </div></div><p class="description"><%- item.desc_loc %></p> <%
|
|
18
|
-
const facetStartIndex = hero.facets.length - item.facets_loc.length;
|
|
19
|
-
item.facets_loc.forEach((facet_loc, i) => {
|
|
20
|
-
const realIndex = i + facetStartIndex;
|
|
21
|
-
if (realIndex >= 0 && facet_loc !== "") {
|
|
22
|
-
const currentFacet = hero.facets[realIndex];
|
|
23
|
-
%> <div class="facet"><div class="name_back type_<%= currentFacet.color %>"></div><div class="name_line type_<%= currentFacet.color %>"></div><p class="name"><img src="<%= getImageUrl(currentFacet.icon, ImageType.IconsFacets) %>"/> <span><%- currentFacet.title_loc %></span></p><div class="content"><div class="ability"><div class="description"><%- currentFacet.abilities.find(ab => ab.id == item.id)?.description_ability_loc %></div></div></div></div> <%
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
-
%> <% if (item.ability_has_scepter && !item.ability_is_granted_by_scepter && item.scepter_loc) { %> <p class="aghanim_description"><span class="title"><img src="<%= getImageUrl("scepter") %>" class="scepter"><%= $t("dota2tracker.template.scepter") %></span><span class="desc"><%- item.scepter_loc %></span></p> <% } %> <% if (item.ability_has_shard && !item.ability_is_granted_by_shard && item.shard_loc) { %> <p class="aghanim_description"><span class="title"><img src="<%= getImageUrl("shard") %>" class="shard"><%= $t("dota2tracker.template.shard") %></span><span class="desc"><%- item.shard_loc %></span></p> <% } %> <% if (item.notes_loc && item.notes_loc.length > 0) { %> <div class="notes"> <% item.notes_loc.forEach((note) => { %> <p><%- note %></p> <% }); %> </div> <% } %> <div class="attributes"> <%
|
|
17
|
+
.map((beh) => $t("dota2tracker.template.behavior." + beh)).join("/") %> </p> <% if (ability_dc?.target_team) { %> <p class="target_team"> <%= $t("dota2tracker.template.affects") %> <%= [].concat(ability_dc?.target_team).map((tt) => $t("dota2tracker.template.target_team." + tt)).join("/") %> </p> <% } %> <% if (!Array.isArray(ability_dc?.dmg_type) && ability_dc?.dmg_type) { %> <p class="dmg_type <%= ability_dc?.dmg_type %>"> <%= $t("dota2tracker.template.damage_type") %> <span><%= $t("dota2tracker.template.damage_type_" + ability_dc?.dmg_type) %></span></p> <% } %> <% if (ability_dc?.dispellable) { %> <p class="dispellable <%= ability_dc?.dispellable == 'Strong Dispels Only' ? 'Strong' : ability_dc?.dispellable %>"> <%= $t("dota2tracker.template.dispellable") %> <span><%= $t("dota2tracker.template." + (ability_dc?.dispellable == "Strong Dispels Only" ? "dispellable_Strong" : ability_dc?.dispellable)) %></span></p> <% } %> <% if (!Array.isArray(ability_dc?.bkbpierce) && ability_dc?.bkbpierce) { %> <p class="bkbpierce <%= ability_dc?.bkbpierce %>"> <%= $t("dota2tracker.template.bkbpierce") %> <span><%= $t("dota2tracker.template." + ability_dc?.bkbpierce) %></span></p> <% } %> </div></div><p class="description"><%- item.desc_loc %></p> <% if (item.ability_has_scepter && !item.ability_is_granted_by_scepter && item.scepter_loc) { %> <p class="aghanim_description"><span class="title"><img src="<%= getImageUrl("scepter") %>" class="scepter"><%= $t("dota2tracker.template.scepter") %></span><span class="desc"><%- item.scepter_loc %></span></p> <% } %> <% if (item.ability_has_shard && !item.ability_is_granted_by_shard && item.shard_loc) { %> <p class="aghanim_description"><span class="title"><img src="<%= getImageUrl("shard") %>" class="shard"><%= $t("dota2tracker.template.shard") %></span><span class="desc"><%- item.shard_loc %></span></p> <% } %> <% if (item.notes_loc && item.notes_loc.length > 0) { %> <div class="notes"> <% item.notes_loc.forEach((note) => { %> <p><%- note %></p> <% }); %> </div> <% } %> <div class="attributes"> <%
|
|
27
18
|
item.special_values.filter(sv => sv.heading_loc).forEach((sv) => {
|
|
28
19
|
// 预计算条件,简化模板逻辑
|
|
29
20
|
const isAllZero = sv.values_float?.every(value => value === 0) || sv.values_float.length == 0;
|
|
30
21
|
const hasScepterVal = sv.values_scepter && sv.values_scepter.length;
|
|
31
22
|
const hasShardVal = sv.values_shard && sv.values_shard.length;
|
|
32
|
-
const hasFacetVal = sv.facet_bonus.name && hero.facets.some(facet => facet.name == sv.facet_bonus.name);
|
|
33
23
|
const hasTalentVal = sv.bonuses.length > 0;
|
|
34
24
|
|
|
35
25
|
// 如果基础值全为0,且没有任何额外加成(A杖/魔晶/命石),则该条目其实没意义,但在原逻辑里似乎是作为空 primary 渲染?
|
|
@@ -39,9 +29,7 @@
|
|
|
39
29
|
// 让我们遵循原逻辑:
|
|
40
30
|
// Primary 部分:除非 (全0 且 有额外加成),否则渲染数值。
|
|
41
31
|
// 如果 (全0 且 有额外加成) -> 渲染内容为空字符串。
|
|
42
|
-
%> <p><span class="heading"><%= sv.heading_loc %></span><span class="values"> <% if (!isAllZero || (isAllZero && (hasScepterVal || hasShardVal
|
|
43
|
-
const facet = hero.facets.find(f => f.name == sv.facet_bonus.name);
|
|
44
|
-
%> <span class="alternative facet"><span class="facet"><span class="name_back type_<%= facet.color %>"><img src="<%= getImageUrl(facet.icon, ImageType.IconsFacets) %>"/> <%= sv.facet_bonus.values.map(value => value + (sv.is_percentage ? "%" : "")).join(" / ") %> </span></span></span> <% } %> <% if (hasTalentVal) { %> <span class="alternative talent"> <% sv.bonuses.forEach(bonus => { %> <img src="<%= getImageUrl("talents", "icons", "svg") %>"/> <%- (bonus.value > 0 ? '<span class="plus">+</span>' : "") + bonus.value + (sv.is_percentage ? "%" : "") %> <% }); %> </span> <% } %> </span></p> <% }); %> </div><p> <% if (hasCd) { %> <span class="cooldown"> <%= cdStats.values_float.join(" / ") %> </span> <% } %> <% if (hasMana) { %> <span class="mana_cost"> <%= manaStats.values_float.join(" / ") %> </span> <% } %> </p> <% if (item.lore_loc) { %> <p class="lore"><%= item.lore_loc %></p> <% } %> </div> <% }); %> </div><div class="lore"> <%- hero.bio_loc %> </div></div></body><script>document.addEventListener('DOMContentLoaded', function() {
|
|
32
|
+
%> <p><span class="heading"><%= sv.heading_loc %></span><span class="values"> <% if (!isAllZero || (isAllZero && (hasScepterVal || hasShardVal))) { %> <span class="primary<%= isAllZero ? ' empty' : '' %>"> <% if (!isAllZero) { %> <%= sv.values_float.map(value => value + (sv.is_percentage ? "%" : "")).join(" / ") %> <% } %> </span> <% } %> <% if (hasScepterVal) { %> <span class="alternative scepter"><img src="<%= getImageUrl("scepter") %>"/> <%- sv.values_scepter.map(value => (value > 0 ? '<span class="plus">+</span>' : "") + value + (sv.is_percentage ? "%" : "")).join(" / ") %> </span> <% } %> <% if (hasShardVal) { %> <span class="alternative shard"><img src="<%= getImageUrl("shard") %>"/> <%- sv.values_shard.map(value => (value > 0 ? '<span class="plus">+</span>' : "") + value + (sv.is_percentage ? "%" : "")).join(" / ") %> </span> <% } %> <% if (hasTalentVal) { %> <span class="alternative talent"> <% sv.bonuses.forEach(bonus => { %> <img src="<%= getImageUrl("talents", "icons", "svg") %>"/> <%- (bonus.value > 0 ? '<span class="plus">+</span>' : "") + bonus.value + (sv.is_percentage ? "%" : "") %> <% }); %> </span> <% } %> </span></p> <% }); %> </div><p> <% if (hasCd) { %> <span class="cooldown"> <%= cdStats.values_float.join(" / ") %> </span> <% } %> <% if (hasMana) { %> <span class="mana_cost"> <%= manaStats.values_float.join(" / ") %> </span> <% } %> </p> <% if (item.lore_loc) { %> <p class="lore"><%= item.lore_loc %></p> <% } %> </div> <% }); %> </div><div class="lore"> <%- hero.bio_loc %> </div></div></body><script>document.addEventListener('DOMContentLoaded', function() {
|
|
45
33
|
const items = document.querySelectorAll('.skills > .skill');
|
|
46
34
|
items.forEach(item => {
|
|
47
35
|
// const name = item.getAttribute('data-name');
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#ff6961" d="M36 32a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4h28a4 4 0 0 1 4 4v28z"></path><circle fill="#FFF" cx="27" cy="7" r="3"></circle><path fill="#FFF" d="M13.06 13.06l2.367-2.366l3.859 1.158l-2.635 2.847a10.018 10.018 0 0 1 4.392 3.379l5.017-5.017a1.5 1.5 0 0 0-.63-2.497l-9.999-3a1.495 1.495 0 0 0-1.492.376l-3 3a1.5 1.5 0 1 0 2.121 2.12zm16.065 4.949a1.496 1.496 0 0 0-1.262-.503l-6.786.617a9.966 9.966 0 0 1 1.464 2.879l3.548-.322l-1.554 6.995a1.499 1.499 0 1 0 2.928.65l2-9a1.5 1.5 0 0 0-.338-1.316zM13 16a8 8 0 1 0 0 16a8 8 0 0 0 0-16zm0 14a6 6 0 1 1 .002-12.002A6 6 0 0 1 13 30z"></path></svg>
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="#fff" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 395 395" xml:space="preserve"><g><path d="M313.002,0H82C36.785,0,0,36.784,0,81.998v230.993C0,358.211,36.785,395,82,395h231.002 C358.216,395,395,358.211,395,312.991V81.998C395,36.784,358.216,0,313.002,0z M380,312.991C380,349.94,349.944,380,313.002,380H82 c-36.944,0-67-30.06-67-67.009V81.998C15,45.055,45.056,15,82,15h231.002C349.944,15,380,45.055,380,81.998V312.991z"/><path d="M305.336,107.5c-21.492,0-38.915,17.422-38.915,38.912c0,21.495,17.423,38.915,38.915,38.915 c21.49,0,38.911-17.42,38.911-38.915C344.247,124.922,326.826,107.5,305.336,107.5z"/><path d="M309.227,186.313c-10.602,0-21.818,7.267-21.818,7.267l-20.557-20.553c-2.876-2.876-3.857-3.915-6.746-3.915H145.701 H65.539v-0.193c0-2.149-1.742-3.891-3.892-3.891c-2.149,0-3.892,1.742-3.892,3.891v0.193h-7.003c-4.298,0-7.782,3.484-7.782,7.783 c0,4.298,3.484,7.783,7.782,7.783h87.166v9.081c0,4.298,3.484,7.783,7.782,7.783h36.863c-0.523,5.762,2.184,11.588,7.477,14.765 l53.325,31.996c2.468,1.48,5.238,2.218,8.009,2.218c2.905,0,5.809-0.813,8.355-2.433l14.475-9.209V287.5h70.042v-66.164 C344.247,201.992,328.567,186.313,309.227,186.313z M251.135,216.658L225.94,201.54h26.137l8.872,8.873L251.135,216.658z"/><path d="M167.491,165.612h45.528c4.298,0,7.782-3.484,7.782-7.783s-3.484-7.783-7.782-7.783h-45.528 c-4.298,0-7.782,3.484-7.782,7.783S163.193,165.612,167.491,165.612z"/></g></svg>
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="green" d="M8.05731 22.3674L9.60454 22.8002L11.5974 21.6551L12.043 20.0773L13.5902 20.51L15.583 19.3649L16.0287 17.7871L17.5759 18.2199L19.5687 17.0748L20.0143 15.4969L21.5615 15.9297L23.5544 14.7846L24 13.2068L23.4492 12.2014L7.50651 21.3621L8.05731 22.3674ZM12.1328 3.50265L11.0312 1.49196C10.8798 1.21549 10.5316 1.11811 10.2576 1.27556L0.29345 7.00098C0.0194354 7.15843 -0.0808273 7.51346 0.0706444 7.78993L1.44766 10.3033L11.91 4.29159C12.184 4.13414 12.2843 3.77912 12.1328 3.50265ZM18.3935 8.4063L14.1658 9.60458L12.4221 10.6065C12.2851 10.6853 12.111 10.6366 12.0353 10.4983L11.7599 9.99565C11.6842 9.85742 11.7343 9.6799 11.8713 9.60118L13.615 8.59924L13.0642 7.59389L11.3205 8.59584C11.1835 8.67456 11.0094 8.62587 10.9337 8.48765L10.6583 7.98497C10.5826 7.84673 10.6327 7.66922 10.7697 7.5905L12.5134 6.58855L11.9626 5.58321L1.99846 11.3086L6.9557 20.3567L22.8984 11.196L22.2615 10.0336C21.5024 8.64813 19.9073 7.97847 18.3935 8.4063Z"></path></svg>
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-1 0 19 19"><path fill="red" d="M16.417 9.579A7.917 7.917 0 1 1 8.5 1.662a7.917 7.917 0 0 1 7.917 7.917zm-2.458 2.96a.396.396 0 0 0-.396-.397h-.667a1.527 1.527 0 0 0-1.249-1.114.777.777 0 0 0 .014-.145V9.378a.794.794 0 0 0-.792-.792H8.201a2.984 2.984 0 0 0-1.682-.516l-.11.002V7.42h2.997a.396.396 0 1 0 0-.792H6.41v-1.3a.396.396 0 0 0-.396-.397H4.891a.396.396 0 0 0 0 .792h.727V8.21a2.997 2.997 0 1 0 3.836 3.466h.71a1.526 1.526 0 1 0 2.732 1.26h.667a.396.396 0 0 0 .396-.397zM8.078 9.507a2.205 2.205 0 1 1-1.559-.646 2.19 2.19 0 0 1 1.559.646zm4.078 3.03a.734.734 0 1 1-.733-.734.735.735 0 0 1 .733.733z"/></svg>
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="#fff" viewBox="0 0 512.001 512.001"><g><g><path d="M120.988,239.868c-4.496,10.625-5.122,20.183-5.157,20.811c-0.267,4.607,3.243,8.547,7.849,8.829 c4.618,0.29,8.574-3.228,8.873-7.833c0.265-4.771,2.339-13.092,5.884-19.44C137.421,242.113,141.397,242.649,120.988,239.868z"/></g></g><g><g><path d="M391.178,255.418c-0.211,8.054-2.458,17.62-6.74,28.398c-1.708,4.299,0.393,9.168,4.692,10.875 c4.293,1.708,9.167-0.39,10.875-4.692c5.103-12.842,7.74-24.392,7.943-34.581H391.178z"/></g></g><g><g><path d="M164.769,210.51c1.046,3.339,1.397,6.953,0.893,10.65c-0.293,2.146-0.857,4.188-1.648,6.1c0,0,51.266,3.416,198.065,3.949 c-0.086-6.331,2.19-12.199,6.244-16.732C217.627,214.046,164.769,210.51,164.769,210.51z"/></g></g><g><g><circle cx="37.179" cy="128.669" r="29.491"/></g></g><g><g><path d="M510.146,391.511l-37.916-66.985c14.35-49.173,20.678-68.137,20.678-68.137l8.949-67.014 c1.502-10.977-6.248-21.075-17.235-22.468l-18.183-2.305c-10.984-1.393-20.996,6.445-22.293,17.431l-1.884,15.955l28.718-21.317 l-37.91,42.278h-46.432c-6.571,0-11.898,5.328-11.898,11.898c0,6.57,5.328,11.898,11.898,11.898h51.744 c3.381,0,6.601-1.438,8.859-3.956l41.456-46.234l-32.023,54.694c-5.28,9.018-14.374,8.169-18.293,8.167c-1.959,0-3.31,0-5.295,0 c-0.399,0.898,3.152-7.399-24.44,57.181c-0.548,1.284-0.907,2.642-1.06,4.031l-8.934,80.338 c-0.939,8.447,5.667,15.857,14.208,15.857c7.179,0,13.361-5.401,14.172-12.701l8.702-78.244l21.512-50.353l-14.121,50.463 c-1.158,3.756-0.718,7.823,1.218,11.243l40.949,72.345c3.885,6.864,12.596,9.276,19.459,5.392 C511.615,407.085,514.03,398.373,510.146,391.511z"/></g></g><g><g><circle cx="464.865" cy="128.702" r="29.491"/></g></g><g><g><path d="M142.923,206.051l-59.556-8.118l-39.135-18.451l13.626,2.292c-1.422-10.945-11.411-18.577-22.254-17.202l-18.182,2.305 C6.43,168.271-1.315,178.374,0.186,189.345l9.12,68.689l21.865,70.857l5.829,70.795c0.646,7.848,7.527,13.705,15.401,13.057 c7.859-0.647,13.705-7.542,13.058-15.401l-5.956-72.345c-0.084-1.031-0.281-2.05-0.585-3.039l-14.123-50.463l21.514,50.353 l8.702,78.244c0.873,7.86,7.96,13.486,15.768,12.612c7.838-0.871,13.483-7.931,12.612-15.768l-8.934-80.338 c-0.154-1.388-0.511-2.747-1.06-4.032l-27.336-61.43l-2.945-24.951l-29.029-25.179l40.79,19.231 c1.097,0.517,2.266,0.862,3.468,1.027l61.369,8.365c6.521,0.887,12.509-3.68,13.396-10.183 C153.994,212.936,149.435,206.939,142.923,206.051z"/></g></g></svg>
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="lightgreen" d="M198.844 64.75c-.985 0-1.974.03-2.97.094-15.915 1.015-32.046 11.534-37.78 26.937-34.072 91.532-51.085 128.865-61.5 222.876 14.633 13.49 31.63 26.45 50.25 38.125l66.406-196.467 17.688 5.968L163.28 362.5c19.51 10.877 40.43 20.234 62 27.28l75.407-201.53 17.5 6.53-74.937 200.282c19.454 5.096 39.205 8.2 58.78 8.875L381.345 225.5l17.094 7.594-75.875 170.656c21.82-1.237 43.205-5.768 63.437-14.28 43.317-53.844 72.633-109.784 84.5-172.69 5.092-26.992-14.762-53.124-54.22-54.81l-6.155-.282-2.188-5.75c-8.45-22.388-19.75-30.093-31.5-32.47-11.75-2.376-25.267 1.535-35.468 7.376l-13.064 7.47-.906-15c-.99-16.396-10.343-29.597-24.313-35.626-13.97-6.03-33.064-5.232-54.812 9.906l-10.438 7.25-3.812-12.125c-6.517-20.766-20.007-27.985-34.78-27.97zM103.28 188.344C71.143 233.448 47.728 299.56 51.407 359.656c27.54 21.84 54.61 33.693 80.063 35.438 14.155.97 27.94-1.085 41.405-6.438-35.445-17.235-67.36-39.533-92.594-63.53l-3.343-3.157.5-4.595c5.794-54.638 13.946-91.5 25.844-129.03z"/></svg>
|
|
@@ -5,4 +5,4 @@
|
|
|
5
5
|
const matchName = /^npc_dota_hero_(?<name>.+)$/.exec(heroData.name);
|
|
6
6
|
return matchName ? matchName[1] : "";
|
|
7
7
|
});
|
|
8
|
-
%> <% const banGradientStyle = "background-image: linear-gradient(to bottom left, transparent calc(50% - 1px), red calc(50% - 1px), black calc(50% + 1px), transparent calc(50% + 1px));"; %> <div class="w-[790px] h-[100px] flex justify-between box m-[5px]"><div class="flag w-[100px] h-full flex justify-center items-end bg-cover <%= !match.didRadiantWin ? 'grayscale' : "" %>" style="background-image:url('<%= getImageUrl("flag_radiant") %>')"> <%= match.didRadiantWin ? $t("dota2tracker.template.won") : "" %> </div><div class="details grow relative flex-col flex"><p class="w-full flex justify-around"><span><%= $t("dota2tracker.template.match_id_") %><%= match.id %></span><span><%= $t("dota2tracker.template.game_mode_") %><%= gameModeStr %></span><span><%= $t("dota2tracker.template.region_") %><%= regionStr %></span></p><p class="w-full flex justify-around"><span><%= $t("dota2tracker.template.start_time_") %><%= startTime %></span><span><%= $t("dota2tracker.template.end_time_") %><%= endTime %></span></p><p class="w-full grow score flex justify-evenly items-end"><span class="score radiant text-3xl"><%= match.radiant.killsCount %></span><span class="time text-sm"><%= match.durationTime %></span><span class="score dire text-3xl"><%= match.dire.killsCount %></span></p><div class="rank absolute w-[64px] h-[64px] bottom-[10px] left-1/2 -translate-x-1/2<%- match.odParsed && match.lobbyType !== "RANKED" ? ` grayscale` : "" %>"><img class="star absolute w-full" src="<%= getImageUrl('star_' + (match.rank ? match.rank.toString().split('')[1] : '')) %>"> <img class="medal absolute w-full" src="<%= getImageUrl('medal_' + (match.rank ? match.rank.toString().split('')[0] : '')) %>"></div></div><div class="flag w-[100px] h-full flex justify-center items-end bg-cover <%= match.didRadiantWin ? 'grayscale' : "" %>" style="background-image:url('<%= getImageUrl("flag_dire") %>')"> <%= !match.didRadiantWin ? $t("dota2tracker.template.won") : "" %> </div></div><div class="w-[790px] grid grid-cols-2 gap-[5px] mx-[5px]"> <% match.players.forEach(player => { %> <%- include(`./player.ejs`, { match, player, utils: {kc, dc, laneSVG},
|
|
8
|
+
%> <% const banGradientStyle = "background-image: linear-gradient(to bottom left, transparent calc(50% - 1px), red calc(50% - 1px), black calc(50% + 1px), transparent calc(50% + 1px));"; %> <div class="w-[790px] h-[100px] flex justify-between box m-[5px]"><div class="flag w-[100px] h-full flex justify-center items-end bg-cover <%= !match.didRadiantWin ? 'grayscale' : "" %>" style="background-image:url('<%= getImageUrl("flag_radiant") %>')"> <%= match.didRadiantWin ? $t("dota2tracker.template.won") : "" %> </div><div class="details grow relative flex-col flex"><p class="w-full flex justify-around"><span><%= $t("dota2tracker.template.match_id_") %><%= match.id %></span><span><%= $t("dota2tracker.template.game_mode_") %><%= gameModeStr %></span><span><%= $t("dota2tracker.template.region_") %><%= regionStr %></span></p><p class="w-full flex justify-around"><span><%= $t("dota2tracker.template.start_time_") %><%= startTime %></span><span><%= $t("dota2tracker.template.end_time_") %><%= endTime %></span></p><p class="w-full grow score flex justify-evenly items-end"><span class="score radiant text-3xl"><%= match.radiant.killsCount %></span><span class="time text-sm"><%= match.durationTime %></span><span class="score dire text-3xl"><%= match.dire.killsCount %></span></p><div class="rank absolute w-[64px] h-[64px] bottom-[10px] left-1/2 -translate-x-1/2<%- match.odParsed && match.lobbyType !== "RANKED" ? ` grayscale` : "" %>"><img class="star absolute w-full" src="<%= getImageUrl('star_' + (match.rank ? match.rank.toString().split('')[1] : '')) %>"> <img class="medal absolute w-full" src="<%= getImageUrl('medal_' + (match.rank ? match.rank.toString().split('')[0] : '')) %>"></div></div><div class="flag w-[100px] h-full flex justify-center items-end bg-cover <%= match.didRadiantWin ? 'grayscale' : "" %>" style="background-image:url('<%= getImageUrl("flag_dire") %>')"> <%= !match.didRadiantWin ? $t("dota2tracker.template.won") : "" %> </div></div><div class="w-[790px] grid grid-cols-2 gap-[5px] mx-[5px]"> <% match.players.forEach(player => { %> <%- include(`./player.ejs`, { match, player, utils: {kc, dc, laneSVG}, partyColor }) %> <% }); %> </div><div class="ban_list box m-[5px] flex flex-wrap"> <% bannedHeroes.forEach(heroName => { %> <div class="ban_hero relative w-[10%]"><i class="absolute w-full h-full z-1" <%- `style="${banGradientStyle}"` %>></i> <img class="grayscale" src="<%= getImageUrl(heroName, ImageType.Heroes) %>" alt=""/></div> <% }); %> </div>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<% const p = player; %> <% const isLD = p.hero.id == 80; %> <% const gridCol = !p.isRadiant + 1; %> <% const gridRow = (p.position ? parseInt(p.position.slice(-1)) : 0) % 5; %> <% const gridStyle = `grid-column: ${gridCol}; grid-row: ${gridRow}`; %> <% const pColor = partyColor[p.partyId]; %> <% const partyLineStyle = `background-color: ${pColor};`; %> <% const partyMarkStyle = `color: ${pColor};`; %> <% const orderColors = ['red', 'yellow', 'green']; %> <% const orderColor = orderColors[Math.floor(p.order / 4)] || 'white'; %> <% const kcVal = Math.floor(p.killContribution * 100); %> <% const dcVal = Math.floor(p.deathContribution * 100); %> <% const kcStyle = `color: ${utils.kc(kcVal)}`; %> <% const dcStyle = `color: ${utils.dc(dcVal)}`; %> <% const
|
|
1
|
+
<% const p = player; %> <% const isLD = p.hero.id == 80; %> <% const gridCol = !p.isRadiant + 1; %> <% const gridRow = (p.position ? parseInt(p.position.slice(-1)) : 0) % 5; %> <% const gridStyle = `grid-column: ${gridCol}; grid-row: ${gridRow}`; %> <% const pColor = partyColor[p.partyId]; %> <% const partyLineStyle = `background-color: ${pColor};`; %> <% const partyMarkStyle = `color: ${pColor};`; %> <% const orderColors = ['red', 'yellow', 'green']; %> <% const orderColor = orderColors[Math.floor(p.order / 4)] || 'white'; %> <% const kcVal = Math.floor(p.killContribution * 100); %> <% const dcVal = Math.floor(p.deathContribution * 100); %> <% const kcStyle = `color: ${utils.kc(kcVal)}`; %> <% const dcStyle = `color: ${utils.dc(dcVal)}`; %> <% const damageReport = p.stats?.heroDamageReport?.receivedTotal || {}; %> <% const dealtReport = p.stats?.heroDamageReport?.dealtTotal || {}; %> <% const damageReceived = (damageReport.physicalDamage || 0) + (damageReport.magicalDamage || 0) + (damageReport.pureDamage || 0); %> <% const ccStun = ((dealtReport.stunDuration || 0) / 100).toFixed(2); %> <% const ccSlow = ((dealtReport.slowDuration || 0) / 100).toFixed(2); %> <% const ccDisable = ((dealtReport.disableDuration || 0) / 100).toFixed(2); %> <div class="box h-[320px] flex flex-col gap-[4px] rounded-[5px]" <%- `style="${gridStyle}"` %>><section class="grid grid-cols-[112px_1fr_100px] grid-rows-[63px_24px]"><div class="avatar relative h-full relative row-1 col-1 text-[10px] text-shadow-[-1px_1px_2px_#000,1px_-1px_2px_#000,-1px_1px_2px_#000,1px_1px_2px_#000]"> <% if (p.leaverStatus != "NONE" && p.leaverStatus != "DISCONNECTED") { %> <img class="leaver absolute w-full h-full object-contain" src="<%= getImageUrl("disconnected") %>"/> <% } %> <div class="party contents"><i class="party_line absolute w-full h-[2px]" <%- `style="${partyLineStyle}"` %>></i> <b class="party_mark absolute leading-[1.5] w-[16px] top-[3px] left-[2px] bg-black/80 text-center" <%- `style="${partyMarkStyle}"` %>> <%= match.party[p.partyId] %> </b></div><div class="hero_info absolute top-[3px] right-0 text-right leading-[1.25]"><p class="order" <%- `style="color: ${orderColor};"` %>> <%= p.isRandom ? $t("dota2tracker.template.random") : $t("dota2tracker.template.pick_order", [`${p.order == null ? "?" : p.order + 1}`]) %> </p><p class="position"><%= $t("dota2tracker.template.position_" + p.position?.slice(-1)) ?? '' %></p></div><p class="level absolute bottom-0 right-0 text-xs px-[2px]"><%= p.level %></p><img class="h-full" src="<%= getImageUrl(p.hero.shortName, ImageType.Heroes) %>"/></div><div class="player_profile mx-[10px] row-1 col-2 w-auto h-full overflow-hidden text-center flex flex-col justify-around leading-[1]"><p class="player_name truncate max-w-full"><%= p.steamAccount.name %></p><p class="flex gap-[12px] justify-center"><span class="kda"><%= p.kills %>/<%= p.deaths %>/<%= p.assists %></span><span class="kc" <%- `style="${kcStyle}"` %>><%= kcVal %>%</span> <span class="dc" <%- `style="${dcStyle}"` %>><%= dcVal %>%</span></p><p class="flex gap-[16px] justify-center"><span class="networth text-[rgb(203,176,42)]"><%= p.networth %></span><span class="score"><%= (p.heroDamage / p.networth)?.toFixed(2) %></span></p></div><div class="lane_rank row-1 col-3 flex w-full h-full justify-between"><div class="lane w-[44px] h-full"><p class="text-[10px] text-center"><%= $t("dota2tracker.template.lane_" + p.laneResult) %></p><div class="h-[44px] w-[44px]"><img src="<%- utils.laneSVG[p.laneResult] %>"/></div></div><div class="rank_plus w-[36px] h-full relative text-[10px] leading-[1.15] text-shadow-[-1px_1px_0_#000,1px_-1px_0_#000,-1px_1px_0_#000,1px_1px_0_#000]"><div class="rank absolute top-0 size-[36px] z-2"><img class="medal absolute inset-0" src="<%= getImageUrl('medal_' + (p.rank.inTop100 ?? p.rank.medal)) %>"/> <img class="stars absolute inset-0" src="<%= getImageUrl('star_' + p.rank.star) %>"/><p class="leader absolute bottom-0 text-center w-full"><%= p.steamAccount?.seasonLeaderboardRank ?? "" %></p></div> <% if (p.dotaPlus) { %> <div class="plus absolute bottom-0 size-[36px] z-1"><img class="" src="<%= getImageUrl("hero_badge_" + (p.dotaPlus ? Math.ceil((p.dotaPlus?.level + 1) / 6) : 1)) %>"><p class="level absolute bottom-0 text-center w-full"><%= p.dotaPlus?.level %></p></div> <% } %> </div></div><div class="titles row-2 col-start-1 col-end-3 w-full flex items-center pl-[10px] gap-[10px]"> <% p.titles.forEach(item => { %> <% const title = parseBadge(item, $t); %> <span <%- `style="color: ${title.color};"` %>><%= title.shortText %></span> <% }); %> </div></section> <% if (!isLD) { %> <section class="items w-full grid grid-cols-[repeat(3,3fr)_2fr_3fr] grid-rows-2"><div class="items_main contents"> <% for(let i = 0; i < 6; i++) { %> <%- include("./item.ejs", {item: p.items[i], style: `col-${i%3+1}`, isNeutral: false}) %> <% } %> </div><div class="items_backpack grayscale col-4 row-start-1 row-span-2 flex flex-col"> <% for(let i = 0; i < 3; i++) { %> <%- include("./item.ejs", {item: p.backpacks[i], style: "", isNeutral: false}) %> <% } %> </div><div class="items_neutral contents"> <%- include("./item.ejs", {item: p.neutral0Id, style: "row-start-1 row-span-2 col-5 flex items-center h-full", isNeutral: true}) %> </div></section> <% } else { %> <section class="items w-full grid grid-cols-[repeat(6,3fr)_10fr] grid-rows-4"><div class="items_hero contents"><div class="items_main contents"> <% for(let i = 0; i < 6; i++) { %> <%- include("./item.ejs", {item: p.items[i], style: `row-1 col-${i+1}`, isNeutral: false}) %> <% } %> </div><div class="items_backpack grayscale contents"> <% for(let i = 0; i < 3; i++) { %> <%- include("./item.ejs", {item: p.backpacks[i], style: `row-2 col-${i+1}`, isNeutral: false}) %> <% } %> </div><div class="items_neutral contents"> <%- include("./item.ejs", {item: p.neutral0Id, style: "row-2 col-6", isNeutral: true}) %> </div></div><div class="items_unit contents"><div class="items_main contents"> <% for(let i = 0; i < 6; i++) { %> <%- include("./item.ejs", {item: p.unitItems[i], style: `row-3 col-${i+1}`, isNeutral: false}) %> <% } %> </div><div class="items_backpack grayscale contents"> <% for(let i = 0; i < 3; i++) { %> <%- include("./item.ejs", {item: p.unitBackpacks[i], style: `row-4 col-${i+1}`, isNeutral: false}) %> <% } %> </div><div class="items_neutral contents"> <%- include("./item.ejs", {item: p.additionalUnit.neutral0Id, style: "row-4 col-6", isNeutral: true}) %> </div></div></section> <% } %> <section class="buffs_supports w-full h-[24px] flex justify-between"><div class="buffs flex h-[24px]"> <% p.buffs.forEach(buff => { %> <div class="relative"><img class="w-[33px] h-[24px]" src="<%= getImageUrl(dotaconstants[`${buff.type}_ids`][buff.id], ImageType[buff.type === "ability" ? "Abilities" : "Items"]) %>"/><p class="count absolute w-full bottom-0 leading-[1] text-center bg-stone-700/50 text-[10px]"><%= buff.stackCount || "" %></p></div> <% }); %> </div><div class="supports flex h-[24px]"> <% p.supportItemsCount.forEach(supportItem => { %> <div class="relative"><img class="w-[33px] h-[24px]" src="<%= getImageUrl(supportItem.name, ImageType.Items) %>"/><p class="count absolute w-full bottom-0 leading-[1] text-center bg-stone-700/50 text-[10px]"><%= supportItem.count || "" %></p></div> <% }); %> </div></section><section class="player-stat h-full flex flex-col justify-around text-[13px] leading-[24px] whitespace-nowrap"><p class="w-full flex justify-around"><span><%= $t("dota2tracker.template.hero_damage_") %><span class="hero_damage"><%= p.heroDamage %></span></span><span><%= $t("dota2tracker.template.building_damage_") %><span class="building_damage"><%= p.towerDamage %></span></span><span><%= $t("dota2tracker.template.damage_received_") %><span class="tak"><%= damageReceived %></span></span></p><p class="w-full flex justify-around"><span><%= $t("dota2tracker.template.lasthit_") %><span class="lh"><%= p.numLastHits %></span>/<span class="dn"><%= p.numDenies %></span></span><span><%= $t("dota2tracker.template.GPM/XPM_") %><span class="gpm"><%= p.goldPerMinute %></span>/<span class="xpm"><%= p.experiencePerMinute %></span></span><span><%= $t("dota2tracker.template.heal_") %><span class="heal"><%= p.heroHealing %></span></span></p><p class="w-full flex justify-center"><span><%= $t("dota2tracker.template.crowd_control_duration_") %></span><span><%= ccStun + "/" %></span><span><%= ccSlow + "/" %></span><span><%= ccDisable %></span>s</p></section></div>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
/*! tailwindcss v4.1.13 | MIT License | https://tailwindcss.com */@layer properties;@layer theme,base,components,utilities;@layer theme{:root,:host{--font-sans: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-stone-700: oklch(37.4% .01 67.558);--color-black: #000;--color-white: #fff;--spacing: .25rem;--text-xs: .75rem;--text-xs--line-height: calc(1 / .75);--text-sm: .875rem;--text-sm--line-height: calc(1.25 / .875);--text-3xl: 1.875rem;--text-3xl--line-height: 1.2 ;--default-font-family: var(--font-sans);--default-mono-font-family: var(--font-mono)}}@layer base{*,:after,:before,::backdrop,::file-selector-button{box-sizing:border-box;margin:0;padding:0;border:0 solid}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;tab-size:4;font-family:var(--default-font-family, ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings, normal);font-variation-settings:var(--default-font-variation-settings, normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings, normal);font-variation-settings:var(--default-mono-font-variation-settings, normal);font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea,::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;border-radius:0;background-color:transparent;opacity:1}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px){::placeholder{color:currentcolor;@supports (color: color-mix(in lab,red,red)){color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit,::-webkit-datetime-edit-year-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]),::file-selector-button{appearance:button}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer utilities{.absolute{position:absolute}.relative{position:relative}.inset-0{inset:calc(var(--spacing) * 0)}.top-0{top:calc(var(--spacing) * 0)}.top-\[3px\]{top:3px}.right-0{right:calc(var(--spacing) * 0)}.bottom-0{bottom:calc(var(--spacing) * 0)}.bottom-\[10px\]{bottom:10px}.left-1\/2{left:50%}.left-\[2px\]{left:2px}.z-1{z-index:1}.z-2{z-index:2}.col-1{grid-column:1}.col-2{grid-column:2}.col-3{grid-column:3}.col-4{grid-column:4}.col-5{grid-column:5}.col-6{grid-column:6}.col-start-2{grid-column-start:2}.col-end-3{grid-column-end:3}.row-1{grid-row:1}.row-2{grid-row:2}.row-3{grid-row:3}.row-4{grid-row:4}.row-span-2{grid-row:span 2 / span 2}.row-start-1{grid-row-start:1}.m-\[5px\]{margin:5px}.mx-\[5px\]{margin-inline:5px}.mx-\[10px\]{margin-inline:10px}.contents{display:contents}.flex{display:flex}.grid{display:grid}.aspect-\[11\/8\]{aspect-ratio:11/8}.size-\[36px\]{width:36px;height:36px}.h-\[2px\]{height:2px}.h-\[18px\]{height:18px}.h-\[24px\]{height:24px}.h-\[44px\]{height:44px}.h-\[64px\]{height:64px}.h-\[100px\]{height:100px}.h-\[320px\]{height:320px}.h-full{height:100%}.w-\[10\%\]{width:10%}.w-\[16px\]{width:16px}.w-\[24px\]{width:24px}.w-\[33px\]{width:33px}.w-\[36px\]{width:36px}.w-\[44px\]{width:44px}.w-\[64px\]{width:64px}.w-\[100px\]{width:100px}.w-\[790px\]{width:790px}.w-\[800px\]{width:800px}.w-auto{width:auto}.w-full{width:100%}.max-w-full{max-width:100%}.grow{flex-grow:1}.origin-top-right{transform-origin:top right}.-translate-x-1\/2{--tw-translate-x: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y)}.scale-\[0\.6\]{scale:.6}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-\[24px_1fr\]{grid-template-columns:24px 1fr}.grid-cols-\[112px_1fr_100px\]{grid-template-columns:112px 1fr 100px}.grid-cols-\[repeat\(3\,3fr\)_2fr_3fr\]{grid-template-columns:repeat(3,3fr) 2fr 3fr}.grid-cols-\[repeat\(6\,3fr\)_10fr\]{grid-template-columns:repeat(6,3fr) 10fr}.grid-rows-1{grid-template-rows:repeat(1,minmax(0,1fr))}.grid-rows-2{grid-template-rows:repeat(2,minmax(0,1fr))}.grid-rows-4{grid-template-rows:repeat(4,minmax(0,1fr))}.grid-rows-\[63px_24px\]{grid-template-rows:63px 24px}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-end{align-items:flex-end}.justify-around{justify-content:space-around}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-evenly{justify-content:space-evenly}.gap-\[4px\]{gap:4px}.gap-\[5px\]{gap:5px}.gap-\[6px\]{gap:6px}.gap-\[12px\]{gap:12px}.gap-\[16px\]{gap:16px}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.overflow-hidden{overflow:hidden}.rounded-\[5px\]{border-radius:5px}.border{border-style:var(--tw-border-style);border-width:1px}.bg-\[\#4444\]{background-color:#4444}.bg-black{background-color:var(--color-black)}.bg-black\/80{background-color:color-mix(in srgb,#000 80%,transparent);@supports (color: color-mix(in lab,red,red)){background-color:color-mix(in oklab,var(--color-black) 80%,transparent)}}.bg-stone-700\/50{background-color:color-mix(in srgb,oklch(37.4% .01 67.558) 50%,transparent);@supports (color: color-mix(in lab,red,red)){background-color:color-mix(in oklab,var(--color-stone-700) 50%,transparent)}}.bg-linear-to-r{--tw-gradient-position: to right;@supports (background-image: linear-gradient(in lab,red,red)){--tw-gradient-position: to right in oklab}background-image:linear-gradient(var(--tw-gradient-stops))}.from-\[\#2d2d2d\]{--tw-gradient-from: #2d2d2d;--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-\[\#9f3c3c\]{--tw-gradient-from: #9f3c3c;--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-\[\#547ea6\]{--tw-gradient-from: #547ea6;--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-\[\#675cae\]{--tw-gradient-from: #675cae;--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-\[\#a2b23e\]{--tw-gradient-from: #a2b23e;--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-\[\#adb6be\]{--tw-gradient-from: #adb6be;--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-\[\#c8a45c\]{--tw-gradient-from: #c8a45c;--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-\[\#000000\]{--tw-gradient-to: #000000;--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-\[\#2a385e\]{--tw-gradient-to: #2a385e;--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-\[\#2d5a18\]{--tw-gradient-to: #2d5a18;--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-\[\#4a2026\]{--tw-gradient-to: #4a2026;--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-\[\#4e5557\]{--tw-gradient-to: #4e5557;--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-\[\#6f3d21\]{--tw-gradient-to: #6f3d21;--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-\[\#261c44\]{--tw-gradient-to: #261c44;--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.bg-cover{background-size:cover}.object-contain{object-fit:contain}.object-cover{object-fit:cover}.px-\[2px\]{padding-inline:2px}.px-\[4px\]{padding-inline:4px}.pl-\[12px\]{padding-left:12px}.text-center{text-align:center}.text-right{text-align:right}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading, var(--text-3xl--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading, var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading, var(--text-xs--line-height))}.text-\[10px\]{font-size:10px}.text-\[13px\]{font-size:13px}.leading-\[1\.5\]{--tw-leading: 1.5;line-height:1.5}.leading-\[1\.15\]{--tw-leading: 1.15;line-height:1.15}.leading-\[1\.25\]{--tw-leading: 1.25;line-height:1.25}.leading-\[1\]{--tw-leading: 1;line-height:1}.leading-\[24px\]{--tw-leading: 24px;line-height:24px}.whitespace-nowrap{white-space:nowrap}.text-\[\#ccc\]{color:#ccc}.text-\[rgb\(203\,176\,42\)\]{color:#cbb02a}.text-white{color:var(--color-white)}.opacity-75{opacity:75%}.grayscale{--tw-grayscale: grayscale(100%);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.text-shadow-\[-1px_1px_0_\#000\,1px_-1px_0_\#000\,-1px_1px_0_\#000\,1px_1px_0_\#000\]{text-shadow:-1px 1px 0 var(--tw-text-shadow-color, #000),1px -1px 0 var(--tw-text-shadow-color, #000),-1px 1px 0 var(--tw-text-shadow-color, #000),1px 1px 0 var(--tw-text-shadow-color, #000)}.text-shadow-\[-1px_1px_2px_\#000\,1px_-1px_2px_\#000\,-1px_1px_2px_\#000\,1px_1px_2px_\#000\]{text-shadow:-1px 1px 2px var(--tw-text-shadow-color, #000),1px -1px 2px var(--tw-text-shadow-color, #000),-1px 1px 2px var(--tw-text-shadow-color, #000),1px 1px 2px var(--tw-text-shadow-color, #000)}}@property --tw-translate-x{syntax: "*"; inherits: false; initial-value: 0;}@property --tw-translate-y{syntax: "*"; inherits: false; initial-value: 0;}@property --tw-translate-z{syntax: "*"; inherits: false; initial-value: 0;}@property --tw-border-style{syntax: "*"; inherits: false; initial-value: solid;}@property --tw-gradient-position{syntax: "*"; inherits: false;}@property --tw-gradient-from{syntax: "<color>"; inherits: false; initial-value: #0000;}@property --tw-gradient-via{syntax: "<color>"; inherits: false; initial-value: #0000;}@property --tw-gradient-to{syntax: "<color>"; inherits: false; initial-value: #0000;}@property --tw-gradient-stops{syntax: "*"; inherits: false;}@property --tw-gradient-via-stops{syntax: "*"; inherits: false;}@property --tw-gradient-from-position{syntax: "<length-percentage>"; inherits: false; initial-value: 0%;}@property --tw-gradient-via-position{syntax: "<length-percentage>"; inherits: false; initial-value: 50%;}@property --tw-gradient-to-position{syntax: "<length-percentage>"; inherits: false; initial-value: 100%;}@property --tw-leading{syntax: "*"; inherits: false;}@property --tw-blur{syntax: "*"; inherits: false;}@property --tw-brightness{syntax: "*"; inherits: false;}@property --tw-contrast{syntax: "*"; inherits: false;}@property --tw-grayscale{syntax: "*"; inherits: false;}@property --tw-hue-rotate{syntax: "*"; inherits: false;}@property --tw-invert{syntax: "*"; inherits: false;}@property --tw-opacity{syntax: "*"; inherits: false;}@property --tw-saturate{syntax: "*"; inherits: false;}@property --tw-sepia{syntax: "*"; inherits: false;}@property --tw-drop-shadow{syntax: "*"; inherits: false;}@property --tw-drop-shadow-color{syntax: "*"; inherits: false;}@property --tw-drop-shadow-alpha{syntax: "<percentage>"; inherits: false; initial-value: 100%;}@property --tw-drop-shadow-size{syntax: "*"; inherits: false;}@property --tw-text-shadow-color{syntax: "*"; inherits: false;}@property --tw-text-shadow-alpha{syntax: "<percentage>"; inherits: false; initial-value: 100%;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x: 0;--tw-translate-y: 0;--tw-translate-z: 0;--tw-border-style: solid;--tw-gradient-position: initial;--tw-gradient-from: #0000;--tw-gradient-via: #0000;--tw-gradient-to: #0000;--tw-gradient-stops: initial;--tw-gradient-via-stops: initial;--tw-gradient-from-position: 0%;--tw-gradient-via-position: 50%;--tw-gradient-to-position: 100%;--tw-leading: initial;--tw-blur: initial;--tw-brightness: initial;--tw-contrast: initial;--tw-grayscale: initial;--tw-hue-rotate: initial;--tw-invert: initial;--tw-opacity: initial;--tw-saturate: initial;--tw-sepia: initial;--tw-drop-shadow: initial;--tw-drop-shadow-color: initial;--tw-drop-shadow-alpha: 100%;--tw-drop-shadow-size: initial;--tw-text-shadow-color: initial;--tw-text-shadow-alpha: 100%}}}
|
|
1
|
+
/*! tailwindcss v4.1.13 | MIT License | https://tailwindcss.com */@layer properties;@layer theme,base,components,utilities;@layer theme{:root,:host{--font-sans: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-stone-700: oklch(37.4% .01 67.558);--color-black: #000;--color-white: #fff;--spacing: .25rem;--text-xs: .75rem;--text-xs--line-height: calc(1 / .75);--text-sm: .875rem;--text-sm--line-height: calc(1.25 / .875);--text-3xl: 1.875rem;--text-3xl--line-height: 1.2 ;--default-font-family: var(--font-sans);--default-mono-font-family: var(--font-mono)}}@layer base{*,:after,:before,::backdrop,::file-selector-button{box-sizing:border-box;margin:0;padding:0;border:0 solid}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;tab-size:4;font-family:var(--default-font-family, ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings, normal);font-variation-settings:var(--default-font-variation-settings, normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings, normal);font-variation-settings:var(--default-mono-font-variation-settings, normal);font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea,::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;border-radius:0;background-color:transparent;opacity:1}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px){::placeholder{color:currentcolor;@supports (color: color-mix(in lab,red,red)){color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit,::-webkit-datetime-edit-year-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]),::file-selector-button{appearance:button}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer utilities{.absolute{position:absolute}.relative{position:relative}.inset-0{inset:calc(var(--spacing) * 0)}.top-0{top:calc(var(--spacing) * 0)}.top-\[3px\]{top:3px}.right-0{right:calc(var(--spacing) * 0)}.bottom-0{bottom:calc(var(--spacing) * 0)}.bottom-\[10px\]{bottom:10px}.left-1\/2{left:50%}.left-\[2px\]{left:2px}.z-1{z-index:1}.z-2{z-index:2}.col-1{grid-column:1}.col-2{grid-column:2}.col-3{grid-column:3}.col-4{grid-column:4}.col-5{grid-column:5}.col-6{grid-column:6}.col-start-1{grid-column-start:1}.col-end-3{grid-column-end:3}.row-1{grid-row:1}.row-2{grid-row:2}.row-3{grid-row:3}.row-4{grid-row:4}.row-span-2{grid-row:span 2 / span 2}.row-start-1{grid-row-start:1}.m-\[5px\]{margin:5px}.mx-\[5px\]{margin-inline:5px}.mx-\[10px\]{margin-inline:10px}.contents{display:contents}.flex{display:flex}.grid{display:grid}.aspect-\[11\/8\]{aspect-ratio:11/8}.size-\[36px\]{width:36px;height:36px}.h-\[2px\]{height:2px}.h-\[24px\]{height:24px}.h-\[44px\]{height:44px}.h-\[64px\]{height:64px}.h-\[100px\]{height:100px}.h-\[320px\]{height:320px}.h-full{height:100%}.w-\[10\%\]{width:10%}.w-\[16px\]{width:16px}.w-\[33px\]{width:33px}.w-\[36px\]{width:36px}.w-\[44px\]{width:44px}.w-\[64px\]{width:64px}.w-\[100px\]{width:100px}.w-\[790px\]{width:790px}.w-\[800px\]{width:800px}.w-auto{width:auto}.w-full{width:100%}.max-w-full{max-width:100%}.grow{flex-grow:1}.origin-top-right{transform-origin:100% 0}.-translate-x-1\/2{--tw-translate-x: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y)}.scale-\[0\.6\]{scale:.6}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-\[112px_1fr_100px\]{grid-template-columns:112px 1fr 100px}.grid-cols-\[repeat\(3\,3fr\)_2fr_3fr\]{grid-template-columns:repeat(3,3fr) 2fr 3fr}.grid-cols-\[repeat\(6\,3fr\)_10fr\]{grid-template-columns:repeat(6,3fr) 10fr}.grid-rows-2{grid-template-rows:repeat(2,minmax(0,1fr))}.grid-rows-4{grid-template-rows:repeat(4,minmax(0,1fr))}.grid-rows-\[63px_24px\]{grid-template-rows:63px 24px}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-end{align-items:flex-end}.justify-around{justify-content:space-around}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-evenly{justify-content:space-evenly}.gap-\[4px\]{gap:4px}.gap-\[5px\]{gap:5px}.gap-\[10px\]{gap:10px}.gap-\[12px\]{gap:12px}.gap-\[16px\]{gap:16px}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.overflow-hidden{overflow:hidden}.rounded-\[5px\]{border-radius:5px}.bg-black{background-color:var(--color-black)}.bg-black\/80{background-color:color-mix(in srgb,#000 80%,transparent);@supports (color: color-mix(in lab,red,red)){background-color:color-mix(in oklab,var(--color-black) 80%,transparent)}}.bg-stone-700\/50{background-color:color-mix(in srgb,oklch(37.4% .01 67.558) 50%,transparent);@supports (color: color-mix(in lab,red,red)){background-color:color-mix(in oklab,var(--color-stone-700) 50%,transparent)}}.bg-cover{background-size:cover}.object-contain{object-fit:contain}.object-cover{object-fit:cover}.px-\[2px\]{padding-inline:2px}.pl-\[10px\]{padding-left:10px}.text-center{text-align:center}.text-right{text-align:right}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading, var(--text-3xl--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading, var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading, var(--text-xs--line-height))}.text-\[10px\]{font-size:10px}.text-\[13px\]{font-size:13px}.leading-\[1\.5\]{--tw-leading: 1.5;line-height:1.5}.leading-\[1\.15\]{--tw-leading: 1.15;line-height:1.15}.leading-\[1\.25\]{--tw-leading: 1.25;line-height:1.25}.leading-\[1\]{--tw-leading: 1;line-height:1}.leading-\[24px\]{--tw-leading: 24px;line-height:24px}.whitespace-nowrap{white-space:nowrap}.text-\[\#ccc\]{color:#ccc}.text-\[rgb\(203\,176\,42\)\]{color:#cbb02a}.text-white{color:var(--color-white)}.opacity-75{opacity:75%}.grayscale{--tw-grayscale: grayscale(100%);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.text-shadow-\[-1px_1px_0_\#000\,1px_-1px_0_\#000\,-1px_1px_0_\#000\,1px_1px_0_\#000\]{text-shadow:-1px 1px 0 var(--tw-text-shadow-color, #000),1px -1px 0 var(--tw-text-shadow-color, #000),-1px 1px 0 var(--tw-text-shadow-color, #000),1px 1px 0 var(--tw-text-shadow-color, #000)}.text-shadow-\[-1px_1px_2px_\#000\,1px_-1px_2px_\#000\,-1px_1px_2px_\#000\,1px_1px_2px_\#000\]{text-shadow:-1px 1px 2px var(--tw-text-shadow-color, #000),1px -1px 2px var(--tw-text-shadow-color, #000),-1px 1px 2px var(--tw-text-shadow-color, #000),1px 1px 2px var(--tw-text-shadow-color, #000)}}@property --tw-translate-x{syntax: "*"; inherits: false; initial-value: 0;}@property --tw-translate-y{syntax: "*"; inherits: false; initial-value: 0;}@property --tw-translate-z{syntax: "*"; inherits: false; initial-value: 0;}@property --tw-leading{syntax: "*"; inherits: false;}@property --tw-blur{syntax: "*"; inherits: false;}@property --tw-brightness{syntax: "*"; inherits: false;}@property --tw-contrast{syntax: "*"; inherits: false;}@property --tw-grayscale{syntax: "*"; inherits: false;}@property --tw-hue-rotate{syntax: "*"; inherits: false;}@property --tw-invert{syntax: "*"; inherits: false;}@property --tw-opacity{syntax: "*"; inherits: false;}@property --tw-saturate{syntax: "*"; inherits: false;}@property --tw-sepia{syntax: "*"; inherits: false;}@property --tw-drop-shadow{syntax: "*"; inherits: false;}@property --tw-drop-shadow-color{syntax: "*"; inherits: false;}@property --tw-drop-shadow-alpha{syntax: "<percentage>"; inherits: false; initial-value: 100%;}@property --tw-drop-shadow-size{syntax: "*"; inherits: false;}@property --tw-text-shadow-color{syntax: "*"; inherits: false;}@property --tw-text-shadow-alpha{syntax: "<percentage>"; inherits: false; initial-value: 100%;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x: 0;--tw-translate-y: 0;--tw-translate-z: 0;--tw-leading: initial;--tw-blur: initial;--tw-brightness: initial;--tw-contrast: initial;--tw-grayscale: initial;--tw-hue-rotate: initial;--tw-invert: initial;--tw-opacity: initial;--tw-saturate: initial;--tw-sepia: initial;--tw-drop-shadow: initial;--tw-drop-shadow-color: initial;--tw-drop-shadow-alpha: 100%;--tw-drop-shadow-size: initial;--tw-text-shadow-color: initial;--tw-text-shadow-alpha: 100%}}}
|
|
@@ -1,13 +1,4 @@
|
|
|
1
|
-
<% const match = data; %> <% const partyColor = ["#caffe5","#ffe484","#e19be2","#ccdaf4"]; %> <% const
|
|
2
|
-
Red: "from-[#9f3c3c] to-[#4a2026]",
|
|
3
|
-
Yellow: "from-[#c8a45c] to-[#6f3d21]",
|
|
4
|
-
Green: "from-[#a2b23e] to-[#2d5a18]",
|
|
5
|
-
Blue: "from-[#547ea6] to-[#2a385e]",
|
|
6
|
-
Purple: "from-[#675cae] to-[#261c44]",
|
|
7
|
-
Gray: "from-[#adb6be] to-[#4e5557]",
|
|
8
|
-
Black: "from-[#2d2d2d] to-[#000000]"
|
|
9
|
-
};
|
|
10
|
-
%> <% const kc = (num) => { let red = (255 - (num * 255) / 100).toFixed(2); return `rgb(255,${red},${red})`; }; %> <% const dc = (num) => { let gray = ((50 - Math.min(num, 50)) * (255 / 50)).toFixed(2); return `rgb(${gray},${gray},${gray})`; }; %> <% const laneSVG = {
|
|
1
|
+
<% const match = data; %> <% const partyColor = ["#caffe5","#ffe484","#e19be2","#ccdaf4"]; %> <% const kc = (num) => { let red = (255 - (num * 255) / 100).toFixed(2); return `rgb(255,${red},${red})`; }; %> <% const dc = (num) => { let gray = ((50 - Math.min(num, 50)) * (255 / 50)).toFixed(2); return `rgb(${gray},${gray},${gray})`; }; %> <% const laneSVG = {
|
|
11
2
|
stomp: getImageUrl("lane_stomp", undefined, ImageFormat.svg),
|
|
12
3
|
advantage: getImageUrl("lane_victory", undefined, ImageFormat.svg),
|
|
13
4
|
disadvantage: getImageUrl("lane_fail", undefined, ImageFormat.svg),
|
|
@@ -15,4 +6,4 @@
|
|
|
15
6
|
tie: getImageUrl("lane_tie", undefined, ImageFormat.svg),
|
|
16
7
|
jungle: getImageUrl("lane_jungle", undefined, ImageFormat.svg),
|
|
17
8
|
};
|
|
18
|
-
%> <%- include("../common/utils/match") %> <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><title>Match</title> <%- `<style>` %> <%- include(`./match_1/base.css`) %> <%- include(`./match_1/style.css`) %> <%- `</style>` %> </head><body class="bg-black w-[800px] text-white"> <%- include(`./match_1/main.ejs`, { match, partyColor,
|
|
9
|
+
%> <%- include("../common/utils/match") %> <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><title>Match</title> <%- `<style>` %> <%- include(`./match_1/base.css`) %> <%- include(`./match_1/style.css`) %> <%- `</style>` %> </head><body class="bg-black w-[800px] text-white"> <%- include(`./match_1/main.ejs`, { match, partyColor, kc, dc, laneSVG }) %> </body></html>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
p{margin:0}img{width:100%;vertical-align:middle}html,body{overflow:hidden;width:800px}nav{font-size:14px;line-height:1.8;height:72px;color:#fff;background-color:#000;display:flex;flex-direction:row;justify-content:space-around;align-items:center}nav>div>p:first-of-type{font-weight:700}nav .match_id p:first-of-type{font-size:16px}nav>div.match_id>p.success:after{content:"\203b<%= $t('dota2tracker.template.analysis_successful') %>";color:#7ba334}nav>div.match_id>p.fail:after{content:"\203b<%= $t('dota2tracker.template.analysis_incomplete') %>";color:#ffb400}nav>div.match_id>p.opendota:after{content:"\203b<%= $t('dota2tracker.template.analysis_by_opendota') %>";color:#34a39a}nav>.rank{width:48px;height:48px;position:relative}nav>.rank>img{width:48px;height:48px;position:absolute}.radiant{color:#3c9028}.dire{color:#9c3628}.match_result{font-weight:700;height:49px;display:flex;justify-content:center;align-items:center}.match_result .win{margin:0 25px}.match_result .win.radiant:after{content:"<%=$t('dota2tracker.template.radiant_won')%>"}.match_result .win.dire:after{content:"<%=$t('dota2tracker.template.dire_won')%>"}.players{display:flex;flex-direction:column}.players .panel{padding:0 10px}.players .panel{padding-top:4px;height:40px;border-top:3px solid #fff;font-size:13.3px;display:grid;grid-template-columns:32px 56px 378px repeat(4,1fr)}.players .panel.radiant{border-color:#3c9028}.players .panel.dire{border-color:#9c3628}.players .panel p{line-height:16px;margin-left:8px}.players .panel .win{font-size:20px;line-height:32px}.players .panel .data{color:#aaa}.player:not(:last-child){border-bottom:1px solid #e1e1e1}.player{color:#000;width:100%;display:grid;grid-template-columns:64px 48px 88px 160px 112px 252px 36px 20px;grid-template-rows:19px 14px 14px 14px;padding-bottom:3px;font-size:12px;line-height:14px;overflow:hidden;justify-content:center}.player>.row-1{margin-top:6px}.player>.hero_avatar{margin-bottom:5px;width:64px;grid-row:1 / span 3;grid-column:1;position:relative}.player>.hero_avatar>.level{width:20px;height:15px;background-color:#323232;position:absolute;bottom:0;right:0;font-size:12px;line-height:15px;color:#fff;text-align:center}.player>.hero_avatar>.party_line{position:absolute;height:2px;top:0;width:100%}.player>.hero_avatar>.party_mark{position:absolute;line-height:1.5;text-align:center;width:16px;font-size:10px;top:3px;left:1px;background-color:#000c}.player>.hero_avatar.party_I>.party_line{background-color:#caffe5}.player>.hero_avatar.party_I>.party_mark{color:#caffe5}.player>.hero_avatar.party_I>.party_mark:after{content:"I"}.player>.hero_avatar.party_II>.party_line{background-color:#ffe484}.player>.hero_avatar.party_II>.party_mark{color:#ffe484}.player>.hero_avatar.party_II>.party_mark:after{content:"II"}.player>.hero_avatar.party_III>.party_line{background-color:#e19be2}.player>.hero_avatar.party_III>.party_mark{color:#e19be2}.player>.hero_avatar.party_III>.party_mark:after{content:"III"}.player>.hero_avatar.party_IV>.party_line{background-color:#ccdaf4}.player>.hero_avatar.party_IV>.party_mark{color:#ccdaf4}.player>.hero_avatar.party_IV>.party_mark:after{content:"IV"}.player>.facet{color:#fff;width:100%;height:16px;grid-row:4;grid-column:1;display:grid;grid-template-columns:16px auto;z-index:1;position:relative;top:-5px}.player>.facet>img{padding:2px;width:12px;height:12px;background-color:#4444}.player>.facet>span{padding:0 2px;line-height:1;display:grid;place-items:center;align-items:center;justify-content:center;height:100%}.player>.facet>span>*{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.player>.facet.Red{background:linear-gradient(to right,#9f3c3c,#4a2026)}.player>.facet.Yellow{background:linear-gradient(to right,#c8a45c,#6f3d21)}.player>.facet.Green{background:linear-gradient(to right,#a2b23e,#2d5a18)}.player>.facet.Blue{background:linear-gradient(to right,#547ea6,#2a385e)}.player>.facet.Purple{background:linear-gradient(to right,#675cae,#261c44)}.player>.facet.Gray{background:linear-gradient(to right,#adb6be,#4e5557)}.player>.facet.Black{background:linear-gradient(to right,#2d2d2d,#000);display:flex;justify-content:center}.player>.rank{position:relative;grid-row:1 / span 3;grid-column:2;width:48px;height:48px}.player>.rank>img{position:absolute}.player>.rank>p{position:absolute;width:100%;bottom:1.5px;text-align:center;font-size:8px;color:#fff;text-shadow:-1px -1px 0 #000,1px -1px 0 #000,-1px 1px 0 #000,1px 1px 0 #000}.player>.titles{grid-row:4;grid-column:
|
|
1
|
+
p{margin:0}img{width:100%;vertical-align:middle}html,body{overflow:hidden;width:800px}nav{font-size:14px;line-height:1.8;height:72px;color:#fff;background-color:#000;display:flex;flex-direction:row;justify-content:space-around;align-items:center}nav>div>p:first-of-type{font-weight:700}nav .match_id p:first-of-type{font-size:16px}nav>div.match_id>p.success:after{content:"\203b<%= $t('dota2tracker.template.analysis_successful') %>";color:#7ba334}nav>div.match_id>p.fail:after{content:"\203b<%= $t('dota2tracker.template.analysis_incomplete') %>";color:#ffb400}nav>div.match_id>p.opendota:after{content:"\203b<%= $t('dota2tracker.template.analysis_by_opendota') %>";color:#34a39a}nav>.rank{width:48px;height:48px;position:relative}nav>.rank>img{width:48px;height:48px;position:absolute}.radiant{color:#3c9028}.dire{color:#9c3628}.match_result{font-weight:700;height:49px;display:flex;justify-content:center;align-items:center}.match_result .win{margin:0 25px}.match_result .win.radiant:after{content:"<%=$t('dota2tracker.template.radiant_won')%>"}.match_result .win.dire:after{content:"<%=$t('dota2tracker.template.dire_won')%>"}.players{display:flex;flex-direction:column}.players .panel{padding:0 10px}.players .panel{padding-top:4px;height:40px;border-top:3px solid #fff;font-size:13.3px;display:grid;grid-template-columns:32px 56px 378px repeat(4,1fr)}.players .panel.radiant{border-color:#3c9028}.players .panel.dire{border-color:#9c3628}.players .panel p{line-height:16px;margin-left:8px}.players .panel .win{font-size:20px;line-height:32px}.players .panel .data{color:#aaa}.player:not(:last-child){border-bottom:1px solid #e1e1e1}.player{color:#000;width:100%;display:grid;grid-template-columns:64px 48px 88px 160px 112px 252px 36px 20px;grid-template-rows:19px 14px 14px 14px;padding-bottom:3px;font-size:12px;line-height:14px;overflow:hidden;justify-content:center}.player>.row-1{margin-top:6px}.player>.hero_avatar{margin-bottom:5px;width:64px;grid-row:1 / span 3;grid-column:1;position:relative}.player>.hero_avatar>.level{width:20px;height:15px;background-color:#323232;position:absolute;bottom:0;right:0;font-size:12px;line-height:15px;color:#fff;text-align:center}.player>.hero_avatar>.party_line{position:absolute;height:2px;top:0;width:100%}.player>.hero_avatar>.party_mark{position:absolute;line-height:1.5;text-align:center;width:16px;font-size:10px;top:3px;left:1px;background-color:#000c}.player>.hero_avatar.party_I>.party_line{background-color:#caffe5}.player>.hero_avatar.party_I>.party_mark{color:#caffe5}.player>.hero_avatar.party_I>.party_mark:after{content:"I"}.player>.hero_avatar.party_II>.party_line{background-color:#ffe484}.player>.hero_avatar.party_II>.party_mark{color:#ffe484}.player>.hero_avatar.party_II>.party_mark:after{content:"II"}.player>.hero_avatar.party_III>.party_line{background-color:#e19be2}.player>.hero_avatar.party_III>.party_mark{color:#e19be2}.player>.hero_avatar.party_III>.party_mark:after{content:"III"}.player>.hero_avatar.party_IV>.party_line{background-color:#ccdaf4}.player>.hero_avatar.party_IV>.party_mark{color:#ccdaf4}.player>.hero_avatar.party_IV>.party_mark:after{content:"IV"}.player>.facet{color:#fff;width:100%;height:16px;grid-row:4;grid-column:1;display:grid;grid-template-columns:16px auto;z-index:1;position:relative;top:-5px}.player>.facet>img{padding:2px;width:12px;height:12px;background-color:#4444}.player>.facet>span{padding:0 2px;line-height:1;display:grid;place-items:center;align-items:center;justify-content:center;height:100%}.player>.facet>span>*{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.player>.facet.Red{background:linear-gradient(to right,#9f3c3c,#4a2026)}.player>.facet.Yellow{background:linear-gradient(to right,#c8a45c,#6f3d21)}.player>.facet.Green{background:linear-gradient(to right,#a2b23e,#2d5a18)}.player>.facet.Blue{background:linear-gradient(to right,#547ea6,#2a385e)}.player>.facet.Purple{background:linear-gradient(to right,#675cae,#261c44)}.player>.facet.Gray{background:linear-gradient(to right,#adb6be,#4e5557)}.player>.facet.Black{background:linear-gradient(to right,#2d2d2d,#000);display:flex;justify-content:center}.player>.rank{position:relative;grid-row:1 / span 3;grid-column:2;width:48px;height:48px}.player>.rank>img{position:absolute}.player>.rank>p{position:absolute;width:100%;bottom:1.5px;text-align:center;font-size:8px;color:#fff;text-shadow:-1px -1px 0 #000,1px -1px 0 #000,-1px 1px 0 #000,1px 1px 0 #000}.player>.titles{grid-row:4;grid-column:1/4;margin-left:2px}.player>.player_name{grid-row:1;grid-column:3 / span 2;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.player>.player_name>.rank{color:#aaa}.player.radiant>.player_name>.name{color:#3c9028}.player.dire>.player_name>.name{color:#9c3628}.player .pick,.player .networth{grid-column:3}.player .networth .gold{color:#cbb02a;text-shadow:1px 1px 0 #000}.player .hero_damage{grid-row:2;grid-column:4}.player .damage_received{grid-row:3;grid-column:4}.player .tower_damage{grid-row:4;grid-column:4}.player .kda{grid-row:1;grid-column:5}.player .kill_contribution{grid-row:2;grid-column:5}.player .stun_duration{grid-row:3;grid-column:5}.player .heal{grid-row:4;grid-column:5}.player .items{grid-row:1 / span 4;grid-column:6;display:grid;grid-template-columns:24px 192px auto;grid-template-rows:32px 24px}.player .items>div{display:flex;background-color:silver}.player .items .normal{height:32px;grid-column:1/-1;grid-row:1}.player .items .backpack{height:24px;width:96px;grid-row:2}.player .items .normal .item{width:40px;height:30px;margin:1px;position:relative}.player .items .time{position:absolute;width:100%;text-align:center;bottom:0;height:11px;line-height:11px;color:#ccc;background-color:#323232}.player .items .backpack{filter:grayscale(100%)}.player .items .backpack .item,.player .items .bear .item{width:30px;height:22px;margin:1px;position:relative}.player .neutral_item{grid-row:1 / span 3;grid-column:7;overflow:hidden;height:32px;width:32px;border-radius:50%;background-size:auto 100%;background-position:center;margin-left:2px}.player .items .item.recipe{background-image:url(https://cdn.cloudflare.steamstatic.com/apps/dota2/images/dota_react/items/recipe.png);background-size:100%}.player .ahgs{grid-row:1 / span 3;grid-column:8}.player .items .bear{height:24px;width:192px;grid-row:2;grid-column:2}.player.bear .items .bear .time{font-size:10px}.player.bear .items .bear_icon{grid-row:2;grid-column:1}.player.bear .items .neutral_item{height:24px;width:24px;grid-row:2;grid-column:3}
|
|
@@ -7,4 +7,4 @@
|
|
|
7
7
|
const b = Math.max(0, (num & 0x0000FF) - Math.round(2.55 * amt));
|
|
8
8
|
return `#${(0x1000000 + (r << 16) + (g << 8) + b).toString(16).slice(1)}`;
|
|
9
9
|
};
|
|
10
|
-
%> <% const
|
|
10
|
+
%> <% const startTime = DateTime.fromSeconds(match.startDateTime).toFormat("yyyy-MM-dd HH:mm:ss").slice(2); %> <% const regionName = $t("dota2tracker.template.regions." + match.regionId); %> <% const modeName = ($t("dota2tracker.template.lobby_types." + match.lobbyType) || match.lobbyType) + "/" + ($t("dota2tracker.template.game_modes." + match.gameMode) || match.gameMode); %> <% const statusClass = match.odParsed ? "opendota" : (match.parsedDateTime ? "success" : "fail"); %> <% const rankStyle = (match.odParsed && match.lobbyType !== "RANKED") ? "filter:grayscale(1)" : ""; %> <%- include("../../common/utils/match") %> <nav><div class="match_id"><p><%= $t("dota2tracker.template.match_id_").slice(0, -1) %> <%- match.id %></p><p class="<%= statusClass %>"></p></div><div class="start_time"><p><%= $t("dota2tracker.template.start_time_").slice(0, -1) %></p><p><%- startTime %></p></div><div class="duration"><p><%= $t("dota2tracker.template.duration_").slice(0, -1) %></p><p><%- match.durationTime %></p></div><div class="region"><p><%= $t("dota2tracker.template.region_").slice(0, -1) %></p><p><%- regionName %></p></div><div class="mode"><p><%= $t("dota2tracker.template.game_mode_").slice(0, -1) %></p><p><%- modeName %></p></div><div class="rank" <%- `style="${rankStyle}"` %>><img src="<%- getImageUrl('medal_' + (match.rank?.toString().split('')[0] ?? '0')) %>" alt=""/> <img style="z-index:1" src="<%- getImageUrl('star_' + (match.rank?.toString().split('')[1] ?? '0')) %>" alt=""/></div></nav><section class="match_result"><span class="kills radiant"><%- match.radiant.killsCount %></span><span class="win <%- match.didRadiantWin ? 'radiant' : 'dire' %>"></span> <span class="kills dire"><%- match.dire.killsCount %></span></section><section class="players"> <% ['radiant', 'dire'].forEach(team => { %> <% const isRadiant = team === 'radiant'; %> <% const teamData = match[team]; %> <% const orderStyle = `order: ${isRadiant ? 0 : 50}`; %> <% const teamName = isRadiant ? ['Radiant', '天辉'] : ['Dire', '夜魇']; %> <% const showWin = (isRadiant === match.didRadiantWin); %> <section class="panel <%= team %>" <%- `style="${orderStyle}"` %>><img src="<%- getImageUrl('logo_' + team) %>"><p><%- teamName.join('<br>') %></p> <% if (showWin) { %> <p class="win"><%= $t('dota2tracker.template.won') %></p> <% } else { %> <p></p> <% } %> <p class="data"><%= $t('dota2tracker.template.kill') %><br><%= teamData.killsCount %></p><p class="data"><%= $t('dota2tracker.template.total_damage') %><br><%= teamData.heroDamage %></p><p class="data"><%= $t('dota2tracker.template.total_gold') %><br><%= teamData.networth %></p><p class="data"><%= $t('dota2tracker.template.total_experience') %><br><%= teamData.experience %></p></section> <% }); %> <% match.players.forEach(p => { %> <% const isBear = p.hero.id == 80; %> <% const orderStyle = `order: ${p.team === 'radiant' ? 1 : 100}`; %> <% const partyClass = p.partyId != null ? ' party_' + match.party[p.partyId] : ''; %> <% const teamTotalDmg = match[p.team].heroDamage || 1; %> <% const teamTotalTaken = match[p.team].damageReceived || 1; %> <% const dmgPct = (p.heroDamage / teamTotalDmg * 100).toFixed(2); %> <% const takenPct = (p.damageReceived / teamTotalTaken * 100).toFixed(2); %> <% const kdaVal = ((p.kills + p.assists) / (p.deaths || 1)).toFixed(2); %> <% const kcVal = (p.killContribution * 100).toFixed(2); %> <% const stunVal = ((p.stats.heroDamageReport?.dealtTotal.stunDuration ?? 0) / 100).toFixed(2); %> <% const pBuffs = p.stats?.matchPlayerBuffEvent || []; %> <% const hasAghs = p.items.some(i => i?.id == 108) || p.backpacks.some(i => i?.id == 108) || pBuffs.some(b => b.itemId == 108); %> <% const hasShard = pBuffs.some(b => b.itemId == 609); %> <div class="player <%= p.team %><%= isBear ? ' bear' : '' %>" <%- `style="${orderStyle}"` %>><div class="hero_avatar row-1<%= partyClass %>"><img src="<%- getImageUrl(p.hero.shortName, ImageType.Heroes) %>"/><p class="level"><%= p.level %></p><p class="party_line"></p><p class="party_mark"></p></div><div class="rank"><img src="<%- getImageUrl('medal_' + (p.rank.inTop100 ?? p.rank.medal)) %>" class="medal"/> <img src="<%- getImageUrl('star_' + p.rank.star) %>" class="stars"/><p><%= p.steamAccount.seasonLeaderboardRank ?? '' %></p></div><div class="titles"> <% p.titles.forEach(item => { %> <% const title = parseBadge(item, $t); %> <span <%- `style="color: ${darken(title.color, 25)};"` %>><%= title.shortText %></span> <% }); %> </div><div class="player_name row-1"><span class="rank">[<%= $t('dota2tracker.template.ranks.' + p.rank.medal) %><%= p.rank.star || '' %>]</span> <span class="name"><%= p.steamAccount.name %></span></div><p class="pick"> <%- p.isRandom ? $t('dota2tracker.template.random') : $t('dota2tracker.template.pick_order', [p.order == null ? '?' : p.order + 1]) %> <%= $t('dota2tracker.template.position_' + p.position?.slice(-1)) ?? '' %> </p><p class="networth"><span class="gold"><%= p.formattedNetworth %></span>(<%= (p.heroDamage / p.networth)?.toFixed(2) %>)</p><p class="hero_damage"> <%= $t('dota2tracker.template.hero_damage_') %><%= p.heroDamage %> (<%= dmgPct %>%)</p><p class="damage_received"> <%= $t('dota2tracker.template.damage_received_') %><%= p.damageReceived %> (<%= takenPct %>%)</p><p class="tower_damage"> <%= $t('dota2tracker.template.building_damage_') %><%= p.towerDamage %> </p><p class="kda row-1"> <%= p.kills %>/<%= p.deaths %>/<%= p.assists %> (<%= kdaVal %>)</p><p class="kill_contribution"> <%= $t('dota2tracker.template.kill_contribution_') %><%= kcVal %>%</p><p class="stun_duration"> <%= $t('dota2tracker.template.crowd_control_duration_') %> <%= stunVal %>s</p><p class="heal"> <%= $t('dota2tracker.template.heal_') %><%= p.heroHealing %> </p><div class="items row-1"><div class="normal"> <% p.items.forEach(item => { %> <div class="item<%= item?.isRecipe ? ' recipe' : '' %>" data-id="<%= item?.id ?? 0 %>"><img src="<%- item ? getImageUrl(item.name, ImageType.Items) : '' %>" alt=""/> <% if (item) { %> <p class="time"><%= item.time %></p> <% } %> </div> <% }); %> </div> <% if (!isBear) { %> <div class="backpack"> <% p.backpacks.forEach(item => { %> <div class="item<%= item?.isRecipe ? ' recipe' : '' %>"><img src="<%- item ? getImageUrl(item.name, ImageType.Items) : '' %>" alt=""/></div> <% }); %> </div> <% } else { %> <img class="bear_icon" src="<%- getImageUrl('lone_druid_spirit_bear', ImageType.Abilities) %>" alt=""><div class="bear"> <% p.unitItems.forEach(item => { %> <div class="item<%= item?.isRecipe ? ' recipe' : '' %>" data-id="<%= item?.id ?? 0 %>"><img src="<%- item ? getImageUrl(item.name, ImageType.Items) : '' %>" alt=""/> <% if (item) { %> <p class="time"><%= item.time %></p> <% } %> </div> <% }); %> </div><div class="neutral_item" <%- `style="background-image: url(${getImageUrl(dotaconstants.item_ids[p.additionalUnit.neutral0Id], ImageType.Items)})"` %>></div> <% } %> </div><div class="neutral_item row-1" <%- `style="background-image: url(${getImageUrl(dotaconstants.item_ids[p.neutral0Id], ImageType.Items)})"` %>></div><div class="ahgs row-1"><img src="<%- getImageUrl('scepter_' + (hasAghs ? 1 : 0)) %>" alt=""/> <img src="<%- getImageUrl('shard_' + (hasShard ? 1 : 0)) %>" alt=""/></div></div> <% }); %> </section>
|
|
@@ -75,4 +75,4 @@
|
|
|
75
75
|
const impAvg = posMatches.length > 0 ? Math.round(posMatches.reduce((acc, m) => acc + m.players.find(ip => ip.steamAccount.id == p.steamAccount.id).imp, 0) / posMatches.length) : "-";
|
|
76
76
|
p.positionPerformance.push({ pos: i + 1, icon: posIcons[i], matchCount: posMatches.length, winCount: wins, imp: impAvg });
|
|
77
77
|
}
|
|
78
|
-
%> <% const posScale = getScale(p.positionPerformance.filter(pos => pos.matchCount > 1), true); %> <!DOCTYPE html><html lang="<%= languageTag %>"><head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><title>Player</title> <%- `<style>` %> <%- include("../common/styles/normalize.min.css") %> <%- include(`./player_1/base.css`) %> <%- `</style>` %> </head><body><div class="wrapper"><div class="player"><div class="avatar"><img src="<%= p.steamAccount?.avatar %>" alt=""/></div><div class="info"><p class="name"> <%= p.steamAccount.name %> <% if (p.guildMember) { %> <span class="guild <%= getGuildClass(p.guildMember.guild.currentPercentile) %>"><%= p.guildMember.guild.tag %></span> <% } %> <% if (p.genHero) { %> <span class="hero_name"><%= p.genHero.name %></span> <% } %> </p><p class="matches"> <%= $t("dota2tracker.template.match_count_") %><%= p.matchCount %> (<span class="win"><%= p.winCount %></span>/<span class="lose"><%= p.matchCount - p.winCount %></span>) <%= $t("dota2tracker.template.winrate_") %> <span <%- `style="color:${getWinRateColor(p.winCount / p.matchCount)};"` %>><%= ((p.winCount / p.matchCount) * 100).toFixed(2) %>%</span></p><p class="matches<%= isAnon ? " blur" : "" %>"><span><%= $t("dota2tracker.template.last25matches_") %> <span class="win"><%= nearWin %></span>/<span class="lose"><%= nearCount - nearWin %></span></span> <span><%= $t("dota2tracker.template.winrate_") %> <span <%- `style="color:${getWinRateColor(nearWin / nearCount)};"` %>><%= ((nearWin / nearCount) * 100).toFixed(2) %>%</span> </span> <span><%= $t("dota2tracker.template.imp_") %><%= isAnon ? "?" : ((p.performance?.imp > 0 ? "+" : "") + p.performance?.imp) %></span></p><p class="matches<%= isAnon ? " blur" : "" %>"><span><%= $t("dota2tracker.template.lane") %> <span class="victory"><%= outcomes.victory + outcomes.stomp %>(<span class="stomp"><%= outcomes.stomp %></span>)</span>-<span class="tie"><%= outcomes.tie %></span>-<span class="fail"><%= outcomes.fail + outcomes.stomped %>(<span class="stomped"><%= outcomes.stomped %></span>)</span> </span> <% const laneTotal = outcomes.victory + outcomes.stomp + outcomes.tie + outcomes.fail + outcomes.stomped; %> <% const laneScore = (outcomes.victory + outcomes.stomp + outcomes.tie / 2) / laneTotal; %> <span><%= $t("dota2tracker.template.lane_advantage_rate_") %> <span <%- `style="color:${getWinRateColor(laneScore)};"` %>><%= isAnon ? "?" : (laneScore * 100).toFixed(2) %>%</span></span></p></div><div class="rank<%= p.isEstimatedRank ? " estimated" : "" %>"><img class="medal" src="<%= getImageUrl('medal_' + (p.rank.inTop100 ?? p.rank.medal)) %>" alt=""/> <img class="star" src="<%= getImageUrl('star_' + p.rank.star) %>" alt=""/><p><%= p.steamAccount.seasonLeaderboardRank ?? "" %></p></div></div><div class="hero_winrate"><div class="heroes"><p class="tip row total"><%= p.genHero ? $t("dota2tracker.template.all_matches_") : $t("dota2tracker.template.top10_") %></p><span class="tip"><%= $t("dota2tracker.template.hero") %></span><span class="tip" style="margin:0 4px"><%= $t("dota2tracker.template.match_count") %></span><span class="tip" style="margin:0 4px"><%= $t("dota2tracker.template.winrate") %></span><span class="tip" style="margin:0 4px"><%= $t("dota2tracker.template.imp") %></span><span class="tip win_count" style="justify-self:end;margin-right:2px"><%= $t("dota2tracker.template.win_count") %></span><span class="tip lose_count" style="justify-self:start;margin-left:2px"><%= $t("dota2tracker.template.lose_count") %></span> <% heroList.forEach(hero => { %> <span><img alt="" src="<%= getImageUrl(hero.hero.shortName, ImageType.HeroIcons) %>"/></span><span class="count"><%= hero.matchCount %></span><span class="win_rate"><%= ((hero.winCount / hero.matchCount) * 100).toFixed(0) %>%</span> <span class="imp"><%= (hero.imp > 0 ? "+" : "") + hero.imp %></span><span class="win" <%- `style="${hero.winCount == 0 ? "visibility:hidden;" : ""}width: ${hero.winCount * heroScale}px"` %>><%= hero.winCount %></span><span class="lose" <%- `style="${hero.matchCount - hero.winCount == 0 ? "visibility:hidden;" : ""}width: ${(hero.matchCount - hero.winCount) * heroScale}px"` %>><%= hero.matchCount - hero.winCount %></span> <% }); %> <p class="tip row near"><%= $t("dota2tracker.template.recently_positions") %></p><span class="tip"><%= $t("dota2tracker.template.position") %></span><span class="tip" style="margin:0 4px"><%= $t("dota2tracker.template.match_count") %></span><span class="tip" style="margin:0 4px"><%= $t("dota2tracker.template.winrate") %></span><span class="tip" style="margin:0 4px"><%= $t("dota2tracker.template.imp") %></span><span class="tip win_count" style="justify-self:end;margin-right:2px"><%= $t("dota2tracker.template.win_count") %></span><span class="tip lose_count" style="justify-self:start;margin-left:2px"><%= $t("dota2tracker.template.lose_count") %></span> <% p.positionPerformance.forEach(pos => { %> <span><img src="<%= getImageUrl(pos.icon, ImageType.IconsFacets) %>"></span><span class="count"><%= pos.matchCount %></span><span class="win_rate"><%= pos.matchCount > 0 ? ((pos.winCount / pos.matchCount) * 100).toFixed(0) : "-" %>%</span> <span class="imp"><%= (pos.imp > 0 ? "+" : "") + pos.imp %></span><span class="win" <%- `style="${pos.winCount == 0 ? "visibility:hidden;" : ""}width: ${pos.winCount * posScale}px"` %>><%= pos.winCount %></span><span class="lose" <%- `style="${pos.matchCount - pos.winCount == 0 ? "visibility:hidden;" : ""}width: ${(pos.matchCount - pos.winCount) * posScale}px"` %>><%= pos.matchCount - pos.winCount %></span> <% }); %> </div> <% if (isAnon) { %> <%- include("player_1/private", {$t, player: p}) %> <% } %> </div> <% if (Math.abs(p.streak) > 1 && !isAnon) { %> <div class="streak" <%- `style="box-shadow:none;color:${getWinRateColor((p.streak + 10) / 20)};"` %>> <%= Math.abs(p.streak) + (p.streak > 0 ? $t("dota2tracker.template.winning_streak") : $t("dota2tracker.template.losing_streak")) %> </div> <% } %> <div><table class="matches"><colgroup><col style="width:auto"/><col style="width:auto"/><col style="width:40px"/><col style="width:auto"/><col style="width:40px"/><col style="width:auto"/><col style="width:auto"/><col style="width:auto"/><col style="width:40px"/></colgroup><thead><tr><th><%= $t("dota2tracker.template.id") %></th><th><%= $t("dota2tracker.template.mode") %></th><th><%= $t("dota2tracker.template.hero") %></th><th><%= $t("dota2tracker.template.kda_kc") %></th><th><%= $t("dota2tracker.template.lane") %></th><th><%= $t("dota2tracker.template.time") %></th><th><%= $t("dota2tracker.template.duration") %></th><th><%= $t("dota2tracker.template.imp") %></th><th><%= $t("dota2tracker.template.rank") %></th></tr></thead><tbody> <% matchesData.forEach(m => { %> <tr class="match <%= m.didWin ? "win" : "lose" %>"><td><%- m.parsedDateTime ? m.id : `<p>${m.id}</p><p>${$t("dota2tracker.template.un_parsed")}</p>` %></td><td><p><%= $t("dota2tracker.template.lobby_types." + m.lobbyType) || m.lobbyType %></p><p><%= $t("dota2tracker.template.game_modes." + m.gameMode) || m.gameMode %></p></td><td><img alt="" src="<%= getImageUrl(m.inner.hero.shortName, ImageType.HeroIcons) %>"/></td><td style="line-height:20px"><p><%= m.kda %> (<%= (m.parsedDateTime ? "" : "≈") + m.kp %>%)</p><p><%= m.inner.kills %>/<%= m.inner.deaths %>/<%= m.inner.assists %></p></td><td><div class="player_lane <%= m.laneRes %>"
|
|
78
|
+
%> <% const posScale = getScale(p.positionPerformance.filter(pos => pos.matchCount > 1), true); %> <!DOCTYPE html><html lang="<%= languageTag %>"><head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><title>Player</title> <%- `<style>` %> <%- include("../common/styles/normalize.min.css") %> <%- include(`./player_1/base.css`) %> <%- `</style>` %> </head><body><div class="wrapper"><div class="player"><div class="avatar"><img src="<%= p.steamAccount?.avatar %>" alt=""/></div><div class="info"><p class="name"> <%= p.steamAccount.name %> <% if (p.guildMember) { %> <span class="guild <%= getGuildClass(p.guildMember.guild.currentPercentile) %>"><%= p.guildMember.guild.tag %></span> <% } %> <% if (p.genHero) { %> <span class="hero_name"><%= p.genHero.name %></span> <% } %> </p><p class="matches"> <%= $t("dota2tracker.template.match_count_") %><%= p.matchCount %> (<span class="win"><%= p.winCount %></span>/<span class="lose"><%= p.matchCount - p.winCount %></span>) <%= $t("dota2tracker.template.winrate_") %> <span <%- `style="color:${getWinRateColor(p.winCount / p.matchCount)};"` %>><%= ((p.winCount / p.matchCount) * 100).toFixed(2) %>%</span></p><p class="matches<%= isAnon ? " blur" : "" %>"><span><%= $t("dota2tracker.template.last25matches_") %> <span class="win"><%= nearWin %></span>/<span class="lose"><%= nearCount - nearWin %></span></span> <span><%= $t("dota2tracker.template.winrate_") %> <span <%- `style="color:${getWinRateColor(nearWin / nearCount)};"` %>><%= ((nearWin / nearCount) * 100).toFixed(2) %>%</span> </span> <span><%= $t("dota2tracker.template.imp_") %><%= isAnon ? "?" : ((p.performance?.imp > 0 ? "+" : "") + p.performance?.imp) %></span></p><p class="matches<%= isAnon ? " blur" : "" %>"><span><%= $t("dota2tracker.template.lane") %> <span class="victory"><%= outcomes.victory + outcomes.stomp %>(<span class="stomp"><%= outcomes.stomp %></span>)</span>-<span class="tie"><%= outcomes.tie %></span>-<span class="fail"><%= outcomes.fail + outcomes.stomped %>(<span class="stomped"><%= outcomes.stomped %></span>)</span> </span> <% const laneTotal = outcomes.victory + outcomes.stomp + outcomes.tie + outcomes.fail + outcomes.stomped; %> <% const laneScore = (outcomes.victory + outcomes.stomp + outcomes.tie / 2) / laneTotal; %> <span><%= $t("dota2tracker.template.lane_advantage_rate_") %> <span <%- `style="color:${getWinRateColor(laneScore)};"` %>><%= isAnon ? "?" : (laneScore * 100).toFixed(2) %>%</span></span></p></div><div class="rank<%= p.isEstimatedRank ? " estimated" : "" %>"><img class="medal" src="<%= getImageUrl('medal_' + (p.rank.inTop100 ?? p.rank.medal)) %>" alt=""/> <img class="star" src="<%= getImageUrl('star_' + p.rank.star) %>" alt=""/><p><%= p.steamAccount.seasonLeaderboardRank ?? "" %></p></div></div><div class="hero_winrate"><div class="heroes"><p class="tip row total"><%= p.genHero ? $t("dota2tracker.template.all_matches_") : $t("dota2tracker.template.top10_") %></p><span class="tip"><%= $t("dota2tracker.template.hero") %></span><span class="tip" style="margin:0 4px"><%= $t("dota2tracker.template.match_count") %></span><span class="tip" style="margin:0 4px"><%= $t("dota2tracker.template.winrate") %></span><span class="tip" style="margin:0 4px"><%= $t("dota2tracker.template.imp") %></span><span class="tip win_count" style="justify-self:end;margin-right:2px"><%= $t("dota2tracker.template.win_count") %></span><span class="tip lose_count" style="justify-self:start;margin-left:2px"><%= $t("dota2tracker.template.lose_count") %></span> <% heroList.forEach(hero => { %> <span><img alt="" src="<%= getImageUrl(hero.hero.shortName, ImageType.HeroIcons) %>"/></span><span class="count"><%= hero.matchCount %></span><span class="win_rate"><%= ((hero.winCount / hero.matchCount) * 100).toFixed(0) %>%</span> <span class="imp"><%= (hero.imp > 0 ? "+" : "") + hero.imp %></span><span class="win" <%- `style="${hero.winCount == 0 ? "visibility:hidden;" : ""}width: ${hero.winCount * heroScale}px"` %>><%= hero.winCount %></span><span class="lose" <%- `style="${hero.matchCount - hero.winCount == 0 ? "visibility:hidden;" : ""}width: ${(hero.matchCount - hero.winCount) * heroScale}px"` %>><%= hero.matchCount - hero.winCount %></span> <% }); %> <p class="tip row near"><%= $t("dota2tracker.template.recently_positions") %></p><span class="tip"><%= $t("dota2tracker.template.position") %></span><span class="tip" style="margin:0 4px"><%= $t("dota2tracker.template.match_count") %></span><span class="tip" style="margin:0 4px"><%= $t("dota2tracker.template.winrate") %></span><span class="tip" style="margin:0 4px"><%= $t("dota2tracker.template.imp") %></span><span class="tip win_count" style="justify-self:end;margin-right:2px"><%= $t("dota2tracker.template.win_count") %></span><span class="tip lose_count" style="justify-self:start;margin-left:2px"><%= $t("dota2tracker.template.lose_count") %></span> <% p.positionPerformance.forEach(pos => { %> <span><img src="<%= getImageUrl(pos.icon, ImageType.IconsFacets) %>"></span><span class="count"><%= pos.matchCount %></span><span class="win_rate"><%= pos.matchCount > 0 ? ((pos.winCount / pos.matchCount) * 100).toFixed(0) : "-" %>%</span> <span class="imp"><%= (pos.imp > 0 ? "+" : "") + pos.imp %></span><span class="win" <%- `style="${pos.winCount == 0 ? "visibility:hidden;" : ""}width: ${pos.winCount * posScale}px"` %>><%= pos.winCount %></span><span class="lose" <%- `style="${pos.matchCount - pos.winCount == 0 ? "visibility:hidden;" : ""}width: ${(pos.matchCount - pos.winCount) * posScale}px"` %>><%= pos.matchCount - pos.winCount %></span> <% }); %> </div> <% if (isAnon) { %> <%- include("player_1/private", {$t, player: p}) %> <% } %> </div> <% if (Math.abs(p.streak) > 1 && !isAnon) { %> <div class="streak" <%- `style="box-shadow:none;color:${getWinRateColor((p.streak + 10) / 20)};"` %>> <%= Math.abs(p.streak) + (p.streak > 0 ? $t("dota2tracker.template.winning_streak") : $t("dota2tracker.template.losing_streak")) %> </div> <% } %> <div><table class="matches"><colgroup><col style="width:auto"/><col style="width:auto"/><col style="width:40px"/><col style="width:auto"/><col style="width:40px"/><col style="width:auto"/><col style="width:auto"/><col style="width:auto"/><col style="width:40px"/></colgroup><thead><tr><th><%= $t("dota2tracker.template.id") %></th><th><%= $t("dota2tracker.template.mode") %></th><th><%= $t("dota2tracker.template.hero") %></th><th><%= $t("dota2tracker.template.kda_kc") %></th><th><%= $t("dota2tracker.template.lane") %></th><th><%= $t("dota2tracker.template.time") %></th><th><%= $t("dota2tracker.template.duration") %></th><th><%= $t("dota2tracker.template.imp") %></th><th><%= $t("dota2tracker.template.rank") %></th></tr></thead><tbody> <% matchesData.forEach(m => { %> <tr class="match <%= m.didWin ? "win" : "lose" %>"><td><%- m.parsedDateTime ? m.id : `<p>${m.id}</p><p>${$t("dota2tracker.template.un_parsed")}</p>` %></td><td><p><%= $t("dota2tracker.template.lobby_types." + m.lobbyType) || m.lobbyType %></p><p><%= $t("dota2tracker.template.game_modes." + m.gameMode) || m.gameMode %></p></td><td><img alt="" src="<%= getImageUrl(m.inner.hero.shortName, ImageType.HeroIcons) %>"/></td><td style="line-height:20px"><p><%= m.kda %> (<%= (m.parsedDateTime ? "" : "≈") + m.kp %>%)</p><p><%= m.inner.kills %>/<%= m.inner.deaths %>/<%= m.inner.assists %></p></td><td><div class="player_lane <%= m.laneRes %>"><img src="<%- getImageUrl("lane_" + m.laneRes, undefined, ImageFormat.svg) %>"/></div></td><td style="line-height:20px"><%= m.timeStr %></td><td><%= m.durationTime %></td><td><%= m.inner.imp != null ? ((m.inner.imp >= 0 ? "+" : "") + m.inner.imp) : "?" %></td><td><img class="medal" src="<%= getImageUrl("medal_" + m.rank?.toString().split("")[0]) %>" style="width:100%"/></td></tr> <% }); %> </tbody></table> <% if (isAnon) { %> <%- include("player_1/private", {$t, player: p}) %> <% } %> </div><div class="plus"> <% p.dotaPlus.forEach(hero => { %> <div class="hero"><img src="<%= getImageUrl(hero.shortName, ImageType.Heroes) %>" alt=""/><div class="level"><img src="<%= getImageUrl("hero_badge_" + Math.ceil((hero.level + 1) / 6)) %>" alt=""/><span><%= hero.level %></span></div><span><%= ((hero.winCount / hero.matchCount) * 100).toFixed(2) %>%</span> <span><%= hero.matchCount %></span></div> <% }); %> <% if (isAnon) { %> <%- include("player_1/private", {$t, player: p}) %> <% } %> </div></div></body></html>
|
package/package.json
CHANGED