feat: 强袭战

This commit is contained in:
bietiaop 2024-12-24 14:40:19 +08:00
parent fb7f746407
commit 3a88596399
14 changed files with 1066 additions and 5 deletions

50
apps/deadly.js Normal file
View file

@ -0,0 +1,50 @@
import { ZZZPlugin } from '../lib/plugin.js';
import settings from '../lib/settings.js';
import _ from 'lodash';
import { Deadly } from '../model/deadly.js';
import { rulePrefix } from '../lib/common.js';
export class Abyss extends ZZZPlugin {
constructor() {
super({
name: '[ZZZ-Plugin]deadly',
dsc: 'zzz危局强袭战',
event: 'message',
priority: _.get(settings.getConfig('priority'), 'deadly', 70),
rule: [
{
reg: `${rulePrefix}(上期|往期)?(危局强袭战|危局|强袭|强袭战)$`,
fnc: 'deadly',
},
],
});
}
async deadly() {
const { api } = await this.getAPI();
await this.getPlayerInfo();
const method = this.e.msg.match(`(上期|往期)`)
? 'zzzDeadlyPeriod'
: 'zzzDeadly';
const deadlyData = await api.getFinalData(method).catch(e => {
this.reply(e.message);
throw e;
});
if (!deadlyData?.has_data) {
await this.reply('没有危局强袭战数据');
return false;
}
const deadly = new Deadly(deadlyData);
const timer = setTimeout(() => {
if (this?.reply) {
this.reply('查询成功,正在下载图片资源,请稍候。');
}
}, 5000);
await deadly.get_assets();
clearTimeout(timer);
const finalData = {
deadly,
};
logger.debug(JSON.stringify(finalData, null, 2));
await this.render('deadly/index.html', finalData, this);
}
}

View file

@ -144,20 +144,20 @@ const helpData = [
],
},
{
title: '式舆防卫战',
title: '绩查询',
icon: 'dungeon',
items: [
{
title: '查看式舆防卫战',
desc: '查看式舆防卫战(深渊)信息',
needCK: false,
needCK: true,
needSK: false,
commands: ['式舆防卫战', '防卫战', '式舆', '深渊', '防卫'],
},
{
title: '查看上期式舆防卫战',
desc: '查看上期式舆防卫战(深渊)信息',
needCK: false,
needCK: true,
needSK: false,
commands: [
'上期式舆防卫战',
@ -167,6 +167,20 @@ const helpData = [
'上期防卫',
],
},
{
title: '查看危局强袭战',
desc: '查看式危局强袭战信息',
needCK: true,
needSK: false,
commands: ['危局强袭战', '危局', '强袭', '强袭战'],
},
{
title: '查看上期危局强袭战',
desc: '查看上期危局强袭战信息',
needCK: true,
needSK: false,
commands: ['上期式舆防卫战', '上期危局', '上期强袭', '上期强袭战'],
},
],
},
{

View file

@ -303,7 +303,12 @@ export default class MysZZZApi extends MysApi {
const configCode = !Array.isArray(_configCode)
? [String(_configCode)]
: _configCode.map(item => String(item));
if (code === '1034' || code === '10035' || configCode.includes(code)) {
if (
code === '1034' ||
code === '10035' ||
code === '10041' ||
configCode.includes(code)
) {
// 如果有注册的mys.req.err调用
if (!!this?.handler && this?.handler?.has('mys.req.err')) {
logger.mark(

View file

@ -62,6 +62,14 @@ export default class ZZZApiTool {
url: `${this.hostRecord}event/game_record_zzz/api/zzz/challenge`,
query: `lang=zh-cn&role_id=${this.uid}&server=${this.server}&schedule_type=2`,
},
zzzDeadly: {
url: `${this.hostRecord}event/game_record_zzz/api/zzz/mem_detail`,
query: `lang=zh-cn&role_id=${this.uid}&server=${this.server}&schedule_type=1`,
},
zzzDeadlyPeriod: {
url: `${this.hostRecord}event/game_record_zzz/api/zzz/mem_detail`,
query: `lang=zh-cn&role_id=${this.uid}&server=${this.server}&schedule_type=2`,
},
zzzMonthly: {
url: `${this.host}event/nap_ledger/month_info`,
query: `uid=${this.uid}&region=${this.server}`,

273
model/deadly.js Normal file
View file

@ -0,0 +1,273 @@
import request from '../utils/request.js';
import { Buffer } from 'node:buffer';
/**
* @typedef {Object} DeadlyTime
* @property {number} hour
* @property {number} minute
* @property {number} second
* @property {number} year
* @property {number} month
* @property {number} day
*/
/**
* @typedef {Object} Bos
* @property {string} race_icon
* @property {string} icon
* @property {string} name
* @property {string} bg_icon
*/
/**
* @typedef {Object} DeadBuffer
* @property {string} desc
* @property {string} icon
* @property {string} name
*/
/**
* @typedef {Object} Buddy
* @property {number} id
* @property {string} rarity
* @property {number} level
* @property {string} bangboo_rectangle_url
*/
/**
* @typedef {Object} AvatarList
* @property {string} rarity
* @property {number} element_type
* @property {number} avatar_profession
* @property {number} id
* @property {number} level
* @property {number} rank
* @property {string} role_square_url
* @property {number} sub_element_type
*/
/**
* @typedef {Object} DeadlyList
* @property {number} star
* @property {number} score
* @property {Bos[]} boss
* @property {DeadBuffer[]} buffer
* @property {Buddy} buddy
* @property {number} total_star
* @property {DeadlyTime} challenge_time
* @property {AvatarList[]} avatar_list
*/
/**
* @typedef {Object} Deadly
* @property {DeadlyTime} start_time
* @property {DeadlyTime} end_time
* @property {string} nick_name
* @property {string} avatar_icon
* @property {boolean} has_data
* @property {number} zone_id
* @property {number} total_star
* @property {number} rank_percent
* @property {number} total_score
* @property {DeadlyList[]} list
*/
/**
* @class Deadly.
*/
export class Deadly {
/**
* @param {Deadly} data
*/
constructor(data) {
this.start_time = new DeadlyTime(data.start_time);
this.end_time = new DeadlyTime(data.end_time);
this.nick_name = data.nick_name;
this.avatar_icon = data.avatar_icon;
this.has_data = data.has_data;
this.zone_id = data.zone_id;
this.total_star = data.total_star;
this.rank_percent = data.rank_percent;
this.total_score = data.total_score;
this.list = data.list.map(item => new DeadlyList(item));
}
async get_assets() {
const avatar_icon_b64 = await request
.get(this.avatar_icon, {}, { responseType: 'arraybuffer' })
.then(response => response.arrayBuffer())
.then(
buffer =>
`data:image/png;base64,${Buffer.from(buffer).toString('base64')}`
);
this.avatar_icon = avatar_icon_b64;
await Promise.all(this.list.map(item => item.get_assets()));
}
}
/**
* @class DeadlyList.
*/
export class DeadlyList {
/**
* @param {DeadlyList} data
*/
constructor(data) {
this.star = data.star;
this.score = data.score;
this.boss = data.boss.map(b => new Bos(b));
this.buffer = data.buffer.map(b => new DeadBuffer(b));
this.buddy = new Buddy(data.buddy);
this.total_star = data.total_star;
this.challenge_time = new DeadlyTime(data.challenge_time);
this.avatar_list = data.avatar_list.map(item => new AvatarList(item));
}
async get_assets() {
await Promise.all([
this.buddy.get_assets(),
...this.avatar_list.map(avatar => avatar.get_assets()),
...this.boss.map(boss => boss.get_assets()),
...this.buffer.map(buffer => buffer.get_assets()),
]);
}
}
/**
* @class AvatarList.
*/
export class AvatarList {
/**
* @param {AvatarList} data
*/
constructor(data) {
this.rarity = data.rarity;
this.element_type = data.element_type;
this.avatar_profession = data.avatar_profession;
this.id = data.id;
this.level = data.level;
this.rank = data.rank;
this.role_square_url = data.role_square_url;
this.sub_element_type = data.sub_element_type;
}
async get_assets() {
const role_square_b64 = await request
.get(this.role_square_url, {}, { responseType: 'arraybuffer' })
.then(response => response.arrayBuffer())
.then(
buffer =>
`data:image/png;base64,${Buffer.from(buffer).toString('base64')}`
);
this.role_square_url = role_square_b64;
}
}
/**
* @class Buddy.
*/
export class Buddy {
/**
* @param {Buddy} data
*/
constructor(data) {
this.id = data.id;
this.rarity = data.rarity;
this.level = data.level;
this.bangboo_rectangle_url = data.bangboo_rectangle_url;
}
async get_assets() {
const bangboo_rectangle_b64 = await request
.get(this.bangboo_rectangle_url, {}, { responseType: 'arraybuffer' })
.then(response => response.arrayBuffer())
.then(
buffer =>
`data:image/png;base64,${Buffer.from(buffer).toString('base64')}`
);
this.bangboo_rectangle_url = bangboo_rectangle_b64;
}
}
/**
* @class DeadBuffer.
*/
export class DeadBuffer {
/**
* @param {DeadBuffer} data
*/
constructor(data) {
this.desc = data.desc;
this.icon = data.icon;
this.name = data.name;
}
async get_assets() {
const icon_b64 = await request
.get(this.icon, {}, { responseType: 'arraybuffer' })
.then(response => response.arrayBuffer())
.then(
buffer =>
`data:image/png;base64,${Buffer.from(buffer).toString('base64')}`
);
this.icon = icon_b64;
}
}
/**
* @class Bos.
*/
export class Bos {
/**
* @param {Bos} data
*/
constructor(data) {
this.race_icon = data.race_icon;
this.icon = data.icon;
this.name = data.name;
this.bg_icon = data.bg_icon;
}
async get_assets() {
const race_icon_b64 = request
.get(this.race_icon, {}, { responseType: 'arraybuffer' })
.then(response => response.arrayBuffer())
.then(
buffer =>
`data:image/png;base64,${Buffer.from(buffer).toString('base64')}`
);
const icon_b64 = request
.get(this.icon, {}, { responseType: 'arraybuffer' })
.then(response => response.arrayBuffer())
.then(
buffer =>
`data:image/png;base64,${Buffer.from(buffer).toString('base64')}`
);
const bg_icon_b64 = request
.get(this.bg_icon, {}, { responseType: 'arraybuffer' })
.then(response => response.arrayBuffer())
.then(
buffer =>
`data:image/png;base64,${Buffer.from(buffer).toString('base64')}`
);
const all = await Promise.all([race_icon_b64, icon_b64, bg_icon_b64]);
this.race_icon = all[0];
this.icon = all[1];
this.bg_icon = all[2];
}
}
/**
* @class DeadlyTime.
*/
export class DeadlyTime {
/**
* @param {DeadlyTime} data
*/
constructor(data) {
this.hour = data.hour;
this.minute = data.minute;
this.second = data.second;
this.year = data.year;
this.month = data.month;
this.day = data.day;
}
}

View file

@ -71,7 +71,7 @@
</div>
</div>
{{else}}
<div class="item bangboo rankb"></div>
<div class="item char rankb"></div>
{{/if}}
<% } %>
{{if floor.node_1.buddy}}

Binary file not shown.

After

Width:  |  Height:  |  Size: 996 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

298
resources/deadly/index.css Normal file
View file

@ -0,0 +1,298 @@
.card {
margin: 0 1em;
padding-top: 1em;
}
.card .star {
background-color: rgba(0, 0, 0, 0.5);
background-image: url("./images/star-icon-light.png");
border-radius: 50%;
background-size: contain;
}
.card .overview {
margin: 0.5em;
margin-bottom: 1.5em;
background-image: url("./images/block-bg-m.png");
background-size: 100% 100%;
padding: 2.2em 2.2em 1.8em 2.2em;
}
.card .overview .u-info {
display: flex;
align-items: center;
gap: 0.2em;
margin-bottom: 0.3em;
}
.card .overview .u-info .avatar {
width: 1.2em;
height: 1.2em;
border-radius: 50%;
overflow: hidden;
}
.card .overview .u-info .avatar img {
width: 100%;
height: 100%;
object-fit: cover;
}
.card .overview .content {
display: flex;
justify-content: space-between;
}
.card .overview .content .left {
display: flex;
align-items: center;
gap: 1em;
}
.card .overview .content .left .value {
font-size: 1.7em;
background: linear-gradient(180deg, rgb(255, 255, 255) 0%, rgba(255, 255, 255, 0.4) 100%);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
}
.card .overview .content .left .percent {
background-color: #ec83de;
color: black;
padding: 0 1em 0 0.6em;
border-radius: 1em;
}
.card .overview .content .right {
display: flex;
align-items: center;
gap: 0.3em;
}
.card .overview .content .right .star {
width: 1.5em;
height: 1.5em;
}
.card .tips {
font-size: 0.8em;
margin: 1em;
color: #979797;
}
.card .tips p {
margin-bottom: 0.5em;
}
.card .item-card {
border-image-source: url("./images/BgFrame01.png");
border-image-slice: 200 100 70 280 fill;
border-image-width: 2em 1em 0.7em 2.8em;
border-image-outset: 0em 0em 0em 0em;
border-image-repeat: stretch stretch;
padding: 1.5em 1.7em;
margin-bottom: 1em;
display: flex;
gap: 1.2em;
position: relative;
}
.card .item-card .pop {
position: absolute;
top: 0;
right: 0;
width: 2.5em;
height: 2.5em;
background-image: url("./images/PetSelectBG.png");
background-size: 100% 100%;
padding: 0.3em;
z-index: 2;
}
.card .item-card .pop img {
width: 100%;
height: 100%;
object-fit: contain;
}
.card .item-card .cover {
position: relative;
height: 11em;
border-radius: 0.6em;
overflow: hidden;
border: 0.1em solid #343434;
box-shadow: 0 0 0.5em rgba(0, 0, 0, 0.3), 0.2em 0.2em 0 rgb(0, 0, 0);
flex-shrink: 0;
flex-grow: 0;
}
.card .item-card .cover::before {
content: "";
position: absolute;
border-radius: 0.6em;
z-index: 2;
inset: 0;
border: 0.15em solid rgba(255, 255, 255, 0.3);
}
.card .item-card .cover .bg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.card .item-card .cover .bg img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
.card .item-card .cover .icon {
position: absolute;
bottom: 0.2em;
right: 0.2em;
width: 3em;
height: 3em;
z-index: 3;
}
.card .item-card .cover .icon img {
width: 100%;
height: 100%;
object-fit: contain;
display: block;
}
.card .item-card .cover img {
height: 100%;
position: relative;
z-index: 1;
display: block;
}
.card .item-card .content {
display: flex;
flex-direction: column;
gap: 0.2em;
flex: 1;
margin-right: 0.3em;
}
.card .item-card .content .name {
background: linear-gradient(180deg, rgb(255, 255, 255) 0%, rgba(255, 255, 255, 0.4) 100%);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
font-size: 1.2em;
}
.card .item-card .content .value {
display: flex;
font-size: 1.6em;
gap: 0.2em;
align-items: center;
}
.card .item-card .content .value .val {
background: linear-gradient(180deg, rgb(255, 255, 255) 0%, rgba(255, 255, 255, 0.4) 100%);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
}
.card .item-card .content .value .stars {
display: flex;
margin-left: 0.2em;
align-items: center;
}
.card .item-card .content .value .stars .star {
width: 0.9em;
height: 0.9em;
margin-left: -0.25em;
}
.card .item-card .content .time {
margin-top: 0.3em;
margin-bottom: 0.6em;
font-size: 0.8em;
color: #979797;
}
.card .item-card .content .list {
display: grid;
grid-template-columns: 1fr 1fr 1fr 0.7fr;
align-items: flex-end;
gap: 1em;
margin-top: auto;
margin-bottom: 0.2em;
}
.card .item-card .content .list .item {
width: 100%;
position: relative;
border-radius: 0.5em;
box-shadow: 0 0 0 0.12em black, 0 0 0 0.24em #333534;
}
.card .item-card .content .list .item > * {
position: inherit;
z-index: 1;
}
.card .item-card .content .list .item.bangboo {
font-size: 0.8em;
}
.card .item-card .content .list .item .count {
position: absolute;
right: 0;
top: 0;
z-index: 2;
background-color: rgba(0, 0, 0, 0.5);
padding: 0.1em 0.3em;
font-size: 0.8em;
border-bottom-left-radius: 0.3em;
border-top-right-radius: 0.5em;
}
.card .item-card .content .list .item .rank_disp {
position: absolute;
top: 0em;
left: 0em;
background-color: rgb(0, 0, 0);
z-index: 2;
padding: 0.1em;
border-bottom-right-radius: 0.25em;
border-top-left-radius: 0.25em;
}
.card .item-card .content .list .item .rank_disp .rank {
width: 1em;
color: white;
position: relative;
}
.card .item-card .content .list .item .rank_disp .rank::before {
content: "";
position: absolute;
top: -0.1em;
right: -0.4em;
width: 0.3em;
height: 0.3em;
background: radial-gradient(circle at 100% 0, transparent 0.3em, rgb(0, 0, 0) 0.3em);
rotate: 90deg;
}
.card .item-card .content .list .item .rank_disp .rank::after {
content: "";
position: absolute;
bottom: -0.4em;
left: -0.1em;
width: 0.3em;
height: 0.3em;
background: radial-gradient(circle at 100% 0, transparent 0.3em, rgb(0, 0, 0) 0.3em);
rotate: 90deg;
}
.card .item-card .content .list .item .image {
width: 100%;
aspect-ratio: 1;
border-radius: 0.5em;
overflow: hidden;
}
.card .item-card .content .list .item .image img {
width: 100%;
height: 100%;
object-fit: cover;
object-position: top;
display: block;
}
.card .item-card .content .list .item.bangboo .image {
position: relative;
}
.card .item-card .content .list .item.bangboo .image img {
width: 210%;
height: 200%;
position: absolute;
object-position: center;
top: 50%;
left: 50%;
transform: translate(-40%, -35%);
}
.card .item-card .content .list .item .c-info {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
background: rgb(0, 0, 0);
color: white;
display: flex;
text-align: center;
}
/*# sourceMappingURL=index.css.map */

View file

@ -0,0 +1,95 @@
{{extend defaultLayout}}
{{block 'css'}}
<link rel="stylesheet" href="{{@sys.currentPath}}/index.css">
{{/block}}
{{block 'main'}}
<div class="card">
<div class="overview">
<div class="u-info">
<div class="avatar">
<img src="{{deadly.avatar_icon}}" alt="avatar">
</div>
<div class="nick">{{deadly.nick_name}}</div>
</div>
<div class="content">
<div class="left">
<div class="value">{{deadly.total_score}}</div>
<div class="percent">{{deadly.rank_percent/100}}%</div>
</div>
<div class="right">
<div class="star">
</div>
<div class="value">x{{deadly.total_star}}</div>
</div>
</div>
</div>
<div class="tips">
<p>统计周期 {{deadly.start_time.year}}.{{deadly.start_time.month}}.{{deadly.start_time.day}} -
{{deadly.end_time.year}}.{{deadly.end_time.month}}.{{deadly.end_time.day}}
</p>
<p>*总得分&排名和挑战详情并非同时刷新挑战详情存在2小时左右延迟</p>
</div>
{{each deadly.list item i}}
<div class="item-card">
<div class="pop"><img src="{{item.buffer[0].icon}}" alt=""></div>
<div class="cover">
<div class="bg">
<img src="{{item.boss[0].bg_icon}}" alt="">
</div>
<div class="icon">
<img src="{{item.boss[0].race_icon}}" alt="">
</div>
<img src="{{item.boss[0].icon}}" alt="">
</div>
<div class="content">
<div class="name">{{item.boss[0].name}}</div>
<div class="value">
<div class="val">{{item.score}}</div>
<div class="stars">
<% for(let i=0 ; i < item.total_star ; i++) { %>
<div class="star"></div>
<% } %>
</div>
</div>
<div class="time">通关时刻:{{item.challenge_time.year}}.{{item.challenge_time.month}}.{{item.challenge_time.day}}
{{item.challenge_time.hour}}:{{item.challenge_time.minute}}:{{item.challenge_time.second}}
</div>
<div class="list">
<% for(let i=0 ; i < 3 ; i++) { %>
{{if item.avatar_list?.[i]}}
<div class="item char">
{{if item.avatar_list[i].rank}}
<div class="count">{{item.avatar_list[i].rank}}</div>
{{/if}}
<div class="rank_disp">
<div class="rank rank-icon {{item.avatar_list[i].rarity}}"></div>
</div>
<div class="image">
<img src="{{item.avatar_list[i].role_square_url}}" alt="">
</div>
</div>
{{else}}
<div class="item char"></div>
{{/if}}
<% } %>
{{if item.buddy}}
<div class="item bangboo">
<div class="rank_disp">
<div class="rank rank-icon {{item.buddy.rarity}}"></div>
</div>
<div class="image">
<img src="{{item.buddy.bangboo_rectangle_url}}" alt="">
</div>
</div>
{{else}}
<div class="item bangboo"></div>
{{/if}}
</div>
</div>
</div>
{{/each}}
</div>
{{/block}}

318
resources/deadly/index.scss Normal file
View file

@ -0,0 +1,318 @@
.card {
margin: 0 1em;
padding-top: 1em;
.star {
background-color: rgba(0, 0, 0, 0.5);
background-image: url('./images/star-icon-light.png');
border-radius: 50%;
background-size: contain;
}
.overview {
margin: 0.5em;
margin-bottom: 1.5em;
background-image: url('./images/block-bg-m.png');
background-size: 100% 100%;
padding: 2.2em 2.2em 1.8em 2.2em;
.u-info {
display: flex;
align-items: center;
gap: 0.2em;
margin-bottom: 0.3em;
.avatar {
width: 1.2em;
height: 1.2em;
border-radius: 50%;
overflow: hidden;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
}
.content {
display: flex;
justify-content: space-between;
.left {
display: flex;
align-items: center;
gap: 1em;
.value {
font-size: 1.7em;
background: linear-gradient(
180deg,
rgba(255, 255, 255, 1) 0%,
rgba(255, 255, 255, 0.4) 100%
);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
}
.percent {
background-color: #ec83de;
color: black;
padding: 0 1em 0 0.6em;
border-radius: 1em;
}
}
.right {
display: flex;
align-items: center;
gap: 0.3em;
.star {
width: 1.5em;
height: 1.5em;
}
}
}
}
.tips {
font-size: 0.8em;
margin: 1em;
color: #979797;
p {
margin-bottom: 0.5em;
}
}
.item-card {
border-image-source: url('./images/BgFrame01.png');
border-image-slice: 200 100 70 280 fill;
border-image-width: 2em 1em 0.7em 2.8em;
border-image-outset: 0em 0em 0em 0em;
border-image-repeat: stretch stretch;
padding: 1.5em 1.7em;
margin-bottom: 1em;
display: flex;
gap: 1.2em;
position: relative;
.pop {
position: absolute;
top: 0;
right: 0;
width: 2.5em;
height: 2.5em;
background-image: url('./images/PetSelectBG.png');
background-size: 100% 100%;
padding: 0.3em;
img {
width: 100%;
height: 100%;
object-fit: contain;
}
z-index: 2;
}
.cover {
position: relative;
height: 11em;
border-radius: 0.6em;
overflow: hidden;
border: 0.1em solid #343434;
box-shadow: 0 0 0.5em rgba(0, 0, 0, 0.3), 0.2em 0.2em 0 rgb(0, 0, 0);
flex-shrink: 0;
flex-grow: 0;
&::before {
content: '';
position: absolute;
border-radius: 0.6em;
z-index: 2;
inset: 0;
border: 0.15em solid rgba(255, 255, 255, 0.3);
}
.bg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
}
.icon {
position: absolute;
bottom: 0.2em;
right: 0.2em;
width: 3em;
height: 3em;
z-index: 3;
img {
width: 100%;
height: 100%;
object-fit: contain;
display: block;
}
}
img {
height: 100%;
position: relative;
z-index: 1;
display: block;
}
}
.content {
display: flex;
flex-direction: column;
gap: 0.2em;
flex: 1;
margin-right: 0.3em;
.name {
background: linear-gradient(
180deg,
rgba(255, 255, 255, 1) 0%,
rgba(255, 255, 255, 0.4) 100%
);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
font-size: 1.2em;
}
.value {
display: flex;
font-size: 1.6em;
gap: 0.2em;
align-items: center;
.val {
background: linear-gradient(
180deg,
rgba(255, 255, 255, 1) 0%,
rgba(255, 255, 255, 0.4) 100%
);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
}
.stars {
display: flex;
margin-left: 0.2em;
align-items: center;
.star {
width: 0.9em;
height: 0.9em;
margin-left: -0.25em;
}
}
}
.time {
margin-top: 0.3em;
margin-bottom: 0.6em;
font-size: 0.8em;
color: #979797;
}
.list {
display: grid;
grid-template-columns: 1fr 1fr 1fr 0.7fr;
align-items: flex-end;
gap: 1em;
margin-top: auto;
margin-bottom: 0.2em;
.item {
width: 100%;
position: relative;
border-radius: 0.5em;
box-shadow: 0 0 0 0.12em black, 0 0 0 0.24em #333534;
> * {
position: inherit;
z-index: 1;
}
&.bangboo {
font-size: 0.8em;
}
.count {
position: absolute;
right: 0;
top: 0;
z-index: 2;
background-color: rgba(0, 0, 0, 0.5);
padding: 0.1em 0.3em;
font-size: 0.8em;
border-bottom-left-radius: 0.3em;
border-top-right-radius: 0.5em;
}
.rank_disp {
position: absolute;
top: 0em;
left: 0em;
background-color: rgb(0, 0, 0);
z-index: 2;
padding: 0.1em;
border-bottom-right-radius: 0.25em;
border-top-left-radius: 0.25em;
.rank {
width: 1em;
color: white;
position: relative;
&::before {
content: '';
position: absolute;
top: -0.1em;
right: -0.4em;
width: 0.3em;
height: 0.3em;
background: radial-gradient(
circle at 100% 0,
transparent 0.3em,
rgb(0, 0, 0) 0.3em
);
rotate: 90deg;
}
&::after {
content: '';
position: absolute;
bottom: -0.4em;
left: -0.1em;
width: 0.3em;
height: 0.3em;
background: radial-gradient(
circle at 100% 0,
transparent 0.3em,
rgb(0, 0, 0) 0.3em
);
rotate: 90deg;
}
}
}
.image {
width: 100%;
aspect-ratio: 1;
border-radius: 0.5em;
overflow: hidden;
img {
width: 100%;
height: 100%;
object-fit: cover;
object-position: top;
display: block;
}
}
&.bangboo {
.image {
position: relative;
img {
width: 210%;
height: 200%;
position: absolute;
object-position: center;
top: 50%;
left: 50%;
transform: translate(-40%, -35%);
}
}
}
.c-info {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
background: rgb(0, 0, 0);
color: white;
display: flex;
text-align: center;
}
}
}
}
}
}