BackIcon哪吒面板美化

2024年10月21日

前言

哪吒探针是一款广受欢迎的服务器监控工具,本篇博客将分享如何为其自定义主题样式,包括界面优化、动态进度条以及缓存数据的处理。


样式调整与背景图片

以下是 CSS 样式,用于适配不同屏幕设备和自定义页面的背景。

/* 屏幕适配 */
@media only screen and (min-width: 1200px) {
   .ui.container {
   width: 80% !important;
}
}
@media only screen and (max-width: 767px) {
   .ui.card>.content>.header:not(.ui), .ui.cards>.card>.content>.header:not(.ui) {
      margin-top: 0.4em !important;
   }
}

/* 整体图标 */
i.icon {
   color: #000;
   width: 1.2em !important;
}

/* 背景图片 */
body {
   content: " " !important;
   background: fixed !important;
   z-index: -1 !important;
   top: 0 !important;
   right: 0 !important;
   bottom: 0 !important;
   left: 0 !important;
   background-position: top !important;
   background-repeat: no-repeat !important;
   background-size: cover !important;
   background-image: url(https://gitee.com/wxte/img/raw/master/image.webp) !important;
   font-family: Arial,Helvetica,sans-serif !important;
}

/* 导航栏 */
.ui.large.menu {
   border: 0 !important;
   border-radius: 0px !important;
   background-color: rgba(255, 255, 255, 55%) !important;
}

/* 首页按钮 */
.ui.menu .active.item {
   background-color: transparent !important;
}

/* 导航栏下拉框 */
.ui.dropdown .menu {
   border: 0 !important;
   border-radius: 0 !important;
   background-color: rgba(255, 255, 255, 80%) !important;
}

/* 登陆按钮 */
.nezha-primary-btn {
   background-color: transparent !important;
   color: #000 !important;
}

/* 大卡片 */
#app .ui.fluid.accordion {
   background-color: #fbfbfb26 !important;
   border-radius: 0.4rem !important;
}

/* 小卡片 */
.ui.four.cards>.card {
   border-radius: 0.6rem !important;
   background-color: #fafafaa3 !important;
}

.status.cards .wide.column {
   padding-top: 0 !important;
   padding-bottom: 0 !important;
   height: 3.3rem !important;
}

.status.cards .three.wide.column {
   padding-right: 0rem !important;
}

.status.cards .wide.column:nth-child(1) {
   margin-top: 2rem !important;
}

.status.cards .wide.column:nth-child(2) {
   margin-top: 2rem !important;
}

.status.cards .description {
   padding-bottom: 0 !important;
}

/* 小鸡名 */
.status.cards .flag {
   margin-right: 0.5rem !important;
}

/* 弹出卡片图标 */
.status.cards .header > .info.icon {
   margin-right: 0 !important;
}

.nezha-secondary-font {
   color: #5E72E4 !important;
}

/* 进度条 */
.ui.progress {
   border-radius: 50rem !important;
}

.ui.progress .bar {
   min-width: 1.8em !important;
   border-radius: 15px !important;
   line-height: 1.65em !important;
}

.ui.fine.progress> .bar {
   background-color: #21ba45 !important;
}

.ui.progress> .bar {
   background-color: #000 !important;
}

.ui.progress.fine .bar {
   background-color: #21ba45 !important;
}

.ui.progress.warning .bar {
   background-color: #ff9800 !important;
}

.ui.progress.error .bar {
   background-color: #e41e10 !important;
}

.ui.progress.offline .bar {
   background-color: #000 !important;
}

/* 上传下载 */
.status.cards .outline.icon {
   margin-right: 1px !important;
}

i.arrow.alternate.circle.down.outline.icon {
   color: #21ba45 !important;
}

i.arrow.alternate.circle.up.outline.icon {
   color: red !important;
}

/* 弹出卡片小箭头 */
.ui.right.center.popup {
   margin: -3px 0 0 0.914286em !important;
   -webkit-transform-origin: left 50% !important;
   transform-origin: left 50% !important;
}

.ui.bottom.left.popup {
   margin-left: 1px !important;
   margin-top: 3px !important;
}

.ui.top.left.popup {
   margin-left: 0 !important;
   margin-bottom: 10px !important;
}

.ui.top.right.popup {
   margin-right: 0 !important;
   margin-bottom: 8px !important;
}

.ui.left.center.popup {
   margin: -3px .91428571em 0 0 !important;
   -webkit-transform-origin: right 50% !important;
   transform-origin: right 50% !important;
}

.ui.right.center.popup:before,
.ui.left.center.popup:before {
   border: 0px solid #fafafaeb !important;
   background: #fafafaeb !important;
}

.ui.top.popup:before {
   border-color: #fafafaeb transparent transparent !important;
}

.ui.popup:before {
   border-color: #fafafaeb transparent transparent !important;
}

.ui.bottom.left.popup:before {
   border-radius: 0 !important;
   border: 1px solid transparent !important;
   border-color: #fafafaeb transparent transparent !important;
   background: #fafafaeb !important;
   -webkit-box-shadow: 0px 0px 0 0 #fafafaeb !important;
   box-shadow: 0px 0px 0 0 #fafafaeb !important;
   -webkit-tap-highlight-color: rgba(0,0,0,0) !important;
}

.ui.bottom.right.popup:before {
   border-radius: 0 !important;
   border: 1px solid transparent !important;
   border-color: #fafafaeb transparent transparent !important;
   background: #fafafaeb !important
   -webkit-box-shadow: 0px 0px 0 0 #fafafaeb !important;
   box-shadow: 0px 0px 0 0 #fafafaeb !important;
   -webkit-tap-highlight-color: rgba(0,0,0,0) !important;
}

.ui.top.left.popup:before {
   border-radius: 0 !important;
   border: 1px solid transparent !important;
   border-color: #fafafaeb transparent transparent !important;
   background: #fafafaeb !important;
   -webkit-box-shadow: 0px 0px 0 0 #fafafaeb !important;
   box-shadow: 0px 0px 0 0 #fafafaeb !important;
   -webkit-tap-highlight-color: rgba(0,0,0,0) !important;
}

.ui.top.right.popup:before {
   border-radius: 0 !important;
   border: 1px solid transparent !important;
   border-color: #fafafaeb transparent transparent !important;
   background: #fafafaeb !important;
   -webkit-box-shadow: 0px 0px 0 0 #fafafaeb !important;
   box-shadow: 0px 0px 0 0 #fafafaeb !important;
   -webkit-tap-highlight-color: rgba(0,0,0,0) !important;
}

.ui.left.center.popup:before {
   border-radius: 0 !important;
   border: 1px solid transparent !important;
   border-color: #fafafaeb transparent transparent !important;
   background: #fafafaeb !important;
   -webkit-box-shadow: 0px 0px 0 0 #fafafaeb !important;
   box-shadow: 0px 0px 0 0 #fafafaeb !important;
   -webkit-tap-highlight-color: rgba(0,0,0,0) !important;
}

/* 弹出卡片 */
.status.cards .ui.content.popup {
   min-width: 20rem !important;
   line-height: 2rem !important;
   border-radius: 5px !important;
   border: 1px solid transparent !important;
   background-color: #fafafaeb !important;
   font-family: Arial,Helvetica,sans-serif !important;
}

.ui.content {
   margin: 0 !important;
   padding: 1em !important;
}

/* 服务页 */
.ui.table {
   background: RGB(225,225,225,0.6) !important;
}

.ui.table thead th {
   background: transparent !important;
}

/* 服务页进度条 */
.service-status .good {
   background-color: #21ba45 !important;
}

.service-status .danger {
   background-color: red !important;
}

.service-status .warning {
   background-color: orange !important;
}

/* 版权 */
.ui.inverted.segment, .ui.primary.inverted.segment {
   color: #000 !important;
   font-weight: bold !important;
   background-color: #fafafaa3 !important;
}
</style>

<!--Logo和版权-->
<script>
window.onload = function(){
var avatar=document.querySelector(".item img")
var footer=document.querySelector("div.is-size-7")
footer.innerHTML=""
footer.style.visibility="visible"
avatar.src="https://www.loliapi.com/acg/pp/"
avatar.style.visibility="visible"
}
</script>

<!-- 进度条颜色动态变化 -->
<script>
window.onload = function(){
    var avatar=document.querySelector(".item img")
    var footer=document.querySelector("div.is-size-7")
    footer.innerHTML=""
    footer.style.visibility="visible"
    avatar.src="https://www.loliapi.com/acg/pp/"
    avatar.style.visibility="visible"

    // 默认分组模式
    if(!localStorage.getItem("showGroup")){
        localStorage.setItem("showGroup", true);
    }
    // 默认暗黑模式
    if(!localStorage.getItem("theme")){
        localStorage.setItem("theme", 'dark');
    }
    // 默认半透明效果
    if(!localStorage.getItem("semiTransparent")){
        localStorage.setItem("semiTransparent", 'true');
    }
    
    const extraData = {
        1: {
            pid: 0,
            shop: 'crunchbits',
            price: '$4',
            cycle: 'month',
            start: '2024-09-27',
            expire: '2024-10-27',
            autoPay: ''
        },
        2: {
            pid: 0,
            shop: 'crunchbits',
            price: '$4',
            cycle: 'month',
            start: '2024-09-28',
            expire: '2024-10-28',
            autoPay: ''
        },
        3: {
            pid: 0,
            shop: 'crunchbits',
            price: '¥99',
            cycle: 'Year',
            start: '2024-07-08',
            expire: '2025-07-08',
            autoPay: ''
        },
        4: {
            pid: 0,
            shop: 'crunchbits',
            price: '$99',
            cycle: 'Year',
            start: '2024-01-09',
            expire: '2025-01-09',
            autoPay: ''
        },
        9: {
            pid: 0,
            shop: 'crunchbits',
            price: '$22.69',
            cycle: '',
            start: '2024-10-12',
            expire: '2025-01-13',
            autoPay: ''
        },
        12: {
            pid: 0,
            shop: 'racknerd',
            price: '$10.98',
            cycle: 'Year',
            start: '2024-09-29',
            expire: '',
            autoPay: ''
        },
        13: {
            pid: 0,
            shop: 'rainyun',
            price: '$14',
            cycle: 'Year',
            start: '2024-09-28',
            expire: '2025-09-28',
            autoPay: ''
        },
        14: {
            pid: 0,
            shop: 'rainyun',
            price: '$10.00',
            cycle: 'Year',
            start: '2024-10-10',
            expire: '2026-10-10',
            autoPay: ''
        },
        15: {
            pid: 0,
            shop: 'colocrossing',
            price: '$10.00',
            cycle: 'Year',
            start: '2024-10-11',
            expire: '2026-10-11',
            autoPay: ''
        },
    }
    const cycleNames = {
        '年付': 'year',
        '半年付': 'half',
        '季付': 'quarterly',
        '月付': 'month',
        '': 'year',
        '': 'half',
        '': 'quarterly',
        '': 'month',
        'Year': 'year',
        'Half': 'half',
        'Quarterly': 'quarterly',
        'Month': 'month',
        'Y': 'year',
        'H': 'half',
        'Q': 'quarterly',
        'M': 'month',
        'year': 'year',
        'half': 'half',
        'quarterly': 'quarterly',
        'month': 'month',
    }
    const cycleValues = {
        year: 365,
        half: 180,
        quarterly: 90,
        month: 30,
    }
    
    const cats = document.querySelectorAll('.ui.accordion');
    cats.forEach((e, i)=>{
        let $catsTitle = e.querySelector('.title');
        let ct = $catsTitle.innerText;
        ct = ct.trim();	
        
        let $itemCard = e.querySelectorAll('.ui.card');
        let uiCardCount = $itemCard.length;
        $catsTitle.innerHTML = $catsTitle.innerHTML.replace(ct, ct+ ' ('+ uiCardCount +')');
        $itemCard.forEach((ee, ii)=>{
            let $content = ee.querySelector('.content');
            let $descriptionGrid = ee.querySelector('.description .ui.grid');
            let $itemTitle = $content.querySelector('.header');
            let id = ee.getAttribute('id');
            if(extraData[id]){
                let pid = extraData[id].pid;
                pid = parseInt(pid);
                let shop = extraData[id].shop;
                let price = extraData[id].price;
                let start = extraData[id].start;
                let expire = extraData[id].expire;
                let cycle = extraData[id].cycle;
                let autoPay = extraData[id].autoPay;
                let cycleName = cycleNames[cycle];
                let cycleValue = cycleValues[cycleName];
                let nowTime = parseInt(new Date().getTime() / 1000);
                let beginTime = parseInt(new Date(start).getTime() / 1000);
                if(autoPay && autoPay==''){
                    let beginDate = new Date(start);
                    let nowDate = new Date();
                    let mSteps = {
                        year: 12,
                        half: 6,
                        quarterly: 3,
                        month: 1,
                    }
                    expire = beginDate.setMonth(beginDate.getMonth() + mSteps[cycleName]);
                    expire = new Date(expire);
                    while(expire.getTime() < nowDate.getTime()){
                        expire= expire.setMonth(expire.getMonth() + mSteps[cycleName]);
                        expire= new Date(expire);
                    }
                    expire= expire.toLocaleDateString();
                }
                let endTime= parseInt(new Date(expire).getTime() / 1000);
                
                if(expire){
                    // 到期日期行
                    let $expireL= document.createElement('div');
                    $expireL.setAttribute('class', 'three wide column');
                    $expireL.innerHTML= '到期';
                    $descriptionGrid.insertBefore($expireL, $descriptionGrid.childNodes[$descriptionGrid.childNodes.length-3])
                    // 到期日期行右侧进度条
                    let $expireR= document.createElement('div');
let aTime= (nowTime - beginTime);
let bTime= (endTime - beginTime);
let remainingTime= (endTime - nowTime); // 剩余时间

// 使用剩余时间的百分比来计算进度条长度
let cTime= parseInt((remainingTime / bTime) * 100); // 计算剩余时间的百分比

// 固定颜色为 rgb(99, 98, 103)
let progressColor= `rgb(99, 98, 103)`;

// 添加高亮效果
let textStyle= 'text-shadow: 0 0 10px #fff, 0 0 20px #fff, 0 0 30px #ffe6e6; left: .5em; text-align: right; color: #fff;';

// 如果到期是无限的,移除文本样式
if (expire= '') {
    textStyle= '';
}

// 设置进度条的宽度和颜色,使用 !important 确保自定义样式生效
$expireR.setAttribute('class', 'expire-box thirteen wide column');
$expireR.innerHTML= `<div class="ui indicating progress active" style="margin-top: -0.2em;">  <!-- 向上移动进度条 -->
  <div class="bar" style="line-height: 1em !important; transition-duration: 300ms; min-width: unset; width: ${cTime}% !important; padding-left: 0.4em; background-color: ${progressColor} !important; box-shadow: 0px 0px 15px rgba(255, 255, 255, 0.8) !important;">
    <div class="progress" style="${textStyle}">${expire}</div>
  </div>
</div>`;

$descriptionGrid.insertBefore($expireR, $descriptionGrid.childNodes[$descriptionGrid.childNodes.length - 3]);
                }
            }
        });
    });
}
</script>