@sjtdev/koishi-plugin-dota2tracker 2.3.4 → 2.5.0
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 +32 -0
- package/lib/index.js +677 -146
- package/lib/queries/PlayersMatchesForDaily.graphql +5 -0
- package/lib/queries/PlayersMatchesForDaily_legacy.graphql +25 -0
- package/lib/templates/common/utils/match.ejs +37 -0
- package/lib/templates/hero/hero_1.ejs +1 -1
- package/lib/templates/match/match_1/player.ejs +1 -1
- package/lib/templates/match/match_1.ejs +1 -1
- package/lib/templates/match/match_2/original.ejs +1 -1
- package/lib/templates/report/daily/style.css +1 -0
- package/lib/templates/report/daily/theme.css +1 -0
- package/lib/templates/report/daily.ejs +7 -21
- package/lib/templates/report/daily_legacy.ejs +21 -0
- package/package.json +5 -8
- /package/lib/templates/report/{daily → daily_legacy}/base.css +0 -0
|
@@ -10,12 +10,17 @@ query PlayersMatchesForDaily($steamAccountIds: [Long]!, $seconds: Long!) {
|
|
|
10
10
|
didRadiantWin
|
|
11
11
|
parsedDateTime
|
|
12
12
|
startDateTime
|
|
13
|
+
durationSeconds
|
|
13
14
|
players {
|
|
15
|
+
heroId
|
|
14
16
|
kills
|
|
15
17
|
deaths
|
|
16
18
|
assists
|
|
17
19
|
imp
|
|
18
20
|
isRadiant
|
|
21
|
+
heroDamage
|
|
22
|
+
towerDamage
|
|
23
|
+
networth
|
|
19
24
|
steamAccount {
|
|
20
25
|
id
|
|
21
26
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
query PlayersMatchesForDaily_Legacy($steamAccountIds: [Long]!, $seconds: Long!) {
|
|
2
|
+
players(steamAccountIds: $steamAccountIds) {
|
|
3
|
+
steamAccount {
|
|
4
|
+
id
|
|
5
|
+
name
|
|
6
|
+
avatar
|
|
7
|
+
}
|
|
8
|
+
matches(request: { startDateTime: $seconds, take: 50 }) {
|
|
9
|
+
id
|
|
10
|
+
didRadiantWin
|
|
11
|
+
parsedDateTime
|
|
12
|
+
startDateTime
|
|
13
|
+
players {
|
|
14
|
+
kills
|
|
15
|
+
deaths
|
|
16
|
+
assists
|
|
17
|
+
imp
|
|
18
|
+
isRadiant
|
|
19
|
+
steamAccount {
|
|
20
|
+
id
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
<%
|
|
2
|
+
/**
|
|
3
|
+
* 智能解析称号徽章
|
|
4
|
+
*/
|
|
5
|
+
parseBadge = function(key, $t) {
|
|
6
|
+
// 1. 获取翻译内容 "富-#FFD700"
|
|
7
|
+
const rawTranslation = $t(key);
|
|
8
|
+
|
|
9
|
+
// 2. 分割颜色
|
|
10
|
+
const parts = rawTranslation.split('-#');
|
|
11
|
+
const text = parts[0];
|
|
12
|
+
const color = parts.length > 1 ? '#' + parts[1] : '#9CA3AF';
|
|
13
|
+
|
|
14
|
+
// 3. 提取 Key 后缀
|
|
15
|
+
const keySuffix = key.split('.').pop() || '';
|
|
16
|
+
|
|
17
|
+
// 4. 白名单 (核心称号不缩写)
|
|
18
|
+
const FORCE_FULL = ['MVP', 'Soul'];
|
|
19
|
+
|
|
20
|
+
// 5. 生成短文本 (战报逻辑)
|
|
21
|
+
let shortText = text;
|
|
22
|
+
|
|
23
|
+
// 逻辑:不是核心称号 && 纯英文 && 长度 > 3 -> 缩写
|
|
24
|
+
if (!FORCE_FULL.includes(keySuffix) &&
|
|
25
|
+
/^[A-Za-z0-9]+$/.test(text) &&
|
|
26
|
+
text.length > 3) {
|
|
27
|
+
shortText = text.charAt(0).toUpperCase();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
fullText: text,
|
|
32
|
+
shortText: shortText,
|
|
33
|
+
color: color,
|
|
34
|
+
style: `color: ${color}; border-color: ${color};`
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
%>
|
|
@@ -12,7 +12,7 @@
|
|
|
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<%= item.facet ? ' facet' : '' %>" data-innate="<%= item.ability_is_innate && !item.ability_is_facet %>"><p class="title<%= item.facet ? (' name_back type_' + item.facet?.color) : '' %>"> <% if (item.facet) { %> <img src="<%= getImageUrl(item.facet?.icon, ImageType.IconsFacets) %>"> <% } %> <span class="name"><%= item.name_loc %></span> <% if (item.ability_is_innate && !item.ability_is_facet) { %> <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)
|
|
15
|
+
%> <div class="skill<%= item.facet ? ' facet' : '' %>" data-innate="<%= item.ability_is_innate && !item.ability_is_facet %>"><p class="title<%= item.facet ? (' name_back type_' + item.facet?.color) : '' %>"> <% if (item.facet) { %> <img src="<%= getImageUrl(item.facet?.icon, ImageType.IconsFacets) %>"> <% } %> <span class="name font-serif"><%= item.name_loc %></span> <% if (item.ability_is_innate && !item.ability_is_facet) { %> <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
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
18
|
const facetStartIndex = hero.facets.length - item.facets_loc.length;
|
|
@@ -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 facetGradient = facetColor[p.facet?.color ?? 'Black']; %> <% const facetIcon = p.facet?.icon; %> <% const facetName = p.facet?.displayName ?? "?"; %> <% 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]"><%- 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="facet row-2 col-1 w-full h-full grid grid-cols-[24px_1fr] grid-rows-1 bg-linear-to-r <%- facetGradient %>"> <% if (p.facet) { %> <div class="w-[24px] h-[24px] flex items-center justify-center bg-[#4444]"><img class="h-[18px]" src="<%= getImageUrl(facetIcon, ImageType.IconsFacets) %>"/></div> <% } %> <div class="facet_name w-full truncate grow px-[4px] text-sm flex justify-center items-center"><span class="w-full truncate text-center"><%= facetName %></span></div></div><div class="titles row-2 col-start-2 col-end-3 w-full flex items-center pl-[12px] gap-[6px]"> <% p.titles.forEach(item => { %> <% 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 facetGradient = facetColor[p.facet?.color ?? 'Black']; %> <% const facetIcon = p.facet?.icon; %> <% const facetName = p.facet?.displayName ?? "?"; %> <% 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]"><%- 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="facet row-2 col-1 w-full h-full grid grid-cols-[24px_1fr] grid-rows-1 bg-linear-to-r <%- facetGradient %>"> <% if (p.facet) { %> <div class="w-[24px] h-[24px] flex items-center justify-center bg-[#4444]"><img class="h-[18px]" src="<%= getImageUrl(facetIcon, ImageType.IconsFacets) %>"/></div> <% } %> <div class="facet_name w-full truncate grow px-[4px] text-sm flex justify-center items-center"><span class="w-full truncate text-center"><%= facetName %></span></div></div><div class="titles row-2 col-start-2 col-end-3 w-full flex items-center pl-[12px] gap-[6px]"> <% 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>
|
|
@@ -15,4 +15,4 @@
|
|
|
15
15
|
tie: getImageUrl("lane_tie", undefined, ImageFormat.svg),
|
|
16
16
|
jungle: getImageUrl("lane_jungle", undefined, ImageFormat.svg),
|
|
17
17
|
};
|
|
18
|
-
%> <!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`) %> <% if (fontFamily) { %><%- `body { font-family: ${fontFamily}; }` %><% } %> <%- `</style>` %> </head><body class="bg-black w-[800px] text-white"> <%- include(`./match_1/main.ejs`, { match, partyColor, facetColor, kc, dc, laneSVG }) %> </body></html>
|
|
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`) %> <% if (fontFamily) { %><%- `body { font-family: ${fontFamily}; }` %><% } %> <%- `</style>` %> </head><body class="bg-black w-[800px] text-white"> <%- include(`./match_1/main.ejs`, { match, partyColor, facetColor, kc, dc, laneSVG }) %> </body></html>
|
|
@@ -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 getFacetSize = n => { const l=n?.length||0; return l<=4?"11px":l===5?"8px":l>=6?"7px":"10px"; }; %> <% 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)" : ""; %> <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 facetColor = p.facet?.color ?? 'Black'; %> <% const facetStyle = `font-size: ${getFacetSize(p.facet?.displayName)}`; %> <% const facetName = p.facet?.displayName ?? '?'; %> <% 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="facet <%= facetColor %>"> <% if (p.facet) { %> <img src="<%- getImageUrl(p.facet.icon, ImageType.IconsFacets) %>"> <% } %> <span <%- `style="${facetStyle}"` %>><p><%= facetName %></p></span></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
|
|
10
|
+
%> <% const getFacetSize = n => { const l=n?.length||0; return l<=4?"11px":l===5?"8px":l>=6?"7px":"10px"; }; %> <% 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 facetColor = p.facet?.color ?? 'Black'; %> <% const facetStyle = `font-size: ${getFacetSize(p.facet?.displayName)}`; %> <% const facetName = p.facet?.displayName ?? '?'; %> <% 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="facet <%= facetColor %>"> <% if (p.facet) { %> <img src="<%- getImageUrl(p.facet.icon, ImageType.IconsFacets) %>"> <% } %> <span <%- `style="${facetStyle}"` %>><p><%= facetName %></p></span></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>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/*! tailwindcss v4.1.18 | 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-serif: "Cinzel", serif;--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-orange-500: oklch(70.5% .213 47.604);--color-slate-300: oklch(86.9% .022 252.894);--color-slate-400: oklch(70.4% .04 256.788);--color-slate-500: oklch(55.4% .046 257.417);--color-slate-600: oklch(44.6% .043 257.281);--color-slate-700: oklch(37.2% .044 257.287);--color-slate-800: oklch(27.9% .041 260.031);--color-black: #000;--color-white: #fff;--spacing: .25rem;--container-md: 28rem;--text-xs: .75rem;--text-xs--line-height: calc(1 / .75);--text-sm: .875rem;--text-sm--line-height: calc(1.25 / .875);--text-base: 1rem;--text-base--line-height: 1.5 ;--text-lg: 1.125rem;--text-lg--line-height: calc(1.75 / 1.125);--text-xl: 1.25rem;--text-xl--line-height: calc(1.75 / 1.25);--text-2xl: 1.5rem;--text-2xl--line-height: calc(2 / 1.5);--text-3xl: 1.875rem;--text-3xl--line-height: 1.2 ;--text-4xl: 2.25rem;--text-4xl--line-height: calc(2.5 / 2.25);--text-6xl: 3.75rem;--text-6xl--line-height: 1;--font-weight-medium: 500;--font-weight-bold: 700;--font-weight-black: 900;--tracking-tight: -.025em;--tracking-wider: .05em;--tracking-widest: .1em;--leading-tight: 1.25;--radius-lg: .5rem;--radius-xl: .75rem;--drop-shadow-md: 0 3px 3px rgb(0 0 0 / .12);--blur-sm: 8px;--default-transition-duration: .15s;--default-transition-timing-function: cubic-bezier(.4, 0, .2, 1);--default-font-family: var(--font-sans);--default-mono-font-family: var(--font-mono);--color-primary: #137fec;--color-background-dark: #101922;--color-dota-red: #ff3c3c;--color-dota-gold: #e8bc56;--color-dota-green: #0bda5b;--color-card-dark: #16202c;--font-display: "Inter", sans-serif}}@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{.pointer-events-none{pointer-events:none}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:calc(var(--spacing) * 0)}.inset-x-0{inset-inline:calc(var(--spacing) * 0)}.bottom-0{bottom:calc(var(--spacing) * 0)}.z-10{z-index:10}.col-span-1{grid-column:span 1 / span 1}.col-span-2{grid-column:span 2 / span 2}.col-span-3{grid-column:span 3 / span 3}.col-span-4{grid-column:span 4 / span 4}.mx-auto{margin-inline:auto}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-auto{margin-top:auto}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.flex{display:flex}.grid{display:grid}.hidden{display:none}.h-1{height:calc(var(--spacing) * 1)}.h-1\.5{height:calc(var(--spacing) * 1.5)}.h-4{height:calc(var(--spacing) * 4)}.h-10{height:calc(var(--spacing) * 10)}.h-12{height:calc(var(--spacing) * 12)}.h-\[27px\]{height:27px}.h-full{height:100%}.min-h-\[22px\]{min-height:22px}.min-h-\[280px\]{min-height:280px}.min-h-screen{min-height:100vh}.w-1{width:calc(var(--spacing) * 1)}.w-6{width:calc(var(--spacing) * 6)}.w-10{width:calc(var(--spacing) * 10)}.w-12{width:calc(var(--spacing) * 12)}.w-\[48px\]{width:48px}.w-full{width:100%}.max-w-\[900px\]{max-width:900px}.max-w-md{max-width:var(--container-md)}.flex-1{flex:1}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-12{grid-template-columns:repeat(12,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-1{gap:calc(var(--spacing) * 1)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-6{gap:calc(var(--spacing) * 6)}.gap-8{gap:calc(var(--spacing) * 8)}.overflow-hidden{overflow:hidden}.overflow-x-hidden{overflow-x:hidden}.rounded{border-radius:.25rem}.rounded-full{border-radius:calc(infinity * 1px)}.rounded-lg{border-radius:var(--radius-lg)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-b-2{border-bottom-style:var(--tw-border-style);border-bottom-width:2px}.border-dota-gold{border-color:var(--color-dota-gold)}.border-dota-red{border-color:var(--color-dota-red)}.border-slate-600{border-color:var(--color-slate-600)}.border-slate-700{border-color:var(--color-slate-700)}.border-white\/5{border-color:color-mix(in srgb,#fff 5%,transparent);@supports (color: color-mix(in lab,red,red)){border-color:color-mix(in oklab,var(--color-white) 5%,transparent)}}.border-white\/10{border-color:color-mix(in srgb,#fff 10%,transparent);@supports (color: color-mix(in lab,red,red)){border-color:color-mix(in oklab,var(--color-white) 10%,transparent)}}.bg-\[\#0d141c\]{background-color:#0d141c}.bg-\[\#16202c\]{background-color:#16202c}.bg-black\/20{background-color:color-mix(in srgb,#000 20%,transparent);@supports (color: color-mix(in lab,red,red)){background-color:color-mix(in oklab,var(--color-black) 20%,transparent)}}.bg-black\/40{background-color:color-mix(in srgb,#000 40%,transparent);@supports (color: color-mix(in lab,red,red)){background-color:color-mix(in oklab,var(--color-black) 40%,transparent)}}.bg-card-dark{background-color:var(--color-card-dark)}.bg-dota-gold{background-color:var(--color-dota-gold)}.bg-dota-gold\/50{background-color:color-mix(in srgb,#e8bc56 50%,transparent);@supports (color: color-mix(in lab,red,red)){background-color:color-mix(in oklab,var(--color-dota-gold) 50%,transparent)}}.bg-dota-green\/50{background-color:color-mix(in srgb,#0bda5b 50%,transparent);@supports (color: color-mix(in lab,red,red)){background-color:color-mix(in oklab,var(--color-dota-green) 50%,transparent)}}.bg-dota-red{background-color:var(--color-dota-red)}.bg-dota-red\/50{background-color:color-mix(in srgb,#ff3c3c 50%,transparent);@supports (color: color-mix(in lab,red,red)){background-color:color-mix(in oklab,var(--color-dota-red) 50%,transparent)}}.bg-orange-500{background-color:var(--color-orange-500)}.bg-slate-800{background-color:var(--color-slate-800)}.bg-gradient-to-t{--tw-gradient-position: to top in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.from-card-dark{--tw-gradient-from: var(--color-card-dark);--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))}.via-card-dark\/80{--tw-gradient-via: color-mix(in srgb, #16202c 80%, transparent);@supports (color: color-mix(in lab,red,red)){--tw-gradient-via: color-mix(in oklab, var(--color-card-dark) 80%, transparent)}--tw-gradient-via-stops: var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-via-stops)}.to-transparent{--tw-gradient-to: transparent;--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}.bg-center{background-position:center}.fill-current{fill:currentcolor}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-6{padding:calc(var(--spacing) * 6)}.px-1{padding-inline:calc(var(--spacing) * 1)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-8{padding-block:calc(var(--spacing) * 8)}.pt-1{padding-top:calc(var(--spacing) * 1)}.pt-2{padding-top:calc(var(--spacing) * 2)}.pb-0\.5{padding-bottom:calc(var(--spacing) * .5)}.pb-1{padding-bottom:calc(var(--spacing) * 1)}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.pb-4{padding-bottom:calc(var(--spacing) * 4)}.pb-6{padding-bottom:calc(var(--spacing) * 6)}.pl-2{padding-left:calc(var(--spacing) * 2)}.text-center{text-align:center}.text-left{text-align:left}.font-display{font-family:var(--font-display)}.font-mono{font-family:var(--font-mono)}.font-serif{font-family:var(--font-serif)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading, var(--text-2xl--line-height))}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading, var(--text-3xl--line-height))}.text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading, var(--text-4xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading, var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading, var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading, var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading, var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading, var(--text-xs--line-height))}.text-\[9px\]{font-size:9px}.text-\[10px\]{font-size:10px}.leading-none{--tw-leading: 1;line-height:1}.leading-tight{--tw-leading: var(--leading-tight);line-height:var(--leading-tight)}.font-black{--tw-font-weight: var(--font-weight-black);font-weight:var(--font-weight-black)}.font-bold{--tw-font-weight: var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight: var(--font-weight-medium);font-weight:var(--font-weight-medium)}.tracking-\[0\.2em\]{--tw-tracking: .2em;letter-spacing:.2em}.tracking-tight{--tw-tracking: var(--tracking-tight);letter-spacing:var(--tracking-tight)}.tracking-wider{--tw-tracking: var(--tracking-wider);letter-spacing:var(--tracking-wider)}.tracking-widest{--tw-tracking: var(--tracking-widest);letter-spacing:var(--tracking-widest)}.text-black{color:var(--color-black)}.text-dota-gold{color:var(--color-dota-gold)}.text-dota-green{color:var(--color-dota-green)}.text-dota-red{color:var(--color-dota-red)}.text-slate-300{color:var(--color-slate-300)}.text-slate-400{color:var(--color-slate-400)}.text-slate-500{color:var(--color-slate-500)}.text-white{color:var(--color-white)}.uppercase{text-transform:uppercase}.italic{font-style:italic}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.opacity-60{opacity:60%}.shadow-\[0_0_30px_rgba\(232\,188\,86\,0\.15\)\]{--tw-shadow: 0 0 30px var(--tw-shadow-color, rgba(232,188,86,.15));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-\[0_0_30px_rgba\(255\,60\,60\,0\.15\)\]{--tw-shadow: 0 0 30px var(--tw-shadow-color, rgba(255,60,60,.15));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-lg{--tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(0 0 0 / .1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(0 0 0 / .1));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-md{--tw-shadow: 0 4px 6px -1px var(--tw-shadow-color, rgb(0 0 0 / .1)), 0 2px 4px -2px var(--tw-shadow-color, rgb(0 0 0 / .1));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-sm{--tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / .1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / .1));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-dota-gold\/20{--tw-shadow-color: color-mix(in srgb, #e8bc56 20%, transparent);@supports (color: color-mix(in lab,red,red)){--tw-shadow-color: color-mix(in oklab, color-mix(in oklab, var(--color-dota-gold) 20%, transparent) var(--tw-shadow-alpha), transparent)}}.shadow-dota-red\/20{--tw-shadow-color: color-mix(in srgb, #ff3c3c 20%, transparent);@supports (color: color-mix(in lab,red,red)){--tw-shadow-color: color-mix(in oklab, color-mix(in oklab, var(--color-dota-red) 20%, transparent) var(--tw-shadow-alpha), transparent)}}.drop-shadow-\[0_1px_2px_rgba\(0\,0\,0\,0\.8\)\]{--tw-drop-shadow-size: drop-shadow(0 1px 2px var(--tw-drop-shadow-color, rgba(0,0,0,.8)));--tw-drop-shadow: var(--tw-drop-shadow-size);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,)}.drop-shadow-\[0_2px_10px_rgba\(0\,0\,0\,0\.5\)\]{--tw-drop-shadow-size: drop-shadow(0 2px 10px var(--tw-drop-shadow-color, rgba(0,0,0,.5)));--tw-drop-shadow: var(--tw-drop-shadow-size);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,)}.drop-shadow-md{--tw-drop-shadow-size: drop-shadow(0 3px 3px var(--tw-drop-shadow-color, rgb(0 0 0 / .12)));--tw-drop-shadow: drop-shadow(var(--drop-shadow-md));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,)}.backdrop-blur-sm{--tw-backdrop-blur: blur(var(--blur-sm));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease, var(--default-transition-timing-function));transition-duration:var(--tw-duration, var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease, var(--default-transition-timing-function));transition-duration:var(--tw-duration, var(--default-transition-duration))}.duration-700{--tw-duration: .7s;transition-duration:.7s}.group-hover\:scale-105{&:is(:where(.group):hover *){@media (hover: hover){--tw-scale-x: 105%;--tw-scale-y: 105%;--tw-scale-z: 105%;scale:var(--tw-scale-x) var(--tw-scale-y)}}}.hover\:bg-white\/\[0\.02\]{&:hover{@media (hover: hover){background-color:color-mix(in srgb,#fff 2%,transparent);@supports (color: color-mix(in lab,red,red)){background-color:color-mix(in oklab,var(--color-white) 2%,transparent)}}}}.sm\:px-6{@media (width >= 40rem){padding-inline:calc(var(--spacing) * 6)}}.md\:grid{@media (width >= 48rem){display:grid}}.md\:grid-cols-4{@media (width >= 48rem){grid-template-columns:repeat(4,minmax(0,1fr))}}.md\:grid-cols-12{@media (width >= 48rem){grid-template-columns:repeat(12,minmax(0,1fr))}}.md\:flex-row{@media (width >= 48rem){flex-direction:row}}.md\:text-6xl{@media (width >= 48rem){font-size:var(--text-6xl);line-height:var(--tw-leading, var(--text-6xl--line-height))}}}::-webkit-scrollbar{width:8px}::-webkit-scrollbar-track{background:var(--color-background-dark)}::-webkit-scrollbar-thumb{background:#233648;border-radius:4px}::-webkit-scrollbar-thumb:hover{background:var(--color-primary)}@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-font-weight{syntax: "*"; inherits: false;}@property --tw-tracking{syntax: "*"; inherits: false;}@property --tw-shadow{syntax: "*"; inherits: false; initial-value: 0 0 #0000;}@property --tw-shadow-color{syntax: "*"; inherits: false;}@property --tw-shadow-alpha{syntax: "<percentage>"; inherits: false; initial-value: 100%;}@property --tw-inset-shadow{syntax: "*"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-shadow-color{syntax: "*"; inherits: false;}@property --tw-inset-shadow-alpha{syntax: "<percentage>"; inherits: false; initial-value: 100%;}@property --tw-ring-color{syntax: "*"; inherits: false;}@property --tw-ring-shadow{syntax: "*"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-ring-color{syntax: "*"; inherits: false;}@property --tw-inset-ring-shadow{syntax: "*"; inherits: false; initial-value: 0 0 #0000;}@property --tw-ring-inset{syntax: "*"; inherits: false;}@property --tw-ring-offset-width{syntax: "<length>"; inherits: false; initial-value: 0px;}@property --tw-ring-offset-color{syntax: "*"; inherits: false; initial-value: #fff;}@property --tw-ring-offset-shadow{syntax: "*"; inherits: false; initial-value: 0 0 #0000;}@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-backdrop-blur{syntax: "*"; inherits: false;}@property --tw-backdrop-brightness{syntax: "*"; inherits: false;}@property --tw-backdrop-contrast{syntax: "*"; inherits: false;}@property --tw-backdrop-grayscale{syntax: "*"; inherits: false;}@property --tw-backdrop-hue-rotate{syntax: "*"; inherits: false;}@property --tw-backdrop-invert{syntax: "*"; inherits: false;}@property --tw-backdrop-opacity{syntax: "*"; inherits: false;}@property --tw-backdrop-saturate{syntax: "*"; inherits: false;}@property --tw-backdrop-sepia{syntax: "*"; inherits: false;}@property --tw-duration{syntax: "*"; inherits: false;}@property --tw-scale-x{syntax: "*"; inherits: false; initial-value: 1;}@property --tw-scale-y{syntax: "*"; inherits: false; initial-value: 1;}@property --tw-scale-z{syntax: "*"; inherits: false; initial-value: 1;}@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-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-font-weight: initial;--tw-tracking: initial;--tw-shadow: 0 0 #0000;--tw-shadow-color: initial;--tw-shadow-alpha: 100%;--tw-inset-shadow: 0 0 #0000;--tw-inset-shadow-color: initial;--tw-inset-shadow-alpha: 100%;--tw-ring-color: initial;--tw-ring-shadow: 0 0 #0000;--tw-inset-ring-color: initial;--tw-inset-ring-shadow: 0 0 #0000;--tw-ring-inset: initial;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-offset-shadow: 0 0 #0000;--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-backdrop-blur: initial;--tw-backdrop-brightness: initial;--tw-backdrop-contrast: initial;--tw-backdrop-grayscale: initial;--tw-backdrop-hue-rotate: initial;--tw-backdrop-invert: initial;--tw-backdrop-opacity: initial;--tw-backdrop-saturate: initial;--tw-backdrop-sepia: initial;--tw-duration: initial;--tw-scale-x: 1;--tw-scale-y: 1;--tw-scale-z: 1}}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@theme{ --color-primary: #137fec; --color-background-light: #f6f7f8; --color-background-dark: #101922; --color-dota-red: #ff3c3c; --color-dota-dark-red: #b91c1c; --color-dota-gold: #e8bc56; --color-dota-dark-gold: #b48518; --color-dota-green: #0bda5b; --color-card-dark: #16202c; --color-card-darker: #0d141c; --color-surface: #1c2633; --font-display: "Inter", sans-serif; --font-serif: "Cinzel", serif; --image-smoke-pattern: radial-gradient(circle at 50% 50%, rgba(20, 30, 40, 0) 0%, rgba(16, 25, 34, .8) 100%); --image-topographic: linear-gradient(rgba(16, 25, 34, .95), rgba(16, 25, 34, .95)), repeating-linear-gradient(45deg, #1a2634 0px, #1a2634 1px, transparent 1px, transparent 10px); }::-webkit-scrollbar{width:8px}::-webkit-scrollbar-track{background:var(--color-background-dark)}::-webkit-scrollbar-thumb{background:#233648;border-radius:4px}::-webkit-scrollbar-thumb:hover{background:var(--color-primary)}
|
|
@@ -1,21 +1,7 @@
|
|
|
1
|
-
<%
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
if (isPos) right = abs;
|
|
9
|
-
else left = abs;
|
|
10
|
-
} else {
|
|
11
|
-
left = right = abs;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
return {
|
|
15
|
-
valStr: (isPos ? "+" : "") + impVal,
|
|
16
|
-
barClass: `score_bar ${isPos ? "pos" : "neg"}${isOver ? " over" : ""}`,
|
|
17
|
-
leftStyle: `width: ${left}px`,
|
|
18
|
-
rightStyle: `width: ${right}px`
|
|
19
|
-
};
|
|
20
|
-
};
|
|
21
|
-
%> <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><title>Daily Report</title> <%- `<style>` %> <%- include("../common/styles/normalize.min.css") %> <%- include("./daily/base.css") %> <% if (fontFamily) { %><%- `body { font-family: ${fontFamily}; }` %><% } %> <%- `</style>` %> </head><body><h3 class="title"><%= title %></h3><div class="players"> <% players.forEach(p => { %> <% const winRate = Math.round((p.winCount / p.matches.length) * 100); %> <% const imp = getImpInfo(p.avgImp); %> <div class="player"><img src="<%= p.steamAccount.avatar %>" class="avatar"/> <span class="name"><%= p.name %></span><span class="count"><span class="win"><%= $t("dota2tracker.template.report_won") %><%= p.winCount %></span><span class="lose"><%= $t("dota2tracker.template.report_lost") %><%= p.loseCount %></span><span><%= $t("dota2tracker.template.report_winrate") %> <%= winRate %>%</span></span><div class="performance"><div class="<%= imp.barClass %>"><div class="left" <%- `style="${imp.leftStyle}"` %>></div><div class="pipe"></div><div class="right" <%- `style="${imp.rightStyle}"` %>></div></div><span class="score_value"><%= imp.valStr %></span></div><span class="kda"><%= p.avgKills %>/<%= p.avgDeaths %>/<%= p.avgAssists %> (<%= p.avgKDA %>)</span></div> <% }); %> </div><div class="combinations" <%- !showCombi ? `style="display:none;"` : "" %>><span style="grid-column:1/-1"><%= $t("dota2tracker.template.combined_win_loss_summary") %></span> <% combinations.forEach(combi => { %> <% const combiRate = Math.round((combi.winCount / combi.matches.length) * 100); %> <div class="players"> <% combi.players.forEach(p => { %> <img src="<%= p.steamAccount.avatar %>" class="avatar"/> <% }); %> </div><span class="win"><%= $t("dota2tracker.template.report_won") %><%= combi.winCount %></span><span class="lose"><%= $t("dota2tracker.template.report_lost") %><%= combi.matches.length - combi.winCount %></span><span><%= $t("dota2tracker.template.report_winrate") %> <%= combiRate %>%</span> <% }); %> </div></body></html>
|
|
1
|
+
<!DOCTYPE html><html class="dark" lang="en"><head><meta charset="utf-8"/><meta content="width=device-width,initial-scale=1" name="viewport"/><title>Dota 2 Daily Recap</title> <%- `<style>` %> <%- include(`./daily/style.css`) %> <% if (fontFamily) { %><%- `body { font-family: ${fontFamily}; }` %><% } %> <%- `</style>` %> <style>::-webkit-scrollbar{width:8px}::-webkit-scrollbar-track{background:#101922}::-webkit-scrollbar-thumb{background:#233648;border-radius:4px}::-webkit-scrollbar-thumb:hover{background:#137fec}.bg-texture{background-color:#101922;background-image:radial-gradient(at 0 0,rgba(19,127,236,.08) 0,transparent 50%),radial-gradient(at 100% 0,rgba(255,60,60,.05) 0,transparent 50%),radial-gradient(at 100% 100%,rgba(232,188,86,.05) 0,transparent 50%)}</style></head><body class="bg-texture font-display text-white overflow-x-hidden antialiased min-h-screen"><div class="w-full flex justify-center py-8 px-4 sm:px-6"><div class="w-full max-w-[900px] flex flex-col gap-8"><div class="flex flex-col items-center justify-center pt-2 pb-4 text-center"><div class="mb-3 border-b-2 border-dota-red pb-1"><span class="text-xs font-bold tracking-[0.2em] uppercase text-dota-gold drop-shadow-md"> <%= $t("dota2tracker.template.report.daily.plugin_name") %> </span></div><h1 class="text-4xl md:text-6xl font-serif font-black tracking-tight text-white uppercase drop-shadow-[0_2px_10px_rgba(0,0,0,0.5)] mb-2"> <%= $t("dota2tracker.template.report.daily.title") %> </h1><div class="flex flex-col items-center gap-1 text-slate-400 font-medium"><p class="text-lg tracking-widest uppercase text-slate-300"><%= data.meta.date %></p><p class="text-xs opacity-60 max-w-md mx-auto"> <%= data.meta.summary %> </p></div></div><div class="grid grid-cols-2 md:grid-cols-4 gap-3"><div class="flex flex-col items-center justify-center p-4 rounded bg-card-dark border border-white/5 shadow-lg relative overflow-hidden group"><span class="text-slate-500 text-[10px] font-bold uppercase tracking-widest mb-1"> <%= $t("dota2tracker.template.report.daily.stats.matches") %> </span><span class="text-3xl font-black text-white"><%= data.headerStats.matches.value %></span><span class="text-xs text-slate-400 mt-1"><%= data.headerStats.matches.subtext %></span></div><div class="flex flex-col items-center justify-center p-4 rounded bg-card-dark border border-white/5 shadow-lg relative overflow-hidden group"><div class="absolute inset-x-0 bottom-0 h-1 <%= data.headerStats.winRate.isWinRateAbove50 ? 'bg-dota-green/50' : 'bg-dota-red/50' %>"></div><span class="text-slate-500 text-[10px] font-bold uppercase tracking-widest mb-1"> <%= $t("dota2tracker.template.report.daily.stats.win_rate") %> </span><span class="text-3xl font-black <%= data.headerStats.winRate.isWinRateAbove50 ? 'text-dota-green' : 'text-dota-red' %>"><%= data.headerStats.winRate.value %></span><span class="text-xs mt-1 <%= data.headerStats.winRate.isPositive ? 'text-dota-green' : 'text-dota-red' %>"><%= data.headerStats.winRate.subtext %></span></div><div class="flex flex-col items-center justify-center p-4 rounded bg-card-dark border border-white/5 shadow-lg relative overflow-hidden group"><div class="absolute inset-x-0 bottom-0 h-1 bg-dota-red/50"></div><span class="text-slate-500 text-[10px] font-bold uppercase tracking-widest mb-1"> <%= $t("dota2tracker.template.report.daily.stats.kills") %> </span><span class="text-3xl font-black text-dota-red"><%= data.headerStats.kills.value %></span><span class="text-xs text-slate-400 mt-1"><%= data.headerStats.kills.subtext %></span></div><div class="flex flex-col items-center justify-center p-4 rounded bg-card-dark border border-white/5 shadow-lg relative overflow-hidden group"><div class="absolute inset-x-0 bottom-0 h-1 bg-dota-gold/50"></div><span class="text-slate-500 text-[10px] font-bold uppercase tracking-widest mb-1"> <%= $t("dota2tracker.template.report.daily.stats.duration") %> </span><span class="text-3xl font-black text-dota-gold"><%= data.headerStats.duration.value %></span><span class="text-xs text-slate-400 mt-1"> <%= data.headerStats.duration.subtext %> </span></div></div><div class="flex flex-col md:flex-row gap-6 mt-2"> <% const lights = [data.spotlights.mvp, data.spotlights.lvp]; %> <% lights.forEach(function(light) { %> <div class="flex-1 relative rounded-lg border <%= light.type === 'MVP' ? 'border-dota-gold shadow-[0_0_30px_rgba(232,188,86,0.15)]' : 'border-dota-red shadow-[0_0_30px_rgba(255,60,60,0.15)]' %> bg-card-dark overflow-hidden group"><div class="absolute inset-0 bg-cover bg-center transition-transform duration-700 group-hover:scale-105" style="background-image:url('<%= light.player.heroBannerUrl %>');opacity:.4"></div><div class="absolute inset-0 bg-gradient-to-t from-card-dark via-card-dark/80 to-transparent"></div><div class="relative z-10 p-6 flex flex-col h-full min-h-[280px]"><div class="flex justify-between items-center"><div class="<%= light.type === 'MVP' ? 'bg-dota-gold text-black shadow-dota-gold/20' : 'bg-dota-red text-white shadow-dota-red/20' %> text-xs font-black uppercase px-3 py-1 rounded shadow-lg"> <%= light.type === 'MVP' ? $t("dota2tracker.template.report.daily.spotlight.mvp_title") : $t("dota2tracker.template.report.daily.spotlight.lvp_title") %> </div><svg xmlns="http://www.w3.org/2000/svg" class="w-10 h-10 fill-current" viewBox="0 0 24 24"> <% if (light.type === 'MVP') { %> <path class="text-dota-gold" d="M19 5h-2V3H7v2H5c-1.1 0-2 .9-2 2v1c0 2.55 1.92 4.63 4.39 4.94.63 1.5 1.98 2.63 3.61 2.96V19H7v2h10v-2h-4v-3.1c1.63-.33 2.98-1.46 3.61-2.96C19.08 12.63 21 10.55 21 8V7c0-1.1-.9-2-2-2zM5 8V7h2v3.82C5.84 10.4 5 9.3 5 8zm14 0c0 1.3-.84 2.4-2 2.82V7h2v1z"/> <% } else { %> <path class="text-dota-red" d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"/> <% } %> </svg></div><div class="mt-auto"><h3 class="text-3xl font-serif font-bold text-white leading-none mb-1 drop-shadow-md"><%= light.player.name %></h3><p class="text-slate-300 text-sm font-medium leading-none mb-1"><%= light.player.heroName %></p><p class="text-slate-400 text-sm font-mono mb-3"><%= light.player.kda %></p><div class="bg-black/40 backdrop-blur-sm rounded-lg p-3 border border-white/10"><div class="flex flex-col gap-2"><div class="flex justify-between items-center border-b border-white/10 pb-2"><span class="text-xs text-slate-400 uppercase tracking-widest font-bold"> <%= light.score.label %> </span><span class="font-mono text-2xl font-bold <%= light.type === 'MVP' ? 'text-dota-gold' : 'text-dota-red' %>"><%= light.score.value %></span></div><div class="flex flex-wrap gap-2 pt-1 min-h-[22px]"> <% if (light.badges && light.badges.length > 0) { %> <% light.badges.forEach(function(badge) { %> <%
|
|
2
|
+
// Convert HEX to RGB for background opacity
|
|
3
|
+
const r = parseInt(badge.hexColor.slice(1, 3), 16);
|
|
4
|
+
const g = parseInt(badge.hexColor.slice(3, 5), 16);
|
|
5
|
+
const b = parseInt(badge.hexColor.slice(5, 7), 16);
|
|
6
|
+
const bgStyle = `background-color: rgba(${r}, ${g}, ${b}, 0.2); border-color: rgba(${r}, ${g}, ${b}, 0.3); color: ${badge.hexColor};`;
|
|
7
|
+
%> <span class="px-2 py-0.5 rounded text-[10px] font-bold uppercase border" style="<%= bgStyle %>"><%= badge.text %></span> <% }); %> <% } else { %> <% } %> </div></div></div></div></div></div> <% }); %> </div><div class="bg-[#0d141c] rounded-xl border border-white/5 overflow-hidden"><div class="flex items-center justify-between p-4 border-b border-white/5 bg-[#16202c]"><h2 class="text-lg font-serif font-bold text-white uppercase tracking-wider flex items-center gap-2"><span class="w-1 h-4 bg-dota-red rounded-full"></span> <%= $t("dota2tracker.template.report.daily.squad.title") %> </h2><div class="text-[10px] font-bold text-slate-400 uppercase tracking-widest bg-black/20 px-2 py-1 rounded border border-white/5"> <%= $t("dota2tracker.template.report.daily.squad.subtitle") %> </div></div><div class="hidden md:grid grid-cols-12 gap-4 px-4 py-3 text-[10px] font-bold text-slate-500 uppercase tracking-widest bg-black/20"><div class="col-span-1 text-center"><%= $t("dota2tracker.template.report.daily.squad.header.rank") %></div><div class="col-span-4 pl-2"><%= $t("dota2tracker.template.report.daily.squad.header.player_info") %></div><div class="col-span-3"><%= $t("dota2tracker.template.report.daily.squad.header.hero_pool") %></div><div class="col-span-2 text-center"><%= $t("dota2tracker.template.report.daily.squad.header.kda") %></div><div class="col-span-2 text-left pl-2"><%= $t("dota2tracker.template.report.daily.squad.header.impact") %></div></div><div class="flex flex-col"> <% data.squad.forEach(function(row) { %> <div class="flex flex-col md:grid md:grid-cols-12 gap-4 p-4 border-b border-white/5 hover:bg-white/[0.02] transition-colors items-center"><div class="col-span-1 flex items-center justify-center"><span class="font-serif italic text-2xl <%= row.rank === 1 ? 'text-dota-gold' : (row.rank === data.squad.length ? 'text-dota-red' : 'text-slate-400') %> font-bold"><%= row.rank %></span></div><div class="col-span-4 w-full flex items-center gap-3 pl-2"><div class="w-12 h-12 rounded bg-cover bg-center border border-slate-600 shadow-md" style="background-image:url('<%= row.player.avatarUrl || '' %>')"></div><div class="flex flex-col"><span class="font-bold text-white text-base leading-tight"><%= row.player.name %></span><div class="flex items-center gap-1 text-xs font-medium mt-0.5"><span class="text-dota-green"><%= row.player.winCount %> <%= $t("dota2tracker.template.won") %></span><span class="text-slate-500">-</span> <span class="text-dota-red"><%= row.player.loseCount %> <%= $t("dota2tracker.template.lost") %></span></div></div></div><div class="col-span-3 w-full flex items-center gap-2"> <% row.heroes.forEach(function(hero) { %> <div class="relative w-[48px] h-[27px] rounded border border-slate-700 shadow-sm overflow-hidden group"><div class="absolute inset-0 bg-cover bg-center" style="background-image:url('<%= hero.url %>')"></div><div class="absolute inset-x-0 bottom-0 flex justify-between px-1 pb-0.5 pointer-events-none"><span class="text-[10px] font-bold leading-none text-dota-green drop-shadow-[0_1px_2px_rgba(0,0,0,0.8)]" style="text-shadow:-1px -1px 0 #000,1px -1px 0 #000,-1px 1px 0 #000,1px 1px 0 #000"><%= hero.wins %></span><span class="text-[10px] font-bold leading-none text-dota-red drop-shadow-[0_1px_2px_rgba(0,0,0,0.8)]" style="text-shadow:-1px -1px 0 #000,1px -1px 0 #000,-1px 1px 0 #000,1px 1px 0 #000"><%= hero.losses %></span></div></div> <% }); %> <% if (row.plusHeroesCount > 0) { %> <span class="text-[10px] font-bold bg-slate-800 text-slate-400 px-1.5 py-0.5 rounded border border-slate-700">+<%= row.plusHeroesCount %></span> <% } %> </div><div class="col-span-2 w-full flex flex-col items-center justify-center"><span class="text-xl font-bold text-white leading-none"><%= row.kda.ratio %></span><div class="text-xs text-slate-500 font-mono mt-1"><%= row.kda.detail %></div></div><div class="col-span-2 w-full flex flex-col justify-center gap-1.5 pl-2"><div class="flex items-center gap-2 w-full"><span class="text-[9px] w-6 text-slate-500 font-bold uppercase"> <%= $t("dota2tracker.template.report.daily.squad.impact.dmg") %> </span><div class="flex-1 h-1.5 bg-slate-800 rounded-full overflow-hidden flex"><div class="h-full bg-dota-red" style="width: <%= row.impact.damage.heroPercent %>%"></div><div class="h-full bg-orange-500" style="width: <%= row.impact.damage.buildingsPercent %>%"></div></div></div><div class="flex items-center gap-2 w-full"><span class="text-[9px] w-6 text-slate-500 font-bold uppercase"> <%= $t("dota2tracker.template.report.daily.squad.impact.gold") %> </span><div class="flex-1 h-1.5 bg-slate-800 rounded-full overflow-hidden"><div class="h-full bg-dota-gold" style="width: <%= row.impact.networth.percent %>%"></div></div></div></div></div> <% }); %> </div></div><div class="flex flex-col items-center justify-center text-center gap-1 pb-6 opacity-60"><div class="flex items-center gap-2 text-dota-gold text-xs font-bold uppercase tracking-widest" style="display:none"><span class="material-symbols-outlined text-sm">auto_awesome</span> <span><%= $t("dota2tracker.template.report.daily.footer.generated_by") %></span></div><p class="text-[10px] text-slate-500 font-mono"><%= data.meta.footerId %></p></div></div></div></body></html>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<% const { title, players, combinations, showCombi } = data; %> <% const getImpInfo = (impVal) => {
|
|
2
|
+
const abs = Math.abs(impVal);
|
|
3
|
+
const isPos = impVal > 0;
|
|
4
|
+
const isOver = abs > 25;
|
|
5
|
+
|
|
6
|
+
let left = 0, right = 0;
|
|
7
|
+
if (isOver) {
|
|
8
|
+
if (isPos) right = abs;
|
|
9
|
+
else left = abs;
|
|
10
|
+
} else {
|
|
11
|
+
left = right = abs;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return {
|
|
15
|
+
valStr: (isPos ? "+" : "") + impVal,
|
|
16
|
+
barClass: `score_bar ${isPos ? "pos" : "neg"}${isOver ? " over" : ""}`,
|
|
17
|
+
leftStyle: `width: ${left}px`,
|
|
18
|
+
rightStyle: `width: ${right}px`
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
%> <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><title>Daily Report</title> <%- `<style>` %> <%- include("../common/styles/normalize.min.css") %> <%- include("./daily_legacy/base.css") %> <% if (fontFamily) { %><%- `body { font-family: ${fontFamily}; }` %><% } %> <%- `</style>` %> </head><body><h3 class="title"><%= title %></h3><div class="players"> <% players.forEach(p => { %> <% const winRate = Math.round((p.winCount / p.matches.length) * 100); %> <% const imp = getImpInfo(p.avgImp); %> <div class="player"><img src="<%= p.steamAccount.avatar %>" class="avatar"/> <span class="name"><%= p.name %></span><span class="count"><span class="win"><%= $t("dota2tracker.template.report_won") %><%= p.winCount %></span><span class="lose"><%= $t("dota2tracker.template.report_lost") %><%= p.loseCount %></span><span><%= $t("dota2tracker.template.report_winrate") %> <%= winRate %>%</span></span><div class="performance"><div class="<%= imp.barClass %>"><div class="left" <%- `style="${imp.leftStyle}"` %>></div><div class="pipe"></div><div class="right" <%- `style="${imp.rightStyle}"` %>></div></div><span class="score_value"><%= imp.valStr %></span></div><span class="kda"><%= p.avgKills %>/<%= p.avgDeaths %>/<%= p.avgAssists %> (<%= p.avgKDA %>)</span></div> <% }); %> </div><div class="combinations" <%- !showCombi ? `style="display:none;"` : "" %>><span style="grid-column:1/-1"><%= $t("dota2tracker.template.combined_win_loss_summary") %></span> <% combinations.forEach(combi => { %> <% const combiRate = Math.round((combi.winCount / combi.matches.length) * 100); %> <div class="players"> <% combi.players.forEach(p => { %> <img src="<%= p.steamAccount.avatar %>" class="avatar"/> <% }); %> </div><span class="win"><%= $t("dota2tracker.template.report_won") %><%= combi.winCount %></span><span class="lose"><%= $t("dota2tracker.template.report_lost") %><%= combi.matches.length - combi.winCount %></span><span><%= $t("dota2tracker.template.report_winrate") %> <%= combiRate %>%</span> <% }); %> </div></body></html>
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sjtdev/koishi-plugin-dota2tracker",
|
|
3
3
|
"description": "koishi插件-追踪群友的DOTA2对局 | A Koishi plugin to track Dota 2 matches",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.5.0",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"typings": "lib/index.d.ts",
|
|
7
7
|
"files": [
|
|
@@ -24,18 +24,15 @@
|
|
|
24
24
|
"dota2"
|
|
25
25
|
],
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"axios": "^1.13.
|
|
27
|
+
"axios": "^1.13.5",
|
|
28
28
|
"dotaconstants": "^10.7.0",
|
|
29
|
-
"ejs": "^
|
|
29
|
+
"ejs": "^4.0.1",
|
|
30
|
+
"fontkit": "^2.0.4",
|
|
30
31
|
"https-proxy-agent": "^7.0.6",
|
|
31
32
|
"luxon": "^3.8.0-alpha.1"
|
|
32
33
|
},
|
|
33
|
-
"devDependencies": {
|
|
34
|
-
"@koishijs/client": "^5.30.11"
|
|
35
|
-
},
|
|
36
34
|
"peerDependencies": {
|
|
37
|
-
"
|
|
38
|
-
"koishi": "^4.18.9"
|
|
35
|
+
"koishi": "^4.18.10"
|
|
39
36
|
},
|
|
40
37
|
"publishConfig": {
|
|
41
38
|
"access": "public",
|
|
File without changes
|