mirror of
https://github.com/PaiGramTeam/PaiGram.git
synced 2024-11-21 22:58:05 +00:00
✨ Support calendar
This commit is contained in:
parent
1835eae244
commit
ea94583a5b
@ -457,8 +457,18 @@ class _NamecardAssets(_AssetsService):
|
|||||||
def game_name(self) -> str:
|
def game_name(self) -> str:
|
||||||
return NAMECARD_DATA[str(self.id)]["icon"]
|
return NAMECARD_DATA[str(self.id)]["icon"]
|
||||||
|
|
||||||
|
@lru_cache
|
||||||
|
def _get_id_from_avatar_id(self, avatar_id: Union[int, str]) -> int:
|
||||||
|
avatar_icon_name = AVATAR_DATA[str(avatar_id)]["icon"].replace("AvatarIcon", "NameCardIcon")
|
||||||
|
for namecard_id, namecard_data in NAMECARD_DATA.items():
|
||||||
|
if namecard_data["icon"] == avatar_icon_name:
|
||||||
|
return int(namecard_id)
|
||||||
|
raise ValueError(avatar_id)
|
||||||
|
|
||||||
def __call__(self, target: int) -> "_NamecardAssets":
|
def __call__(self, target: int) -> "_NamecardAssets":
|
||||||
result = _NamecardAssets(self.client)
|
result = _NamecardAssets(self.client)
|
||||||
|
if target > 10000000:
|
||||||
|
target = self._get_id_from_avatar_id(target)
|
||||||
result.id = target
|
result.id = target
|
||||||
result.enka = DEFAULT_EnkaAssets.namecards(target)
|
result.enka = DEFAULT_EnkaAssets.namecards(target)
|
||||||
return result
|
return result
|
||||||
|
@ -9,7 +9,7 @@ from httpx import AsyncClient, RemoteProtocolError, Response, URL
|
|||||||
from utils.const import AMBR_HOST, PROJECT_ROOT
|
from utils.const import AMBR_HOST, PROJECT_ROOT
|
||||||
from utils.log import logger
|
from utils.log import logger
|
||||||
|
|
||||||
__all__ = ["update_metadata_from_ambr", "update_metadata_from_github", "make_github_fast"]
|
__all__ = ["update_metadata_from_ambr", "update_metadata_from_github", "make_github_fast", "RESOURCE_DEFAULT_PATH"]
|
||||||
GENSHIN_PY_DATA_REPO = parse_token("aHR0cHM6Ly9naXRsYWIuY29tL0RpbWJyZWF0aC9nYW1lZGF0YS8tL3Jhdy9tYXN0ZXIv").decode()
|
GENSHIN_PY_DATA_REPO = parse_token("aHR0cHM6Ly9naXRsYWIuY29tL0RpbWJyZWF0aC9nYW1lZGF0YS8tL3Jhdy9tYXN0ZXIv").decode()
|
||||||
RESOURCE_REPO = "PaiGramTeam/PaiGram_Resources"
|
RESOURCE_REPO = "PaiGramTeam/PaiGram_Resources"
|
||||||
RESOURCE_BRANCH = "remote"
|
RESOURCE_BRANCH = "remote"
|
||||||
|
359
modules/apihelper/client/components/calendar.py
Normal file
359
modules/apihelper/client/components/calendar.py
Normal file
@ -0,0 +1,359 @@
|
|||||||
|
import re
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
from typing import List, Tuple, Optional, Dict, Union
|
||||||
|
|
||||||
|
from httpx import AsyncClient
|
||||||
|
|
||||||
|
from core.base.assets import AssetsService
|
||||||
|
from metadata.genshin import AVATAR_DATA
|
||||||
|
from metadata.scripts.metadatas import RESOURCE_DEFAULT_PATH
|
||||||
|
from metadata.shortname import roleToId
|
||||||
|
from modules.apihelper.models.genshin.calendar import Date, FinalAct, ActEnum, ActDetail, ActTime, BirthChar
|
||||||
|
from modules.wiki.character import Character
|
||||||
|
|
||||||
|
|
||||||
|
class Calendar:
|
||||||
|
"""原神活动日历"""
|
||||||
|
|
||||||
|
ANNOUNCEMENT_LIST = "https://hk4e-api.mihoyo.com/common/hk4e_cn/announcement/api/getAnnList"
|
||||||
|
ANNOUNCEMENT_PARAMS = {
|
||||||
|
"game": "hk4e",
|
||||||
|
"game_biz": "hk4e_cn",
|
||||||
|
"lang": "zh-cn",
|
||||||
|
"bundle_id": "hk4e_cn",
|
||||||
|
"platform": "pc",
|
||||||
|
"region": "cn_gf01",
|
||||||
|
"level": "55",
|
||||||
|
"uid": "100000000",
|
||||||
|
}
|
||||||
|
MIAO_API = "http://miaoapi.cn/api/calendar"
|
||||||
|
REMOTE_API = f"https://raw.fastgit.org/{RESOURCE_DEFAULT_PATH}calendar.json"
|
||||||
|
IGNORE_IDS = [
|
||||||
|
495, # 有奖问卷调查开启!
|
||||||
|
1263, # 米游社《原神》专属工具一览
|
||||||
|
423, # 《原神》玩家社区一览
|
||||||
|
422, # 《原神》防沉迷系统说明
|
||||||
|
762, # 《原神》公平运营声明
|
||||||
|
762, # 《原神》公平运营声明
|
||||||
|
]
|
||||||
|
IGNORE_RE = re.compile(r"(内容专题页|版本更新说明|调研|防沉迷|米游社|专项意见|更新修复与优化|问卷调查|版本更新通知|更新时间说明|预下载功能|周边限时|周边上新|角色演示)")
|
||||||
|
FULL_TIME_RE = re.compile(r"(魔神任务)")
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.client = AsyncClient()
|
||||||
|
self.birthday_list = self.gen_birthday_list()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def gen_birthday_list() -> Dict[str, List[str]]:
|
||||||
|
"""生成生日列表"""
|
||||||
|
birthday_list = {}
|
||||||
|
for value in AVATAR_DATA.values():
|
||||||
|
key = "_".join([str(i) for i in value["birthday"]])
|
||||||
|
data = birthday_list.get(key, [])
|
||||||
|
data.append(value["name"])
|
||||||
|
birthday_list[key] = data
|
||||||
|
return birthday_list
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_now_hour() -> datetime:
|
||||||
|
"""获取当前时间"""
|
||||||
|
return datetime.now().replace(minute=0, second=0, microsecond=0)
|
||||||
|
|
||||||
|
async def req_cal_data(self) -> Tuple[List[List[ActDetail]], Dict[str, ActTime]]:
|
||||||
|
"""请求日历数据"""
|
||||||
|
list_data = await self.client.get(self.ANNOUNCEMENT_LIST, params=self.ANNOUNCEMENT_PARAMS)
|
||||||
|
list_data = list_data.json()
|
||||||
|
|
||||||
|
new_list_data = [[], []]
|
||||||
|
for idx, data in enumerate(list_data.get("data", {}).get("list", [])):
|
||||||
|
for item in data.get("list", []):
|
||||||
|
new_list_data[idx].append(ActDetail(**item))
|
||||||
|
time_map = {}
|
||||||
|
req = await self.client.get(self.MIAO_API)
|
||||||
|
if req.status_code == 200:
|
||||||
|
miao_data = req.json()
|
||||||
|
time_map.update({key: ActTime(**value) for key, value in miao_data.get("data", {}).items()})
|
||||||
|
req = await self.client.get(self.REMOTE_API)
|
||||||
|
if req.status_code == 200:
|
||||||
|
remote_data = req.json()
|
||||||
|
time_map.update({key: ActTime(**value) for key, value in remote_data.get("data", {}).items()})
|
||||||
|
return new_list_data, time_map
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def date_to_weekday(date_: datetime) -> str:
|
||||||
|
"""日期转换为星期"""
|
||||||
|
time = ["一", "二", "三", "四", "五", "六", "日"]
|
||||||
|
return time[date_.weekday()]
|
||||||
|
|
||||||
|
async def get_date_list(self) -> Tuple[List[Date], datetime, datetime, timedelta, float]:
|
||||||
|
"""获取日历数据"""
|
||||||
|
data_list: List[Date] = []
|
||||||
|
today = self.get_now_hour()
|
||||||
|
temp = today - timedelta(days=7)
|
||||||
|
month = 0
|
||||||
|
date, week, is_today = [], [], []
|
||||||
|
start_date, end_date = None, None
|
||||||
|
for i in range(13):
|
||||||
|
temp += timedelta(days=1)
|
||||||
|
m, d, w = temp.month, temp.day, self.date_to_weekday(temp)
|
||||||
|
if month == 0:
|
||||||
|
start_date = temp
|
||||||
|
month = m
|
||||||
|
if month != m and len(date) > 0:
|
||||||
|
data_list.append(Date(month=month, date=date, week=week, is_today=is_today))
|
||||||
|
date, week, is_today = [], [], []
|
||||||
|
month = m
|
||||||
|
date.append(d)
|
||||||
|
week.append(w)
|
||||||
|
is_today.append(temp == today)
|
||||||
|
if i == 12:
|
||||||
|
data_list.append(Date(month=month, date=date, week=week, is_today=is_today))
|
||||||
|
end_date = temp
|
||||||
|
start_time = start_date.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||||
|
end_time = end_date.replace(hour=23, minute=59, second=59, microsecond=999999)
|
||||||
|
total_range: timedelta = end_time - start_time
|
||||||
|
now_left: float = (self.get_now_hour() - start_time) / total_range * 100
|
||||||
|
return (
|
||||||
|
data_list,
|
||||||
|
start_time,
|
||||||
|
end_time,
|
||||||
|
total_range,
|
||||||
|
now_left,
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def human_read(d: timedelta) -> str:
|
||||||
|
"""将日期转换为人类可读"""
|
||||||
|
hour = d.seconds // 3600
|
||||||
|
minute = d.seconds // 60 % 60
|
||||||
|
if minute >= 59:
|
||||||
|
hour += 1
|
||||||
|
text = ""
|
||||||
|
if d.days:
|
||||||
|
text += f"{d.days}天"
|
||||||
|
if hour:
|
||||||
|
text += f"{hour}小时"
|
||||||
|
return text
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def count_width(
|
||||||
|
act: FinalAct,
|
||||||
|
detail: Optional[ActTime],
|
||||||
|
ds: ActDetail,
|
||||||
|
start_time: datetime,
|
||||||
|
end_time: datetime,
|
||||||
|
total_range: timedelta,
|
||||||
|
) -> Tuple[datetime, datetime]:
|
||||||
|
"""计算宽度"""
|
||||||
|
|
||||||
|
def get_date(d1: str, d2: str) -> datetime:
|
||||||
|
if d1 and len(d1) > 6:
|
||||||
|
return datetime.strptime(d1, "%Y-%m-%d %H:%M:%S")
|
||||||
|
return datetime.strptime(d2, "%Y-%m-%d %H:%M:%S")
|
||||||
|
|
||||||
|
s_date = get_date(detail and detail.start, ds.start_time)
|
||||||
|
e_date = get_date(detail and detail.end, ds.end_time)
|
||||||
|
s_time = max(s_date, start_time)
|
||||||
|
e_time = min(e_date, end_time)
|
||||||
|
|
||||||
|
s_range = s_time - start_time
|
||||||
|
e_range = e_time - start_time
|
||||||
|
|
||||||
|
act.left = s_range / total_range * 100
|
||||||
|
act.width = e_range / total_range * 100 - act.left
|
||||||
|
act.duration = (e_time - s_time).total_seconds()
|
||||||
|
act.start = s_date.strftime("%m-%d %H:%M")
|
||||||
|
act.end = e_date.strftime("%m-%d %H:%M")
|
||||||
|
return s_date, e_date
|
||||||
|
|
||||||
|
def parse_label(self, act: FinalAct, is_act: bool, s_date: datetime, e_date: datetime) -> None:
|
||||||
|
"""解析活动标签"""
|
||||||
|
now = self.get_now_hour()
|
||||||
|
label = ""
|
||||||
|
if self.FULL_TIME_RE.findall(act.title) or e_date - s_date > timedelta(days=365):
|
||||||
|
label = f"{s_date.strftime('%m-%d %H:%M')} 后永久有效" if s_date < now else "永久有效"
|
||||||
|
elif s_date < now < e_date:
|
||||||
|
label = f'{e_date.strftime("%m-%d %H:%M")} ({self.human_read(e_date - now)}后结束)'
|
||||||
|
if act.width > (38 if is_act else 55):
|
||||||
|
label = f"{s_date.strftime('%m-%d %H:%M')} ~ {label}"
|
||||||
|
elif s_date > now:
|
||||||
|
label = f'{s_date.strftime("%m-%d %H:%M")} ({self.human_read(s_date - now)}后开始)'
|
||||||
|
elif is_act:
|
||||||
|
label = f"{s_date.strftime('%m-%d %H:%M')} ~ {e_date.strftime('%m-%d %H:%M')}"
|
||||||
|
act.label = label
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
async def parse_type(act: FinalAct, assets: AssetsService) -> None:
|
||||||
|
"""解析活动类型"""
|
||||||
|
if "神铸赋形" in act.title:
|
||||||
|
act.type = ActEnum.weapon
|
||||||
|
act.title = re.sub(r"(单手剑|双手剑|长柄武器|弓|法器|·)", "", act.title)
|
||||||
|
act.sort = 2
|
||||||
|
elif "祈愿" in act.title:
|
||||||
|
act.type = ActEnum.character
|
||||||
|
if reg_ret := re.search(r"·(.*)\(", act.title):
|
||||||
|
char_name = reg_ret[1]
|
||||||
|
char = assets.avatar(roleToId(char_name))
|
||||||
|
act.banner = (await assets.namecard(char.id).navbar()).as_uri()
|
||||||
|
act.face = (await char.icon()).as_uri()
|
||||||
|
act.sort = 1
|
||||||
|
elif "纪行" in act.title:
|
||||||
|
act.type = ActEnum.no_display
|
||||||
|
elif act.title == "深渊":
|
||||||
|
act.type = ActEnum.abyss
|
||||||
|
|
||||||
|
async def get_list(
|
||||||
|
self,
|
||||||
|
ds: ActDetail,
|
||||||
|
start_time: datetime,
|
||||||
|
end_time: datetime,
|
||||||
|
total_range: timedelta,
|
||||||
|
time_map: Dict[str, ActTime],
|
||||||
|
is_act: bool,
|
||||||
|
assets: AssetsService,
|
||||||
|
) -> Optional[FinalAct]:
|
||||||
|
"""获取活动列表"""
|
||||||
|
act = FinalAct(
|
||||||
|
id=ds.ann_id,
|
||||||
|
type=ActEnum.activity if is_act else ActEnum.normal,
|
||||||
|
title=ds.title,
|
||||||
|
banner=ds.banner if is_act else "",
|
||||||
|
sort=5 if is_act else 10,
|
||||||
|
icon=ds.tag_icon,
|
||||||
|
)
|
||||||
|
detail: Optional[ActTime] = time_map.get(str(act.id))
|
||||||
|
|
||||||
|
if act.id in self.IGNORE_IDS or self.IGNORE_RE.findall(act.title) or (detail and not detail.display):
|
||||||
|
return None
|
||||||
|
await self.parse_type(act, assets)
|
||||||
|
s_date, e_date = self.count_width(act, detail, ds, start_time, end_time, total_range)
|
||||||
|
self.parse_label(act, is_act, s_date, e_date)
|
||||||
|
|
||||||
|
if s_date <= end_time and e_date >= start_time:
|
||||||
|
act.mergeStatus = 1 if act.type in {ActEnum.activity, ActEnum.normal} else 0
|
||||||
|
return act
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_abyss_cal(start_time: datetime, end_time: datetime) -> List[List[Union[datetime, str]]]:
|
||||||
|
"""获取深渊日历"""
|
||||||
|
last = datetime.now().replace(day=1) - timedelta(days=2)
|
||||||
|
last_month = last.month
|
||||||
|
curr = datetime.now()
|
||||||
|
curr_month = curr.month
|
||||||
|
next_date = last + timedelta(days=40)
|
||||||
|
next_month = next_date.month
|
||||||
|
|
||||||
|
def start(date: datetime, up: bool = False):
|
||||||
|
return date.replace(day=1 if up else 16, hour=4, minute=0, second=0, microsecond=0)
|
||||||
|
|
||||||
|
def end(date: datetime, up: bool = False):
|
||||||
|
return date.replace(day=1 if up else 16, hour=3, minute=59, second=59, microsecond=999999)
|
||||||
|
|
||||||
|
check = [
|
||||||
|
[start(last, False), end(last, True), f"{last_month}月下半"],
|
||||||
|
[start(curr, True), end(curr, False), f"{curr_month}月上半"],
|
||||||
|
[start(curr, False), end(next_date, True), f"{curr_month}月下半"],
|
||||||
|
[start(next_date, True), end(next_date, False), f"{next_month}月上半"],
|
||||||
|
]
|
||||||
|
ret = []
|
||||||
|
for ds in check:
|
||||||
|
s, e, _ = ds
|
||||||
|
if (s <= start_time <= e) or (s <= end_time <= e):
|
||||||
|
ret.append(ds)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
async def get_birthday_char(
|
||||||
|
self, date_list: List[Date], assets: AssetsService
|
||||||
|
) -> Tuple[int, Dict[str, Dict[str, List[BirthChar]]]]:
|
||||||
|
"""获取生日角色"""
|
||||||
|
birthday_char_line = 0
|
||||||
|
birthday_chars = {}
|
||||||
|
for date in date_list:
|
||||||
|
birthday_chars[str(date.month)] = {}
|
||||||
|
for d in date.date:
|
||||||
|
key = f"{date.month}_{d}"
|
||||||
|
if char := self.birthday_list.get(key):
|
||||||
|
birthday_char_line = max(len(char), birthday_char_line)
|
||||||
|
birthday_chars[str(date.month)][str(d)] = []
|
||||||
|
for c in char:
|
||||||
|
character = await Character.get_by_name(c)
|
||||||
|
birthday_chars[str(date.month)][str(d)].append(
|
||||||
|
BirthChar(
|
||||||
|
name=c,
|
||||||
|
star=character.rarity,
|
||||||
|
icon=(await assets.avatar(roleToId(c)).icon()).as_uri(),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return birthday_char_line, birthday_chars
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_merge_next(target: List[FinalAct], li: FinalAct) -> Optional[FinalAct]:
|
||||||
|
"""获取下一个可以合并的活动"""
|
||||||
|
return next(
|
||||||
|
(li2 for li2 in target if (li2.mergeStatus == 1) and (li.left + li.width <= li2.left)),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
|
||||||
|
def merge_list(self, target: List[FinalAct]) -> Tuple[List[List[FinalAct]], int, int]:
|
||||||
|
"""将两个活动合并为一行"""
|
||||||
|
char_count = 0
|
||||||
|
char_old = 0
|
||||||
|
ret: List[List[FinalAct]] = []
|
||||||
|
for idx, li in enumerate(target):
|
||||||
|
if li.type == ActEnum.character:
|
||||||
|
char_count += 1
|
||||||
|
if li.left == 0:
|
||||||
|
char_old += 1
|
||||||
|
li.idx = char_count
|
||||||
|
if li.mergeStatus == 1:
|
||||||
|
if li2 := self.get_merge_next(target[idx + 1 :], li):
|
||||||
|
li.mergeStatus = 2
|
||||||
|
li2.mergeStatus = 2
|
||||||
|
ret.append([li, li2])
|
||||||
|
if li.mergeStatus != 2:
|
||||||
|
li.mergeStatus = 2
|
||||||
|
ret.append([li])
|
||||||
|
return ret, char_count, char_old
|
||||||
|
|
||||||
|
async def get_photo_data(self, assets: AssetsService) -> Dict:
|
||||||
|
"""获取数据"""
|
||||||
|
now = self.get_now_hour()
|
||||||
|
list_data, time_map = await self.req_cal_data()
|
||||||
|
(
|
||||||
|
date_list,
|
||||||
|
start_time,
|
||||||
|
end_time,
|
||||||
|
total_range,
|
||||||
|
now_left,
|
||||||
|
) = await self.get_date_list()
|
||||||
|
birthday_char_line, birthday_chars = await self.get_birthday_char(date_list, assets)
|
||||||
|
target: List[FinalAct] = []
|
||||||
|
abyss: List[FinalAct] = []
|
||||||
|
|
||||||
|
for ds in list_data[1]:
|
||||||
|
if act := await self.get_list(ds, start_time, end_time, total_range, time_map, True, assets):
|
||||||
|
target.append(act)
|
||||||
|
for ds in list_data[0]:
|
||||||
|
if act := await self.get_list(ds, start_time, end_time, total_range, time_map, False, assets):
|
||||||
|
target.append(act)
|
||||||
|
abyss_cal = self.get_abyss_cal(start_time, end_time)
|
||||||
|
for t in abyss_cal:
|
||||||
|
ds = ActDetail(
|
||||||
|
title=f"「深境螺旋」· {t[2]}",
|
||||||
|
start_time=t[0].strftime("%Y-%m-%d %H:%M:%S"),
|
||||||
|
end_time=t[1].strftime("%Y-%m-%d %H:%M:%S"),
|
||||||
|
)
|
||||||
|
if act := await self.get_list(ds, start_time, end_time, total_range, {}, True, assets):
|
||||||
|
abyss.append(act)
|
||||||
|
target.sort(key=lambda x: (x.sort, x.start, x.duration))
|
||||||
|
target, char_count, char_old = self.merge_list(target)
|
||||||
|
return {
|
||||||
|
"date_list": date_list,
|
||||||
|
"now_left": now_left,
|
||||||
|
"list": target,
|
||||||
|
"abyss": abyss,
|
||||||
|
"char_mode": f"char-{char_count}-{char_old}",
|
||||||
|
"now_time": now.strftime("%Y-%m-%d %H 时"),
|
||||||
|
"birthday_char_line": birthday_char_line,
|
||||||
|
"birthday_chars": birthday_chars,
|
||||||
|
}
|
76
modules/apihelper/models/genshin/calendar.py
Normal file
76
modules/apihelper/models/genshin/calendar.py
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
from enum import Enum
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
|
class Date(BaseModel):
|
||||||
|
"""日历日期"""
|
||||||
|
|
||||||
|
month: int
|
||||||
|
date: List[int]
|
||||||
|
week: List[str]
|
||||||
|
is_today: List[bool]
|
||||||
|
|
||||||
|
|
||||||
|
class ActEnum(str, Enum):
|
||||||
|
"""活动类型"""
|
||||||
|
|
||||||
|
character = "character"
|
||||||
|
weapon = "weapon"
|
||||||
|
activity = "activity"
|
||||||
|
normal = "normal"
|
||||||
|
no_display = "pass"
|
||||||
|
abyss = "abyss"
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return self.value
|
||||||
|
|
||||||
|
|
||||||
|
class FinalAct(BaseModel):
|
||||||
|
"""最终活动数据"""
|
||||||
|
|
||||||
|
id: int
|
||||||
|
type: ActEnum
|
||||||
|
title: str
|
||||||
|
banner: str
|
||||||
|
mergeStatus: int = 0
|
||||||
|
face: str = ""
|
||||||
|
icon: str = ""
|
||||||
|
left: float = 0.0
|
||||||
|
width: float = 0.0
|
||||||
|
label: str = ""
|
||||||
|
sort: int = 0
|
||||||
|
idx: int = 0
|
||||||
|
start: str = ""
|
||||||
|
end: str = ""
|
||||||
|
duration: int = 0
|
||||||
|
|
||||||
|
|
||||||
|
class ActDetail(BaseModel):
|
||||||
|
"""活动详情"""
|
||||||
|
|
||||||
|
ann_id: int = 0
|
||||||
|
banner: str = ""
|
||||||
|
tag_icon: str = ""
|
||||||
|
title: str
|
||||||
|
start_time: str
|
||||||
|
end_time: str
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
class ActTime(BaseModel):
|
||||||
|
"""活动时间"""
|
||||||
|
|
||||||
|
title: str = ""
|
||||||
|
start: str = ""
|
||||||
|
end: str = ""
|
||||||
|
display: bool = True
|
||||||
|
|
||||||
|
|
||||||
|
class BirthChar(BaseModel):
|
||||||
|
"""生日角色"""
|
||||||
|
|
||||||
|
name: str
|
||||||
|
star: int
|
||||||
|
icon: str
|
@ -19,6 +19,7 @@ from core.user import UserService
|
|||||||
from core.user.error import UserNotFoundError
|
from core.user.error import UserNotFoundError
|
||||||
from metadata.genshin import AVATAR_DATA
|
from metadata.genshin import AVATAR_DATA
|
||||||
from metadata.shortname import roleToId, roleToName
|
from metadata.shortname import roleToId, roleToName
|
||||||
|
from modules.apihelper.client.components.calendar import Calendar
|
||||||
from utils.bot import get_args
|
from utils.bot import get_args
|
||||||
from utils.decorators.error import error_callable
|
from utils.decorators.error import error_callable
|
||||||
from utils.decorators.restricts import restricts
|
from utils.decorators.restricts import restricts
|
||||||
@ -48,12 +49,7 @@ class BirthdayPlugin(Plugin, BasePlugin):
|
|||||||
cookie_service: CookiesService = None,
|
cookie_service: CookiesService = None,
|
||||||
):
|
):
|
||||||
"""Load Data."""
|
"""Load Data."""
|
||||||
self.birthday_list = {}
|
self.birthday_list = Calendar.gen_birthday_list()
|
||||||
for value in AVATAR_DATA.values():
|
|
||||||
key = "_".join([str(i) for i in value["birthday"]])
|
|
||||||
data = self.birthday_list.get(key, [])
|
|
||||||
data.append(value["name"])
|
|
||||||
self.birthday_list.update({key: data})
|
|
||||||
self.user_service = user_service
|
self.user_service = user_service
|
||||||
self.cookie_service = cookie_service
|
self.cookie_service = cookie_service
|
||||||
|
|
||||||
|
62
plugins/genshin/calendar.py
Normal file
62
plugins/genshin/calendar.py
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
from typing import Dict
|
||||||
|
|
||||||
|
from telegram import Update
|
||||||
|
from telegram.constants import ChatAction
|
||||||
|
from telegram.ext import CallbackContext, MessageHandler, filters
|
||||||
|
|
||||||
|
from core.base.assets import AssetsService
|
||||||
|
from core.base.redisdb import RedisDB
|
||||||
|
from core.baseplugin import BasePlugin
|
||||||
|
from core.plugin import Plugin, handler
|
||||||
|
from core.template import TemplateService
|
||||||
|
from modules.apihelper.client.components.calendar import Calendar
|
||||||
|
from utils.decorators.error import error_callable
|
||||||
|
from utils.decorators.restricts import restricts
|
||||||
|
from utils.log import logger
|
||||||
|
|
||||||
|
try:
|
||||||
|
import ujson as jsonlib
|
||||||
|
except ImportError:
|
||||||
|
import json as jsonlib
|
||||||
|
|
||||||
|
|
||||||
|
class CalendarPlugin(Plugin, BasePlugin):
|
||||||
|
"""活动日历查询"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
template_service: TemplateService = None,
|
||||||
|
assets_service: AssetsService = None,
|
||||||
|
redis: RedisDB = None,
|
||||||
|
):
|
||||||
|
self.template_service = template_service
|
||||||
|
self.assets_service = assets_service
|
||||||
|
self.calendar = Calendar()
|
||||||
|
self.cache = redis.client
|
||||||
|
|
||||||
|
async def _fetch_data(self) -> Dict:
|
||||||
|
if data := await self.cache.get("plugin:calendar"):
|
||||||
|
return jsonlib.loads(data.decode("utf-8"))
|
||||||
|
data = await self.calendar.get_photo_data(self.assets_service)
|
||||||
|
await self.cache.set("plugin:calendar", jsonlib.dumps(data, default=lambda x: x.dict()), ex=1800)
|
||||||
|
return data
|
||||||
|
|
||||||
|
@handler.command("calendar", block=False)
|
||||||
|
@handler(MessageHandler, filters=filters.Regex(r"^(活动)+(日历|日历列表)$"), block=False)
|
||||||
|
@restricts()
|
||||||
|
@error_callable
|
||||||
|
async def command_start(self, update: Update, _: CallbackContext) -> None:
|
||||||
|
user = update.effective_user
|
||||||
|
message = update.effective_message
|
||||||
|
mode = "list" if "列表" in message.text else "calendar"
|
||||||
|
logger.info("用户 %s[%s] 查询日历 | 模式 %s", user.full_name, user.id, mode)
|
||||||
|
await message.reply_chat_action(ChatAction.TYPING)
|
||||||
|
data = await self._fetch_data()
|
||||||
|
data["display_mode"] = mode
|
||||||
|
image = await self.template_service.render(
|
||||||
|
"genshin/calendar/calendar.html",
|
||||||
|
data,
|
||||||
|
query_selector=".container",
|
||||||
|
)
|
||||||
|
await message.reply_chat_action(ChatAction.UPLOAD_PHOTO)
|
||||||
|
await image.reply_photo(message)
|
@ -146,9 +146,16 @@
|
|||||||
<div class="command-description">角色生日</div>
|
<div class="command-description">角色生日</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="command">
|
<div class="command">
|
||||||
<div class="command-name">/birthday_card</div>
|
<div class="command-name">
|
||||||
|
/birthday_card
|
||||||
|
<i class="fa fa-id-card-o ml-2"></i>
|
||||||
|
</div>
|
||||||
<div class="command-description">领取角色生日画片</div>
|
<div class="command-description">领取角色生日画片</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="command">
|
||||||
|
<div class="command-name">/calendar</div>
|
||||||
|
<div class="command-description">活动日历</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
450
resources/genshin/calendar/calendar.css
Normal file
450
resources/genshin/calendar/calendar.css
Normal file
@ -0,0 +1,450 @@
|
|||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
font-size: 18px;
|
||||||
|
color: #1e1f20;
|
||||||
|
transform: scale(1);
|
||||||
|
transform-origin: 0 0;
|
||||||
|
width: 996px;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
width: 996px;
|
||||||
|
padding: 10px 0px 10px 0px;
|
||||||
|
background-size: 100% 100%;
|
||||||
|
}
|
||||||
|
.logo {
|
||||||
|
font-size: 18px;
|
||||||
|
text-align: center;
|
||||||
|
color: #fff;
|
||||||
|
margin: 20px 0 10px 0;
|
||||||
|
}
|
||||||
|
.calendar {
|
||||||
|
min-height: 400px;
|
||||||
|
position: relative;
|
||||||
|
padding: 1px 0;
|
||||||
|
width: 956px;
|
||||||
|
margin: 20px;
|
||||||
|
box-shadow: 0 0 0 10px rgba(0, 0, 0, 0.6);
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
.cal-bg {
|
||||||
|
position: absolute;
|
||||||
|
width: 956px;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
text-align: center;
|
||||||
|
border-collapse: collapse;
|
||||||
|
height: 100%;
|
||||||
|
box-shadow: 0 0 1px 0 #fff inset;
|
||||||
|
border-radius: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.cal-bg table {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.cal-bg .tr.thead {
|
||||||
|
background: rgba(0, 0, 0, 0.8);
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
.cal-bg td {
|
||||||
|
box-shadow: 0 0 1px 0 #fff;
|
||||||
|
}
|
||||||
|
.cal-bg td.date {
|
||||||
|
width: 7.692%;
|
||||||
|
}
|
||||||
|
.cal-bg td.date span {
|
||||||
|
display: block;
|
||||||
|
line-height: 18px;
|
||||||
|
}
|
||||||
|
.cal-bg td.date span.date-week {
|
||||||
|
line-height: 12px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
.cal-bg td.date.current-date {
|
||||||
|
background: #d3bc8e;
|
||||||
|
border: 1px solid #d3bc8e;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
.cal-bg td.date.current-date span.date-week {
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
.cal-bg td.line {
|
||||||
|
background: rgba(0, 0, 0, 0.4);
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
.cal-bg td.line.current-date {
|
||||||
|
background: rgba(211, 188, 142, 0.4);
|
||||||
|
}
|
||||||
|
.cal-bg .card {
|
||||||
|
width: 65px;
|
||||||
|
height: 76px;
|
||||||
|
margin: 8px auto -4px;
|
||||||
|
}
|
||||||
|
.cal-bg .card .img {
|
||||||
|
height: 60px;
|
||||||
|
}
|
||||||
|
.cal-bg .card .char-name {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
line-height: 17px;
|
||||||
|
font-size: 12px;
|
||||||
|
background: #e8e2d8;
|
||||||
|
}
|
||||||
|
.cal-list {
|
||||||
|
position: relative;
|
||||||
|
padding-top: 80px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.cal-list.char-num-0 {
|
||||||
|
padding-top: 80px;
|
||||||
|
}
|
||||||
|
.cal-list.char-num-1 {
|
||||||
|
padding-top: 160px;
|
||||||
|
}
|
||||||
|
.cal-list.char-num-2 {
|
||||||
|
padding-top: 240px;
|
||||||
|
}
|
||||||
|
.cal-list.char-num-3 {
|
||||||
|
padding-top: 320px;
|
||||||
|
}
|
||||||
|
.cal-list .cal-item {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
border-radius: 5px;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
background: #e8e2d8;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
.cal-list .cal-item:after {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
left: 3px;
|
||||||
|
top: 3px;
|
||||||
|
right: 4px;
|
||||||
|
bottom: 4px;
|
||||||
|
box-shadow: 0 0 1px 0 #000 inset, 0 0 2px 0 #222a3b;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
.cal-list .cal-item .info {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 15px 50px 15px 55px;
|
||||||
|
min-width: calc(100% - 400px);
|
||||||
|
border-radius: 5px;
|
||||||
|
background-image: linear-gradient(to right, #E8E2D8, #E8E2D8 80%, rgba(232, 226, 216, 0) 100%);
|
||||||
|
}
|
||||||
|
.cal-list .cal-item .banner {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 500px;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
background-size: 100% auto;
|
||||||
|
background-position: left 40%;
|
||||||
|
}
|
||||||
|
.cal-list .cal-item strong {
|
||||||
|
display: block;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
.cal-list .cal-item span {
|
||||||
|
display: block;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.cal-list .cal-item.type-character {
|
||||||
|
overflow: visible;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
.cal-list .cal-item.type-character .info {
|
||||||
|
padding-left: 65px;
|
||||||
|
}
|
||||||
|
.cal-list .cal-item.type-character .character-img {
|
||||||
|
height: 75px;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
.cal-list .cal-item.type-normal {
|
||||||
|
margin-top: 5px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
.cal-list .cal-item.type-normal:last-child {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
.cal-list .cal-item.type-normal:after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.cal-list .cal-item.type-normal:first-of-type {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
.cal-list .cal-item.type-normal .info {
|
||||||
|
padding: 8px 20px 8px 15px;
|
||||||
|
line-height: 16px;
|
||||||
|
color: #4b5366;
|
||||||
|
}
|
||||||
|
.cal-list .cal-item.type-normal .cal-icon {
|
||||||
|
width: 23px;
|
||||||
|
height: 23px;
|
||||||
|
top: 6px;
|
||||||
|
margin-left: -3px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
.cal-list .cal-item.type-normal strong {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
.cal-list .cal-item.type-normal .info {
|
||||||
|
padding-left: 38px;
|
||||||
|
}
|
||||||
|
.cal-list .cal-item.type-normal strong,
|
||||||
|
.cal-list .cal-item.type-normal span {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
.cal-list .cal-item.type-normal.small-mode span {
|
||||||
|
display: block;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
.cal-list .cal-item.type-normal.li-col1 {
|
||||||
|
margin-top: -40px;
|
||||||
|
}
|
||||||
|
.cal-list .cal-item .cal-icon {
|
||||||
|
position: absolute;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
left: 10px;
|
||||||
|
top: 10px;
|
||||||
|
}
|
||||||
|
.cal-list .cal-item.li-col1 {
|
||||||
|
margin-top: -82px;
|
||||||
|
}
|
||||||
|
.cal-list.char-2-1 .type-character.li-idx-2,
|
||||||
|
.cal-list.char-3-1 .type-character.li-idx-2 {
|
||||||
|
margin-top: -82px;
|
||||||
|
}
|
||||||
|
.cal-list.char-3-2 .type-character.li-idx-3 {
|
||||||
|
margin-top: -82px;
|
||||||
|
}
|
||||||
|
.cal-list.char-4-2 .type-character.li-idx-3 {
|
||||||
|
margin-top: -166px;
|
||||||
|
}
|
||||||
|
.cal-list .type-weapon.li-idx-2 {
|
||||||
|
margin-top: -82px;
|
||||||
|
}
|
||||||
|
.calendar .now-line {
|
||||||
|
position: absolute;
|
||||||
|
top: 86px;
|
||||||
|
bottom: -18px;
|
||||||
|
width: 2px;
|
||||||
|
box-shadow: 0 0 5px 0 #fff;
|
||||||
|
background: #fff;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
.calendar .now-line:after {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border-left: 10px solid transparent;
|
||||||
|
border-right: 10px solid transparent;
|
||||||
|
border-bottom: 20px solid #fff;
|
||||||
|
position: absolute;
|
||||||
|
bottom: -8px;
|
||||||
|
left: -9px;
|
||||||
|
transform: scaleY(0.7);
|
||||||
|
transform-origin: bottom center;
|
||||||
|
}
|
||||||
|
.calendar .now-line.line2 {
|
||||||
|
z-index: 3;
|
||||||
|
opacity: 0.5;
|
||||||
|
background: #d3bc8d;
|
||||||
|
width: 2px;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
.now-time {
|
||||||
|
text-align: center;
|
||||||
|
padding-top: 5px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
.now-time span {
|
||||||
|
color: #fff;
|
||||||
|
background: rgba(0, 0, 0, 0.6);
|
||||||
|
border-radius: 30px;
|
||||||
|
padding: 10px 15px;
|
||||||
|
border: 1px solid #fff;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.cal-abyss-cont {
|
||||||
|
padding-top: 15px;
|
||||||
|
height: 80px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.cal-abyss-cont .cal-item {
|
||||||
|
border-radius: 0;
|
||||||
|
background: url("img/abyss.jpg") #333465 top right no-repeat;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
.cal-abyss-cont .cal-item .info {
|
||||||
|
background: none;
|
||||||
|
color: #d3bc8d;
|
||||||
|
background-image: linear-gradient(to right, #333465, #333465 80%, rgba(51, 52, 101, 0) 100%);
|
||||||
|
}
|
||||||
|
.cal-abyss-cont .cal-item:before {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
width: 3px;
|
||||||
|
left: 0;
|
||||||
|
top: 1px;
|
||||||
|
bottom: 1px;
|
||||||
|
position: absolute;
|
||||||
|
background: #d3bc8d;
|
||||||
|
z-index: 8;
|
||||||
|
}
|
||||||
|
.cal-abyss-cont .cal-item:after {
|
||||||
|
box-shadow: 0 0 1px 0 #fff;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
.calendar-mode .for-list-mode {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.list-mode .container {
|
||||||
|
width: 740px;
|
||||||
|
}
|
||||||
|
.list-mode .for-calendar-mode {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.list-mode .cal-bg {
|
||||||
|
width: initial;
|
||||||
|
}
|
||||||
|
.list-mode .cal-list {
|
||||||
|
padding: 45px 10px 0;
|
||||||
|
}
|
||||||
|
.list-mode .calendar {
|
||||||
|
width: 700px;
|
||||||
|
}
|
||||||
|
.list-mode .cal-abyss-cont {
|
||||||
|
height: initial !important;
|
||||||
|
}
|
||||||
|
.list-mode .cal-item {
|
||||||
|
position: relative;
|
||||||
|
margin-left: 0 !important;
|
||||||
|
width: initial !important;
|
||||||
|
left: 0 !important;
|
||||||
|
}
|
||||||
|
.list-mode .now-line {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.daily-talent {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin: 5px 10px 0;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
padding: 10px 9px 10px;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
.daily-talent .item-icon {
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
.daily-talent .card {
|
||||||
|
width: 87px;
|
||||||
|
height: 105px;
|
||||||
|
margin: 10px 0 15px;
|
||||||
|
}
|
||||||
|
.daily-talent .card .item-icon {
|
||||||
|
width: 77px;
|
||||||
|
margin: 0 6px;
|
||||||
|
height: 82px;
|
||||||
|
padding-top: 5px;
|
||||||
|
}
|
||||||
|
.daily-talent .card .img {
|
||||||
|
width: 77px;
|
||||||
|
height: 77px;
|
||||||
|
}
|
||||||
|
.daily-talent .card .weekly {
|
||||||
|
position: absolute;
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
border-radius: 50%;
|
||||||
|
bottom: -10px;
|
||||||
|
right: -3px;
|
||||||
|
background-color: rgba(232, 226, 216, 0.9);
|
||||||
|
box-shadow: 0 0 2px 0 #000;
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
.daily-talent .card .weekly .weekly-icon {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
margin: -3px;
|
||||||
|
background-size: contain;
|
||||||
|
background-position: center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
.daily-talent .card .banner {
|
||||||
|
height: 20px;
|
||||||
|
padding-top: 1px;
|
||||||
|
line-height: 20px;
|
||||||
|
color: #fff;
|
||||||
|
position: relative;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
.daily-talent .card .banner .title {
|
||||||
|
margin-right: -50px;
|
||||||
|
width: calc(100% + 50px);
|
||||||
|
display: flex;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 2;
|
||||||
|
text-shadow: 0 0 1px rgba(0, 0, 0, 0.8), 1px 1px 2px rgba(0, 0, 0, 0.8);
|
||||||
|
padding-left: 45px;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
.daily-talent .card .banner .icon {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
background-size: contain;
|
||||||
|
background-position: center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
display: inline-block;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: -8px;
|
||||||
|
}
|
||||||
|
.daily-talent .card .banner .line {
|
||||||
|
height: 6px;
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 13px;
|
||||||
|
}
|
||||||
|
.daily-talent .card .banner .line.first {
|
||||||
|
margin-left: 35%;
|
||||||
|
width: 65%;
|
||||||
|
border-radius: 3px 0 0 3px;
|
||||||
|
}
|
||||||
|
.daily-talent .card .banner .line.last {
|
||||||
|
width: 94%;
|
||||||
|
border-radius: 0 3px 3px 0;
|
||||||
|
}
|
||||||
|
.daily-talent .card .banner.city-1 .line {
|
||||||
|
background: #37c9b8;
|
||||||
|
}
|
||||||
|
.daily-talent .card .banner.city-2 .line {
|
||||||
|
background: #bca244;
|
||||||
|
}
|
||||||
|
.daily-talent .card .banner.city-3 .line {
|
||||||
|
background: #ac60c9;
|
||||||
|
}
|
||||||
|
.daily-talent .card .banner.city-4 .line {
|
||||||
|
background: #54b640;
|
||||||
|
}
|
||||||
|
/*# sourceMappingURL=calendar.css.map */
|
103
resources/genshin/calendar/calendar.html
Normal file
103
resources/genshin/calendar/calendar.html
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-cn">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width">
|
||||||
|
<link rel="shortcut icon" href="#"/>
|
||||||
|
<link rel="stylesheet" type="text/css" href="common.css"/>
|
||||||
|
<title>Calendar</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="calendar.css"/>
|
||||||
|
</head>
|
||||||
|
<body class="elem-hydro {{ display_mode }}-mode" style=transform:scale(1)>
|
||||||
|
<div class="container elem-bg" id="container">
|
||||||
|
<div class="calendar">
|
||||||
|
<div class="cal-bg for-calendar-mode">
|
||||||
|
<table class="cont-table" border-collapse="collapse">
|
||||||
|
<tr class="tr thead">
|
||||||
|
{% for d in date_list %}
|
||||||
|
<td colspan="{{ d.date.__len__() }}" class="td month">{{ d.month }}月</td>
|
||||||
|
{% endfor %}
|
||||||
|
</tr>
|
||||||
|
<tr class="tr thead">
|
||||||
|
{% for d in date_list %}
|
||||||
|
{% for dn in range(d.date.__len__()) %}
|
||||||
|
<td class="td date {{ 'current-date' if d.is_today[dn] else ''}}">
|
||||||
|
<span class="date-num">{{ d.date[dn] }}日</span>
|
||||||
|
<span class="date-week">周{{ d.week[dn] }}</span>
|
||||||
|
</td>
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
</tr>
|
||||||
|
<tr class="tr">
|
||||||
|
{% for d in date_list %}
|
||||||
|
{% for dn in range(d.date.__len__()) %}
|
||||||
|
<td class="line {{ 'current-date' if d.is_today[dn] else ''}}">
|
||||||
|
{% for char in birthday_chars[d.month|string][d.date[dn]|string] %}
|
||||||
|
<div class="card">
|
||||||
|
<div class="item-icon star{{ char.star }}">
|
||||||
|
<div class="img" style="background-image:url('{{ char.icon }}')"></div>
|
||||||
|
<span class="char-name">{{ char.name }}{{ '生日' if char.name.__len__() < 4 else '' }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</td>
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="cal-bg for-list-mode">
|
||||||
|
<table class="cont-table" border-collapse="collapse">
|
||||||
|
<tr class="tr thead">
|
||||||
|
<td class="td month">活动列表</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="tr">
|
||||||
|
<td class="line"></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="cal-list {{ char_mode }} char-num-{{ birthday_char_line }}">
|
||||||
|
<div class="cal-abyss-cont">
|
||||||
|
{% for li in abyss %}
|
||||||
|
<div class="cal-item type-abyss" style="left:{{ li.left }}%;width:{{li.width}}%">
|
||||||
|
<div class="info">
|
||||||
|
<img src="img/abyss-icon.png" class="cal-icon"/>
|
||||||
|
<strong>{{ li.title }}</strong>
|
||||||
|
<span>{{ li.label }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% for lis in list %}
|
||||||
|
{% for li in lis %}
|
||||||
|
<div
|
||||||
|
class="cal-item type-{{ li.type }} {{ 'li-idx-' if li.idx else ''}}{{ li.idx if li.idx else '' }} {{'small-mode' if li.width < 20 else ''}} li-col{{ lis.index(li) }}"
|
||||||
|
style="left:{{ li.left }}%;width:{{li.width}}%"
|
||||||
|
data-id="{{li.id}}"
|
||||||
|
data-type="{{li.type}}">
|
||||||
|
{% if li.banner %}
|
||||||
|
<div class="banner" style="background-image:url('{{li.banner}}')"></div>
|
||||||
|
{% endif %}
|
||||||
|
<div class="info">
|
||||||
|
{% if li.type == "character" %}
|
||||||
|
<img src="{{ li.face }}" class="character-img"/>
|
||||||
|
{% else %}
|
||||||
|
<img src="{{ li.icon }}" class="cal-icon"/>
|
||||||
|
{% endif %}
|
||||||
|
<strong>{{ li.title }}</strong>
|
||||||
|
<span>{{ li.label }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<div class="now-line" style="left:{{now_left}}%"></div>
|
||||||
|
<div class="now-line line2" style="left:{{now_left}}%"></div>
|
||||||
|
</div>
|
||||||
|
<div class="now-time">
|
||||||
|
<span>{{ now_time }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="copyright">Inspired By Miao-Plugin</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
573
resources/genshin/calendar/calendar.less
Normal file
573
resources/genshin/calendar/calendar.less
Normal file
@ -0,0 +1,573 @@
|
|||||||
|
//linear-gradient(to right, rgba(232, 226, 216, 1), rgba(232, 226, 216, 1) 80%, rgba(232, 226, 216, 0) 100%);
|
||||||
|
|
||||||
|
.linear-bg(@color) {
|
||||||
|
background-image: linear-gradient(to right, @color, @color 80%, fade(@color, 0) 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-size: 18px;
|
||||||
|
color: #1e1f20;
|
||||||
|
transform: scale(1);
|
||||||
|
transform-origin: 0 0;
|
||||||
|
width: 996px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
width: 996px;
|
||||||
|
padding: 10px 0px 10px 0px;
|
||||||
|
background-size: 100% 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
font-size: 18px;
|
||||||
|
text-align: center;
|
||||||
|
color: #fff;
|
||||||
|
margin: 20px 0 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar {
|
||||||
|
min-height: 400px;
|
||||||
|
position: relative;
|
||||||
|
padding: 1px 0;
|
||||||
|
width: 956px;
|
||||||
|
margin: 20px;
|
||||||
|
box-shadow: 0 0 0 10px rgba(0, 0, 0, .6);
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cal-bg {
|
||||||
|
position: absolute;
|
||||||
|
width: 956px;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
text-align: center;
|
||||||
|
border-collapse: collapse;
|
||||||
|
height: 100%;
|
||||||
|
box-shadow: 0 0 1px 0 #fff inset;
|
||||||
|
border-radius: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
table {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.tr.thead {
|
||||||
|
background: rgba(0, 0, 0, .8);
|
||||||
|
height: 40px;
|
||||||
|
|
||||||
|
td {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
box-shadow: 0 0 1px 0 #fff;
|
||||||
|
|
||||||
|
&.date {
|
||||||
|
width: 7.692%;
|
||||||
|
|
||||||
|
span {
|
||||||
|
display: block;
|
||||||
|
line-height: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.date-num {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
span.date-week {
|
||||||
|
line-height: 12px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.current-date {
|
||||||
|
background: #d3bc8e;
|
||||||
|
border: 1px solid #d3bc8e;
|
||||||
|
color: #000;
|
||||||
|
|
||||||
|
span.date-week {
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
&.line {
|
||||||
|
background: rgba(0, 0, 0, 0.4);
|
||||||
|
vertical-align: top;
|
||||||
|
|
||||||
|
&.current-date {
|
||||||
|
background: rgba(211, 188, 142, .4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
width: 65px;
|
||||||
|
height: 76px;
|
||||||
|
margin: 8px auto -4px;
|
||||||
|
|
||||||
|
.img {
|
||||||
|
height: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.char-name {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
line-height: 17px;
|
||||||
|
font-size: 12px;
|
||||||
|
background: #e8e2d8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.cal-list {
|
||||||
|
position: relative;
|
||||||
|
padding-top: 80px;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&.char-num-0 {
|
||||||
|
padding-top: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.char-num-1 {
|
||||||
|
padding-top: 160px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.char-num-2 {
|
||||||
|
padding-top: 240px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.char-num-3 {
|
||||||
|
padding-top: 320px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cal-item {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
border-radius: 5px;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
background: rgba(232, 226, 216, 1);
|
||||||
|
z-index: 1;
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
left: 3px;
|
||||||
|
top: 3px;
|
||||||
|
right: 4px;
|
||||||
|
bottom: 4px;
|
||||||
|
box-shadow: 0 0 1px 0 #000 inset, 0 0 2px 0 #222a3b;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 15px 50px 15px 55px;
|
||||||
|
min-width: calc(100% - 400px);
|
||||||
|
border-radius: 5px;
|
||||||
|
.linear-bg(#E8E2D8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 500px;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
background-size: 100% auto;
|
||||||
|
background-position: left 40%;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
strong {
|
||||||
|
display: block;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
display: block;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
&.type-character {
|
||||||
|
overflow: visible;
|
||||||
|
margin-top: 20px;
|
||||||
|
|
||||||
|
.info {
|
||||||
|
padding-left: 65px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.character-img {
|
||||||
|
height: 75px;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 10;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.type-normal {
|
||||||
|
margin-top: 5px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
&:first-of-type {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
padding: 8px 20px 8px 15px;
|
||||||
|
line-height: 16px;
|
||||||
|
color: #4b5366;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cal-icon {
|
||||||
|
|
||||||
|
width: 23px;
|
||||||
|
height: 23px;
|
||||||
|
top: 6px;
|
||||||
|
margin-left: -3px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
strong {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
padding-left: 38px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
strong,
|
||||||
|
span {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
&.small-mode span {
|
||||||
|
display: block;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.li-col1 {
|
||||||
|
margin-top: -40px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.cal-icon {
|
||||||
|
position: absolute;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
left: 10px;
|
||||||
|
top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.li-col1 {
|
||||||
|
margin-top: -82px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.char-2-1,
|
||||||
|
&.char-3-1 {
|
||||||
|
.type-character.li-idx-2 {
|
||||||
|
margin-top: -82px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.char-3-2 {
|
||||||
|
.type-character.li-idx-3 {
|
||||||
|
margin-top: -82px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.char-4-2 {
|
||||||
|
.type-character.li-idx-3 {
|
||||||
|
margin-top: -166px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.type-weapon.li-idx-2 {
|
||||||
|
margin-top: -82px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar .now-line {
|
||||||
|
position: absolute;
|
||||||
|
top: 86px;
|
||||||
|
bottom: -18px;
|
||||||
|
width: 2px;
|
||||||
|
box-shadow: 0 0 5px 0 #fff;
|
||||||
|
background: #fff;
|
||||||
|
opacity: .8;
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border-left: 10px solid transparent;
|
||||||
|
border-right: 10px solid transparent;
|
||||||
|
border-bottom: 20px solid #fff;
|
||||||
|
position: absolute;
|
||||||
|
bottom: -8px;
|
||||||
|
left: -9px;
|
||||||
|
transform: scaleY(.7);
|
||||||
|
transform-origin: bottom center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.line2 {
|
||||||
|
z-index: 3;
|
||||||
|
opacity: .5;
|
||||||
|
background: rgb(211, 188, 141);
|
||||||
|
width: 2px;
|
||||||
|
box-shadow: none;
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.now-time {
|
||||||
|
text-align: center;
|
||||||
|
padding-top: 5px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
|
||||||
|
span {
|
||||||
|
color: #fff;
|
||||||
|
background: rgba(0, 0, 0, 0.6);
|
||||||
|
border-radius: 30px;
|
||||||
|
padding: 10px 15px;
|
||||||
|
border: 1px solid #fff;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.cal-abyss-cont {
|
||||||
|
padding-top: 15px;
|
||||||
|
height: 80px;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.cal-item {
|
||||||
|
border-radius: 0;
|
||||||
|
background: url("img/abyss.jpg") #333465 top right no-repeat;
|
||||||
|
position: absolute;
|
||||||
|
|
||||||
|
.info {
|
||||||
|
background: none;
|
||||||
|
color: rgba(211, 188, 141, 1);
|
||||||
|
.linear-bg(#333465);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
width: 3px;
|
||||||
|
left: 0;
|
||||||
|
top: 1px;
|
||||||
|
bottom: 1px;
|
||||||
|
position: absolute;
|
||||||
|
background: #d3bc8d;
|
||||||
|
z-index: 8;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
box-shadow: 0 0 1px 0 #fff;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-mode {
|
||||||
|
.for-list-mode {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-mode {
|
||||||
|
|
||||||
|
.container {
|
||||||
|
width: 740px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.for-calendar-mode {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cal-bg {
|
||||||
|
width: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cal-list {
|
||||||
|
padding: 45px 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar {
|
||||||
|
width: 700px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cal-abyss-cont {
|
||||||
|
height: initial !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cal-item {
|
||||||
|
position: relative;
|
||||||
|
margin-left: 0 !important;
|
||||||
|
width: initial !important;
|
||||||
|
left: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.now-line {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@width: 77px;
|
||||||
|
|
||||||
|
.daily-talent {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin: 5px 10px 0;
|
||||||
|
background: rgba(0, 0, 0, .5);
|
||||||
|
padding: 10px 9px 10px;
|
||||||
|
border-radius: 10px;
|
||||||
|
|
||||||
|
|
||||||
|
.item-icon {
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
width: @width + 10px;
|
||||||
|
height: @width + 28px;
|
||||||
|
margin: 10px 0 15px;
|
||||||
|
|
||||||
|
|
||||||
|
.item-icon {
|
||||||
|
width: @width;
|
||||||
|
margin: 0 6px;
|
||||||
|
height: @width + 5px;
|
||||||
|
padding-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.img {
|
||||||
|
width: @width;
|
||||||
|
height: @width;
|
||||||
|
}
|
||||||
|
|
||||||
|
.weekly {
|
||||||
|
position: absolute;
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
border-radius: 50%;
|
||||||
|
bottom: -10px;
|
||||||
|
right: -3px;
|
||||||
|
background-color: rgba(232, 226, 216, 0.9);
|
||||||
|
box-shadow: 0 0 2px 0 #000;
|
||||||
|
overflow: visible;
|
||||||
|
|
||||||
|
.weekly-icon {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
margin: -3px;
|
||||||
|
background-size: contain;
|
||||||
|
background-position: center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner {
|
||||||
|
height: 20px;
|
||||||
|
padding-top: 1px;
|
||||||
|
line-height: 20px;
|
||||||
|
color: #fff;
|
||||||
|
position: relative;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
margin-right: -50px;
|
||||||
|
width: calc(100% + 50px);
|
||||||
|
display: flex;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 2;
|
||||||
|
text-shadow: 0 0 1px rgba(0, 0, 0, .8), 1px 1px 2px rgba(0, 0, 0, .8);
|
||||||
|
padding-left: 45px;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
background-size: contain;
|
||||||
|
background-position: center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
display: inline-block;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: -8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line {
|
||||||
|
height: 6px;
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 13px;
|
||||||
|
|
||||||
|
&.first {
|
||||||
|
margin-left: 35%;
|
||||||
|
width: 65%;
|
||||||
|
border-radius: 3px 0 0 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.last {
|
||||||
|
width: 94%;
|
||||||
|
border-radius: 0 3px 3px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.city(@name, @bg) {
|
||||||
|
&.city-@{name} .line {
|
||||||
|
background: @bg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.city(1, #37c9b8);
|
||||||
|
.city(2, #bca244);
|
||||||
|
.city(3, #ac60c9);
|
||||||
|
.city(4, #54b640);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
521
resources/genshin/calendar/common.css
Normal file
521
resources/genshin/calendar/common.css
Normal file
@ -0,0 +1,521 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: 'Number';
|
||||||
|
src: url("../../fonts/tttgbnumber.ttf") format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'YS';
|
||||||
|
src: url("../../fonts/HYWenHei-65W.ttf") format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
.font-ys {
|
||||||
|
font-family: Number, "汉仪文黑-65W", YS, PingFangSC-Medium, "PingFang SC", sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-size: 18px;
|
||||||
|
color: #1e1f20;
|
||||||
|
font-family: Number, "汉仪文黑-65W", YS, PingFangSC-Medium, "PingFang SC", sans-serif;
|
||||||
|
transform: scale(1.4);
|
||||||
|
transform-origin: 0 0;
|
||||||
|
width: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
width: 600px;
|
||||||
|
padding: 20px 15px 10px 15px;
|
||||||
|
background-size: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
.head-box {
|
||||||
|
border-radius: 15px;
|
||||||
|
padding: 10px 20px;
|
||||||
|
position: relative;
|
||||||
|
color: #fff;
|
||||||
|
margin-top: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.head-box .title {
|
||||||
|
font-family: Number, "汉仪文黑-65W", YS, PingFangSC-Medium, "PingFang SC", sans-serif;
|
||||||
|
font-size: 36px;
|
||||||
|
text-shadow: 0 0 1px #000, 1px 1px 3px rgba(0, 0, 0, 0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
.head-box .title .label {
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.head-box .genshin_logo {
|
||||||
|
position: absolute;
|
||||||
|
top: 1px;
|
||||||
|
right: 15px;
|
||||||
|
width: 97px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.head-box .label {
|
||||||
|
font-size: 16px;
|
||||||
|
text-shadow: 0 0 1px #000, 1px 1px 3px rgba(0, 0, 0, 0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
.head-box .label span {
|
||||||
|
color: #d3bc8e;
|
||||||
|
padding: 0 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice {
|
||||||
|
color: #888;
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: right;
|
||||||
|
padding: 12px 5px 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice-center {
|
||||||
|
color: #fff;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
text-shadow: 1px 1px 1px #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.copyright {
|
||||||
|
font-size: 14px;
|
||||||
|
text-align: center;
|
||||||
|
color: #fff;
|
||||||
|
position: relative;
|
||||||
|
padding-left: 10px;
|
||||||
|
text-shadow: 1px 1px 1px #000;
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.copyright .version {
|
||||||
|
color: #d3bc8e;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
.cons {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
padding: 0 5px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cons-0 {
|
||||||
|
background: #666;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cons-n0 {
|
||||||
|
background: #404949;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cons-1 {
|
||||||
|
background: #5cbac2;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cons-2 {
|
||||||
|
background: #339d61;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cons-3 {
|
||||||
|
background: #3e95b9;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cons-4 {
|
||||||
|
background: #3955b7;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cons-5 {
|
||||||
|
background: #531ba9cf;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cons-6 {
|
||||||
|
background: #ff5722;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cons2-0 {
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #666;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cons2-1 {
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #71b1b7;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cons2-2 {
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #369961;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cons2-3 {
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #4596b9;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cons2-4 {
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #4560b9;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cons2-5 {
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #531ba9cf;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cons2-6 {
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #ff5722;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******** Fetter ********/
|
||||||
|
.fetter {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
display: inline-block;
|
||||||
|
background: url('img/fetter.png');
|
||||||
|
background-size: auto 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fetter.fetter1 {
|
||||||
|
background-position: 0% 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fetter.fetter2 {
|
||||||
|
background-position: 11.11111111% 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fetter.fetter3 {
|
||||||
|
background-position: 22.22222222% 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fetter.fetter4 {
|
||||||
|
background-position: 33.33333333% 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fetter.fetter5 {
|
||||||
|
background-position: 44.44444444% 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fetter.fetter6 {
|
||||||
|
background-position: 55.55555556% 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fetter.fetter7 {
|
||||||
|
background-position: 66.66666667% 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fetter.fetter8 {
|
||||||
|
background-position: 77.77777778% 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fetter.fetter9 {
|
||||||
|
background-position: 88.88888889% 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fetter.fetter10 {
|
||||||
|
background-position: 100% 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******** ELEM ********/
|
||||||
|
.elem-hydro .talent-icon {
|
||||||
|
background-image: url("../player_card/img/talent-hydro.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
.elem-hydro .elem-bg,
|
||||||
|
.hydro-bg {
|
||||||
|
background-image: url("../player_card/img/bg-hydro.jpg");
|
||||||
|
}
|
||||||
|
|
||||||
|
.elem-anemo .talent-icon {
|
||||||
|
background-image: url("../player_card/img/talent-anemo.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
.elem-anemo .elem-bg,
|
||||||
|
.anemo-bg {
|
||||||
|
background-image: url("../player_card/img/bg-anemo.jpg");
|
||||||
|
}
|
||||||
|
|
||||||
|
.elem-cryo .talent-icon {
|
||||||
|
background-image: url("../player_card/img/talent-cryo.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
.elem-cryo .elem-bg,
|
||||||
|
.cryo-bg {
|
||||||
|
background-image: url("../player_card/img/bg-cryo.jpg");
|
||||||
|
}
|
||||||
|
|
||||||
|
.elem-electro .talent-icon {
|
||||||
|
background-image: url("../player_card/img/talent-electro.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
.elem-electro .elem-bg,
|
||||||
|
.electro-bg {
|
||||||
|
background-image: url("../player_card/img/bg-electro.jpg");
|
||||||
|
}
|
||||||
|
|
||||||
|
.elem-geo .talent-icon {
|
||||||
|
background-image: url("../player_card/img/talent-geo.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
.elem-geo .elem-bg,
|
||||||
|
.geo-bg {
|
||||||
|
background-image: url("../player_card/img/bg-geo.jpg");
|
||||||
|
}
|
||||||
|
|
||||||
|
.elem-pyro .talent-icon {
|
||||||
|
background-image: url("../player_card/img/talent-pyro.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
.elem-pyro .elem-bg,
|
||||||
|
.pyro-bg {
|
||||||
|
background-image: url("../player_card/img/bg-pyro.jpg");
|
||||||
|
}
|
||||||
|
|
||||||
|
.elem-dendro .talent-icon {
|
||||||
|
background-image: url("../player_card/img/talent-dendro.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
.elem-dendro .elem-bg,
|
||||||
|
.dendro-bg {
|
||||||
|
background-image: url("../player_card/img/bg-dendro.jpg");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cont */
|
||||||
|
.cont {
|
||||||
|
border-radius: 10px;
|
||||||
|
background: url("img/card-bg.png") top left repeat-x;
|
||||||
|
background-size: auto 100%;
|
||||||
|
margin: 5px 15px 5px 10px;
|
||||||
|
position: relative;
|
||||||
|
box-shadow: 0 0 1px 0 #ccc, 2px 2px 4px 0 rgba(50, 50, 50, 0.8);
|
||||||
|
overflow: hidden;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cont-title {
|
||||||
|
background: rgba(0, 0, 0, 0.4);
|
||||||
|
box-shadow: 0 0 1px 0 #fff;
|
||||||
|
color: #d3bc8e;
|
||||||
|
padding: 10px 20px;
|
||||||
|
text-align: left;
|
||||||
|
border-radius: 10px 10px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cont-title span {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #aaa;
|
||||||
|
margin-left: 10px;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cont-title.border-less {
|
||||||
|
background: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
|
||||||
|
box-shadow: none;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cont-body {
|
||||||
|
padding: 10px 15px;
|
||||||
|
font-size: 12px;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
box-shadow: 0 0 1px 0 #fff;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cont-footer {
|
||||||
|
padding: 10px 15px;
|
||||||
|
font-size: 12px;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cont > ul.cont-msg {
|
||||||
|
display: block;
|
||||||
|
padding: 5px 10px;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.cont-msg,
|
||||||
|
.cont-footer ul {
|
||||||
|
padding-left: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.cont-msg li,
|
||||||
|
.cont-footer ul li {
|
||||||
|
margin: 5px 0;
|
||||||
|
margin-left: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.cont-msg li strong,
|
||||||
|
.cont-footer ul li strong {
|
||||||
|
font-weight: normal;
|
||||||
|
margin: 0 2px;
|
||||||
|
color: #d3bc8e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cont-table {
|
||||||
|
display: table;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cont-table .tr {
|
||||||
|
display: table-row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cont-table .tr:nth-child(even) {
|
||||||
|
background: rgba(0, 0, 0, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cont-table .tr:nth-child(odd) {
|
||||||
|
background: rgba(50, 50, 50, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cont-table .tr > div,
|
||||||
|
.cont-table .tr > td {
|
||||||
|
display: table-cell;
|
||||||
|
box-shadow: 0 0 1px 0 #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cont-table .tr > div.value-full {
|
||||||
|
display: table;
|
||||||
|
width: 200%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cont-table .tr > div.value-none {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cont-table .thead {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cont-table .thead > div,
|
||||||
|
.cont-table .thead > td {
|
||||||
|
color: #d3bc8e;
|
||||||
|
background: rgba(0, 0, 0, 0.4);
|
||||||
|
line-height: 40px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cont-table .title,
|
||||||
|
.cont-table .th {
|
||||||
|
color: #d3bc8e;
|
||||||
|
padding-right: 15px;
|
||||||
|
text-align: right;
|
||||||
|
background: rgba(0, 0, 0, 0.4);
|
||||||
|
min-width: 100px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
font-size: 18px;
|
||||||
|
text-align: center;
|
||||||
|
color: #fff;
|
||||||
|
margin: 20px 0 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* item-icon */
|
||||||
|
.item-icon {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 4px;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-icon .img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: block;
|
||||||
|
background-size: contain;
|
||||||
|
background-position: center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-icon.artis .img {
|
||||||
|
width: 84%;
|
||||||
|
height: 84%;
|
||||||
|
margin: 8%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-icon.star4 {
|
||||||
|
background-image: url("../abyss/background/roleStarBg4.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-icon.opacity-bg.star4 {
|
||||||
|
background-image: url("../abyss/background/roleStarBg4.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-icon.star5 {
|
||||||
|
background-image: url("../abyss/background/roleStarBg5.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-icon.opacity-bg.star5 {
|
||||||
|
background-image: url("../abyss/background/roleStarBg5.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-list {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-list .item-card {
|
||||||
|
width: 70px;
|
||||||
|
background: #e7e5d9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-list .item-icon {
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
border-bottom-right-radius: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-list .item-title {
|
||||||
|
color: #222;
|
||||||
|
font-size: 13px;
|
||||||
|
text-align: center;
|
||||||
|
padding: 2px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-list .item-icon {
|
||||||
|
height: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-list .item-badge {
|
||||||
|
position: absolute;
|
||||||
|
display: block;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
background: rgba(0, 0, 0, 0.6);
|
||||||
|
font-size: 12px;
|
||||||
|
color: #fff;
|
||||||
|
padding: 4px 5px 3px;
|
||||||
|
border-radius: 0 0 6px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*# sourceMappingURL=common.css.map */
|
391
resources/genshin/calendar/common.less
Normal file
391
resources/genshin/calendar/common.less
Normal file
@ -0,0 +1,391 @@
|
|||||||
|
.font(@name, @file) {
|
||||||
|
@font-face {
|
||||||
|
font-family: @name;
|
||||||
|
src: url("../../fonts/@{file}.ttf") format('truetype');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.font('Number', 'tttgbnumber');
|
||||||
|
.font('YS', 'HYWenHei-65W');
|
||||||
|
|
||||||
|
.font-ys {
|
||||||
|
font-family: Number, "汉仪文黑-65W", YS, PingFangSC-Medium, "PingFang SC", sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-size: 18px;
|
||||||
|
color: #1e1f20;
|
||||||
|
font-family: Number, "汉仪文黑-65W", YS, PingFangSC-Medium, "PingFang SC", sans-serif;
|
||||||
|
transform: scale(1.4);
|
||||||
|
transform-origin: 0 0;
|
||||||
|
width: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
width: 600px;
|
||||||
|
padding: 20px 15px 10px 15px;
|
||||||
|
background-size: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.head-box {
|
||||||
|
border-radius: 15px;
|
||||||
|
padding: 10px 20px;
|
||||||
|
position: relative;
|
||||||
|
color: #fff;
|
||||||
|
margin-top: 30px;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
.font-ys;
|
||||||
|
font-size: 36px;
|
||||||
|
text-shadow: 0 0 1px #000, 1px 1px 3px rgba(0, 0, 0, .9);
|
||||||
|
|
||||||
|
.label {
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.genshin_logo {
|
||||||
|
position: absolute;
|
||||||
|
top: 1px;
|
||||||
|
right: 15px;
|
||||||
|
width: 97px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
font-size: 16px;
|
||||||
|
text-shadow: 0 0 1px #000, 1px 1px 3px rgba(0, 0, 0, .9);
|
||||||
|
|
||||||
|
span {
|
||||||
|
color: #d3bc8e;
|
||||||
|
padding: 0 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.notice {
|
||||||
|
color: #888;
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: right;
|
||||||
|
padding: 12px 5px 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice-center {
|
||||||
|
color: #fff;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
text-shadow: 1px 1px 1px #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.copyright {
|
||||||
|
font-size: 14px;
|
||||||
|
text-align: center;
|
||||||
|
color: #fff;
|
||||||
|
position: relative;
|
||||||
|
padding-left: 10px;
|
||||||
|
text-shadow: 1px 1px 1px #000;
|
||||||
|
margin: 10px 0;
|
||||||
|
|
||||||
|
.version {
|
||||||
|
color: #d3bc8e;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0 3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* */
|
||||||
|
|
||||||
|
.cons {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
padding: 0 5px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.cons(@idx, @bg, @color:#fff) {
|
||||||
|
.cons-@{idx} {
|
||||||
|
background: @bg;
|
||||||
|
color: @color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.cons(0, #666);
|
||||||
|
.cons(n0, #404949);
|
||||||
|
.cons(1, #5cbac2);
|
||||||
|
.cons(2, #339d61);
|
||||||
|
.cons(3, #3e95b9);
|
||||||
|
.cons(4, #3955b7);
|
||||||
|
.cons(5, #531ba9cf);
|
||||||
|
.cons(6, #ff5722);
|
||||||
|
|
||||||
|
.cons2(@idx, @bg, @color:#fff) {
|
||||||
|
.cons2-@{idx} {
|
||||||
|
border-radius: 4px;
|
||||||
|
background: @bg;
|
||||||
|
color: @color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.cons2(0, #666);
|
||||||
|
.cons2(1, #71b1b7);
|
||||||
|
.cons2(2, #369961);
|
||||||
|
.cons2(3, #4596b9);
|
||||||
|
.cons2(4, #4560b9);
|
||||||
|
.cons2(5, #531ba9cf);
|
||||||
|
.cons2(6, #ff5722);
|
||||||
|
|
||||||
|
/******** Fetter ********/
|
||||||
|
|
||||||
|
.fetter {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
display: inline-block;
|
||||||
|
background: url('img/fetter.png');
|
||||||
|
background-size: auto 100%;
|
||||||
|
@fetters: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10;
|
||||||
|
each(@fetters, {
|
||||||
|
&.fetter@{value} {
|
||||||
|
background-position: (-100%/9)+(100%/9)*@value 0;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/******** ELEM ********/
|
||||||
|
|
||||||
|
@elems: hydro, anemo, cryo, electro, geo, pyro, dendro;
|
||||||
|
|
||||||
|
each(@elems, {
|
||||||
|
.elem-@{value} .talent-icon {
|
||||||
|
background-image: url("../player_card/img/talent-@{value}.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
.elem-@{value} .elem-bg,
|
||||||
|
.@{value}-bg {
|
||||||
|
background-image: url("../player_card/img/bg-@{value}.jpg");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
/* cont */
|
||||||
|
|
||||||
|
.cont {
|
||||||
|
border-radius: 10px;
|
||||||
|
background: url("img/card-bg.png") top left repeat-x;
|
||||||
|
background-size: auto 100%;
|
||||||
|
// backdrop-filter: blur(3px);
|
||||||
|
margin: 5px 15px 5px 10px;
|
||||||
|
position: relative;
|
||||||
|
box-shadow: 0 0 1px 0 #ccc, 2px 2px 4px 0 rgba(50, 50, 50, .8);
|
||||||
|
overflow: hidden;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.cont-title {
|
||||||
|
background: rgba(0, 0, 0, .4);
|
||||||
|
box-shadow: 0 0 1px 0 #fff;
|
||||||
|
color: #d3bc8e;
|
||||||
|
padding: 10px 20px;
|
||||||
|
text-align: left;
|
||||||
|
border-radius: 10px 10px 0 0;
|
||||||
|
|
||||||
|
span {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #aaa;
|
||||||
|
margin-left: 10px;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.border-less {
|
||||||
|
background: linear-gradient(rgba(0, 0, 0, .5), rgba(0, 0, 0, 0));
|
||||||
|
box-shadow: none;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.cont-body {
|
||||||
|
padding: 10px 15px;
|
||||||
|
font-size: 12px;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
box-shadow: 0 0 1px 0 #fff;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.cont-footer {
|
||||||
|
padding: 10px 15px;
|
||||||
|
font-size: 12px;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cont > ul.cont-msg {
|
||||||
|
display: block;
|
||||||
|
padding: 5px 10px;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.cont-msg, .cont-footer ul {
|
||||||
|
padding-left: 15px;
|
||||||
|
|
||||||
|
li {
|
||||||
|
margin: 5px 0;
|
||||||
|
margin-left: 15px;
|
||||||
|
|
||||||
|
strong {
|
||||||
|
font-weight: normal;
|
||||||
|
margin: 0 2px;
|
||||||
|
color: #d3bc8e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.cont-table {
|
||||||
|
display: table;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cont-table .tr {
|
||||||
|
display: table-row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cont-table .tr:nth-child(even) {
|
||||||
|
background: rgba(0, 0, 0, .4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cont-table .tr:nth-child(odd) {
|
||||||
|
background: rgba(50, 50, 50, .4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cont-table .tr > div,
|
||||||
|
.cont-table .tr > td {
|
||||||
|
display: table-cell;
|
||||||
|
box-shadow: 0 0 1px 0 #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cont-table .tr > div.value-full {
|
||||||
|
display: table;
|
||||||
|
width: 200%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cont-table .tr > div.value-none {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cont-table .thead {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cont-table .thead > div,
|
||||||
|
.cont-table .thead > td {
|
||||||
|
color: #d3bc8e;
|
||||||
|
background: rgba(0, 0, 0, .4);
|
||||||
|
line-height: 40px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.cont-table .title,
|
||||||
|
.cont-table .th {
|
||||||
|
color: #d3bc8e;
|
||||||
|
padding-right: 15px;
|
||||||
|
text-align: right;
|
||||||
|
background: rgba(0, 0, 0, .4);
|
||||||
|
min-width: 100px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
font-size: 18px;
|
||||||
|
text-align: center;
|
||||||
|
color: #fff;
|
||||||
|
margin: 20px 0 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* item-icon */
|
||||||
|
.item-icon {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 4px;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: block;
|
||||||
|
background-size: contain;
|
||||||
|
background-position: center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.artis {
|
||||||
|
.img {
|
||||||
|
width: 84%;
|
||||||
|
height: 84%;
|
||||||
|
margin: 8%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@stars: 4, 5;
|
||||||
|
each(@stars, {
|
||||||
|
&.star@{value} {
|
||||||
|
background-image: url("../abyss/background/roleStarBg@{value}.png");
|
||||||
|
}
|
||||||
|
&.opacity-bg.star@{value} {
|
||||||
|
background-image: url("../abyss/background/roleStarBg@{value}.png");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-list {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.item-card {
|
||||||
|
width: 70px;
|
||||||
|
background: #e7e5d9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-icon {
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
border-bottom-right-radius: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-title {
|
||||||
|
color: #222;
|
||||||
|
font-size: 13px;
|
||||||
|
text-align: center;
|
||||||
|
padding: 2px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-icon {
|
||||||
|
height: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-badge {
|
||||||
|
position: absolute;
|
||||||
|
display: block;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
background: rgba(0, 0, 0, 0.6);
|
||||||
|
font-size: 12px;
|
||||||
|
color: #fff;
|
||||||
|
padding: 4px 5px 3px;
|
||||||
|
border-radius: 0 0 6px 0;
|
||||||
|
}
|
||||||
|
}
|
199
resources/genshin/calendar/example.html
Normal file
199
resources/genshin/calendar/example.html
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-cn">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width">
|
||||||
|
<link rel="shortcut icon" href="#"/>
|
||||||
|
<link rel="stylesheet" type="text/css" href="common.css"/>
|
||||||
|
<title>miao-plugin</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="calendar.css"/>
|
||||||
|
</head>
|
||||||
|
<body class="elem-hydro calendar-mode" style=transform:scale(1)>
|
||||||
|
<div class="container elem-bg" id="container">
|
||||||
|
<div class="calendar">
|
||||||
|
<div class="cal-bg for-calendar-mode">
|
||||||
|
<table class="cont-table" border-collapse="collapse">
|
||||||
|
<tr class="tr thead">
|
||||||
|
<td colspan="13" class="td month">2月</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="tr thead">
|
||||||
|
<td class="td date">
|
||||||
|
<span class="date-num">9日</span>
|
||||||
|
<span class="date-week">周四</span>
|
||||||
|
</td>
|
||||||
|
<td class="td date">
|
||||||
|
<span class="date-num">10日</span>
|
||||||
|
<span class="date-week">周五</span>
|
||||||
|
</td>
|
||||||
|
<td class="td date">
|
||||||
|
<span class="date-num">11日</span>
|
||||||
|
<span class="date-week">周五</span>
|
||||||
|
</td>
|
||||||
|
<td class="td date">
|
||||||
|
<span class="date-num">12日</span>
|
||||||
|
<span class="date-week">周五</span>
|
||||||
|
</td>
|
||||||
|
<td class="td date">
|
||||||
|
<span class="date-num">13日</span>
|
||||||
|
<span class="date-week">周五</span>
|
||||||
|
</td>
|
||||||
|
<td class="td date">
|
||||||
|
<span class="date-num">14日</span>
|
||||||
|
<span class="date-week">周五</span>
|
||||||
|
</td>
|
||||||
|
<td class="td date current-date">
|
||||||
|
<span class="date-num">15日</span>
|
||||||
|
<span class="date-week">周五</span>
|
||||||
|
</td>
|
||||||
|
<td class="td date">
|
||||||
|
<span class="date-num">16日</span>
|
||||||
|
<span class="date-week">周五</span>
|
||||||
|
</td>
|
||||||
|
<td class="td date">
|
||||||
|
<span class="date-num">17日</span>
|
||||||
|
<span class="date-week">周五</span>
|
||||||
|
</td>
|
||||||
|
<td class="td date">
|
||||||
|
<span class="date-num">18日</span>
|
||||||
|
<span class="date-week">周五</span>
|
||||||
|
</td>
|
||||||
|
<td class="td date">
|
||||||
|
<span class="date-num">19日</span>
|
||||||
|
<span class="date-week">周五</span>
|
||||||
|
</td>
|
||||||
|
<td class="td date">
|
||||||
|
<span class="date-num">20日</span>
|
||||||
|
<span class="date-week">周五</span>
|
||||||
|
</td>
|
||||||
|
<td class="td date">
|
||||||
|
<span class="date-num">21日</span>
|
||||||
|
<span class="date-week">周五</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="tr">
|
||||||
|
<td class="line">
|
||||||
|
</td>
|
||||||
|
<td class="line">
|
||||||
|
</td>
|
||||||
|
<td class="line">
|
||||||
|
</td>
|
||||||
|
<td class="line">
|
||||||
|
</td>
|
||||||
|
<td class="line">
|
||||||
|
</td>
|
||||||
|
<td class="line">
|
||||||
|
</td>
|
||||||
|
<td class="line current-date">
|
||||||
|
</td>
|
||||||
|
<td class="line">
|
||||||
|
</td>
|
||||||
|
<td class="line">
|
||||||
|
</td>
|
||||||
|
<td class="line">
|
||||||
|
</td>
|
||||||
|
<td class="line">
|
||||||
|
</td>
|
||||||
|
<td class="line">
|
||||||
|
</td>
|
||||||
|
<td class="line">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="cal-bg for-list-mode">
|
||||||
|
<table class="cont-table" border-collapse="collapse">
|
||||||
|
<tr class="tr thead">
|
||||||
|
<td class="td month">活动列表</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="tr">
|
||||||
|
<td class="line"></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="cal-list char-2-2 char-num-0">
|
||||||
|
<div class="cal-abyss-cont">
|
||||||
|
<div class="cal-item type-abyss" style="left:0.0%;width:55.12811609691518%">
|
||||||
|
<div class="info">
|
||||||
|
<img src="img/abyss-icon.png" class="cal-icon"/>
|
||||||
|
<strong>「深境螺旋」· 2月上半</strong>
|
||||||
|
<span>02-01 04:00 ~ 02-16 03:59 (5小时2分钟后结束)</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cal-item type-abyss" style="left:55.1282051282542%;width:44.8717948717458%">
|
||||||
|
<div class="info">
|
||||||
|
<img src="img/abyss-icon.png" class="cal-icon"/>
|
||||||
|
<strong>「深境螺旋」· 2月下半</strong>
|
||||||
|
<span>02-16 04:00 (5小时2分钟后开始)</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="cal-item type-weapon li-col"
|
||||||
|
style="margin-left:0.0%;width:100.0%"
|
||||||
|
data-id="3429"
|
||||||
|
data-type="weapon">
|
||||||
|
<div class="banner" style="background-image:url('https://webstatic.mihoyo.com/upload/ann/2022/12/28/d9e5b0f28d65bc817d44cd1170f6b9a2_5522946055662469236.jpg')"></div>
|
||||||
|
<div class="info">
|
||||||
|
<img src='https://uploadstatic.mihoyo.com/announcement/2020/03/05/2cf7327b5fb2c050872ead29e338e368_7400353291716098710.png' class="cal-icon"/>
|
||||||
|
<strong>「神铸赋形」祈愿:「护摩之杖」「若水」概率UP!</strong>
|
||||||
|
<span>02-07 18:00 ~ 02-28 14:59 (12天15小时56分钟后结束)</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="cal-item type-activity li-col"
|
||||||
|
style="margin-left:0.0%;width:100.0%"
|
||||||
|
data-id="3420"
|
||||||
|
data-type="activity">
|
||||||
|
<div class="banner" style="background-image:url('https://webstatic.mihoyo.com/upload/ann/2022/12/28/dfdb4fe78124efbd888bb11d90481e3b_1185432047750172096.jpg')"></div>
|
||||||
|
<div class="info">
|
||||||
|
<img src='https://uploadstatic.mihoyo.com/announcement/2020/03/05/f3016cc0dbe3f9c2305566742ae5927f_1830032474842461374.png' class="cal-icon"/>
|
||||||
|
<strong>「花时来信」神里绫华衣装限时折扣</strong>
|
||||||
|
<span>01-18 11:00 ~ 02-27 03:59 (11天4小时56分钟后结束)</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="cal-item type-pass li-col"
|
||||||
|
style="margin-left:0.0%;width:100.0%"
|
||||||
|
data-id="3421"
|
||||||
|
data-type="pass">
|
||||||
|
<div class="banner" style="background-image:url('https://webstatic.mihoyo.com/upload/ann/2022/12/28/760d459815947d53014f57497228d35b_8021829647860262889.jpg')"></div>
|
||||||
|
<div class="info">
|
||||||
|
<img src='https://uploadstatic.mihoyo.com/announcement/2020/03/05/f3016cc0dbe3f9c2305566742ae5927f_1830032474842461374.png' class="cal-icon"/>
|
||||||
|
<strong>「合韵纪行」活动说明</strong>
|
||||||
|
<span>01-18 11:00 ~ 02-27 03:59 (11天4小时56分钟后结束)</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="cal-item type-character li-idx-1 li-col1"
|
||||||
|
style="margin-left:0.0%;width:100.0%"
|
||||||
|
data-id="3427"
|
||||||
|
data-type="character">
|
||||||
|
<div class="banner" style="background-image:url('https://webstatic.mihoyo.com/upload/ann/2022/12/28/fdae43817589c40f9116aee1bc08f429_773289207622522746.jpg')"></div>
|
||||||
|
<div class="info">
|
||||||
|
<img src="" class="character-img"/>
|
||||||
|
<strong>胡桃</strong>
|
||||||
|
<span>02-07 18:00 ~ 02-28 14:59 (12天15小时56分钟后结束)</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="cal-item type-normal li-col"
|
||||||
|
style="margin-left:0.0%;width:100.0%"
|
||||||
|
data-id="3469"
|
||||||
|
data-type="normal">
|
||||||
|
<div class="info">
|
||||||
|
<img src='https://uploadstatic.mihoyo.com/announcement/2020/03/05/f3016cc0dbe3f9c2305566742ae5927f_1830032474842461374.png' class="cal-icon"/>
|
||||||
|
<strong>【有奖活动】「磬弦奏华夜」3.4版本攻略征集活动</strong>
|
||||||
|
<span>01-18 18:00 ~ 02-26 23:59 (11天55分钟后结束)</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="now-line" style="left:53.5461451299444%"></div>
|
||||||
|
<div class="now-line line2" style="left:53.5461451299444%"></div>
|
||||||
|
</div>
|
||||||
|
<div class="now-time">
|
||||||
|
<span>当前时间:2023-02-15 23:03</span>
|
||||||
|
</div>
|
||||||
|
<div class="copyright">Inspired By Miao-Plugin</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
BIN
resources/genshin/calendar/img/abyss-icon.png
Normal file
BIN
resources/genshin/calendar/img/abyss-icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 49 KiB |
BIN
resources/genshin/calendar/img/abyss.jpg
Normal file
BIN
resources/genshin/calendar/img/abyss.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 29 KiB |
BIN
resources/genshin/calendar/img/card-bg.png
Normal file
BIN
resources/genshin/calendar/img/card-bg.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.5 KiB |
BIN
resources/genshin/calendar/img/fetter.png
Normal file
BIN
resources/genshin/calendar/img/fetter.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 61 KiB |
Loading…
Reference in New Issue
Block a user