fix(forum): align forum pages with the reference layout
- cards: restore the shared card shell, add author follow/message actions, score group, last-reply meta and reference plate header actions - home: desktop left tab rail, widget-only sidebar, reference load-more markup - plate: 1-based tabs, reference defaults (全部/推荐/最新回复/热门/精华) - post: fixed action rail, score footer, author card, h1 article title - quick publish: plate selector moved into the submit row like the reference
This commit is contained in:
1 parent
7a59c65252
commit
ec5dfcd82f
15 files changed
+396
-166
No files matched your search
+105
-45
@@ -24,44 +24,44 @@
|
||||
#forum .jio-forum__tabs a{padding:14px 0;color:var(--forum-muted);border-bottom:2px solid transparent}
|
||||
#forum .jio-forum__tabs .is-active{color:var(--forum-accent);border-color:var(--forum-accent);font-weight:600}
|
||||
|
||||
/* ── 论坛首页:栏目 TAB ─────────────────────────────────────────── */
|
||||
/* ── 论坛首页:栏目 TAB(桌面端为左侧竖排导航,移动端横排滑动) ───────── */
|
||||
#forum.forum-home{padding-bottom:40px}
|
||||
.forum-home .forum-home__main{min-width:0}
|
||||
.forum-home .content-layout{min-width:0}
|
||||
.forum-home-tab .fixed-wrap-nav{margin-bottom:10px}
|
||||
.forum-home-tab .tab-nav-theme{border-bottom:none;padding:0;margin:0}
|
||||
.forum-home-tab .tab-nav-theme li{padding:0 2px}
|
||||
.forum-home-tab .tab-nav-theme li > a{display:block;padding:10px 12px;font-size:16px;color:var(--muted-2-color)}
|
||||
.forum-home-tab .tab-nav-theme li.active > a{color:var(--focus-color);font-weight:600}
|
||||
.forum-home-tab .tab-nav-theme li{padding:0}
|
||||
.forum-home-tab .tab-nav-theme li > a{display:block;padding:6px;margin:1px 0;font-size:16px;color:var(--muted-2-color);overflow:hidden}
|
||||
.forum-home-tab .tab-nav-theme li > a:hover{color:var(--main-color)}
|
||||
.forum-home-tab .tab-nav-theme li.active > a{color:var(--focus-color);font-weight:500;background:var(--focus-color-opacity05);border-radius:var(--mini-radius)}
|
||||
.forum-home-tab .tab-nav-theme li::before{display:none}
|
||||
.forum-home-tab .tab-content > .tab-pane{display:none}
|
||||
.forum-home-tab .tab-content > .tab-pane.active{display:block}
|
||||
.forum-main-tab-content{min-height:120px}
|
||||
.forum-more{padding:20px 0;text-align:center}
|
||||
.forum-more.is-loading{display:none}
|
||||
.forum-tab-pane > .ajax-item:last-of-type{margin-bottom:0}
|
||||
/* 首页栏目是横向 TAB,覆盖通用 .fixed-wrap 的竖排侧栏导航形态 */
|
||||
@media (min-width:768px){
|
||||
.forum-home-tab{--fixed-width:auto}
|
||||
.forum-home-tab > .fixed-wrap-nav{position:static;width:auto}
|
||||
.forum-home-tab > .fixed-wrap-nav + .fixed-wrap-content{margin-left:0}
|
||||
.forum-home-tab .fixed-wrap-nav.affix{position:sticky;left:auto;right:auto;width:auto;z-index:11;background:var(--main-bg-color);box-shadow:0 0 10px var(--main-shadow)}
|
||||
.forum-home-tab .tab-nav-theme.mini-scrollbar,
|
||||
.forum-home-tab .tab-nav-theme.swiper-scroll .swiper-wrapper{flex-direction:row;overflow-x:auto;overflow-y:hidden;text-align:left;white-space:nowrap;border-bottom:none;margin:0;padding:0}
|
||||
.forum-home-tab .tab-nav-theme.mini-scrollbar > li,
|
||||
.forum-home-tab .tab-nav-theme.swiper-scroll .swiper-wrapper > li{display:inline-block;padding:0;margin:0}
|
||||
@media (max-width:767px){
|
||||
.forum-home-tab .fixed-wrap-nav:not(.affix):not(.affix-bottom){margin-bottom:10px;padding:0 5px;background:transparent;box-shadow:none}
|
||||
.forum-home-tab .tab-nav-theme{display:flex;flex-direction:row;overflow-x:auto;overflow-y:hidden;text-align:left;white-space:nowrap;border-bottom:none;margin:0;padding:0}
|
||||
.forum-home-tab .tab-nav-theme > li{display:inline-block;padding:0;margin:0;flex:0 0 auto}
|
||||
.forum-home-tab .tab-nav-theme > li > a{padding:8px 10px;margin:0;font-size:15px;background:none!important}
|
||||
}
|
||||
.quick-posts-box{border-radius:var(--main-radius);padding:15px}
|
||||
.quick-posts-box .title-theme{margin-bottom:10px}
|
||||
.quick-input-group{padding:15px;border:1px solid var(--main-border-color);border-radius:var(--main-radius)}
|
||||
.quick-posts-box .edit-posts-title{position:relative}
|
||||
.quick-posts-box .edit-posts-title .line-form-line{display:none}
|
||||
.quick-posts-box .edit-posts-title textarea{width:100%;color:var(--main-color);padding:0;margin-bottom:10px;font-weight:500;font-size:18px;border:0;border-bottom:1px solid var(--main-border-color);background:transparent;resize:none;outline:0}
|
||||
.quick-posts-box .edit-posts-content textarea{outline:0!important;border:none;display:block;width:100%;padding:0;background:transparent;color:var(--main-color);resize:vertical;min-height:88px}
|
||||
.quick-posts-box .edit-posts-title textarea{width:100%;color:var(--main-color);opacity:1;padding:0;margin-bottom:10px;font-weight:500;font-size:18px;border:0;border-bottom:1px solid var(--main-border-color);background:transparent;resize:none;outline:0}
|
||||
.quick-posts-box .edit-posts-content textarea{outline:0!important;border:none;display:block;width:100%;padding:0;margin-bottom:10px;background:var(--main-bg-color);opacity:.9;color:var(--main-color);resize:vertical;min-height:88px}
|
||||
.quick-posts-box .preview .add,.quick-posts-box .preview .preview-item{width:90px;height:90px;border:1px dashed var(--main-border-color);background:none;margin:2px;border-radius:var(--main-radius);position:relative}
|
||||
.quick-posts-box .preview .add:before{content:"+";position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:28px;color:var(--muted-3-color)}
|
||||
.quick-posts-box .drop-select .dropdown-menu{min-width:320px}
|
||||
.quick-more-btns{color:var(--muted-color);position:relative;flex-wrap:wrap;gap:6px}
|
||||
.quick-more-btns .drop-btn{padding:6px 4px;cursor:pointer}
|
||||
.quick-posts-box .dropdown-menu.fluid::before{left:20px}
|
||||
.quick-posts-box .but-plate{font-size:14px;padding:5px 9px 6px 5px}
|
||||
.quick-more-btns{color:var(--muted-color);position:relative;flex-wrap:wrap}
|
||||
.quick-more-btns .drop-btn{padding:6px 4px;cursor:pointer;white-space:nowrap}
|
||||
.quick-more-btns .drop-select{position:relative}
|
||||
.quick-selected-tags > *{display:inline-block}
|
||||
.quick-selected-tags > *:empty{display:none}
|
||||
.quick-selected-tags [name="topics"]{color:var(--focus-color);margin-top:6px;font-size:13px}
|
||||
.quick-posts-submit .but{padding:6px 5px;min-width:85px}
|
||||
.quick-posts-submit .quick-captcha{margin-bottom:8px}
|
||||
.hide-type-drop .select-drop-box .badg.active{--this-bg:var(--focus-color);--this-color:#fff}
|
||||
@@ -75,6 +75,15 @@
|
||||
.quick-posts-form .jio-forum__message:empty{display:none}
|
||||
.forum-pending-plate{background:var(--main-bg-color);box-shadow:0 0 10px var(--main-shadow);border-radius:var(--main-radius);padding:12px 15px;margin-bottom:10px}
|
||||
|
||||
/* ── 论坛首页 / 版块页的加载更多(与主题 AJAX 翻页按钮同构) ───────── */
|
||||
.forum-tab-pane .theme-pagination,.plate-tab .theme-pagination{margin:0}
|
||||
.forum-tab-pane .theme-pagination.ajax-pag,.plate-tab .theme-pagination.ajax-pag{padding:15px 5px 10px}
|
||||
.forum-tab-pane .theme-pagination .ajax-next a,.plate-tab .theme-pagination .ajax-next a{color:var(--muted-color);opacity:.6;border-radius:30px;padding:5px 15px;display:inline-block}
|
||||
.forum-tab-pane .theme-pagination .ajax-next a:hover,.plate-tab .theme-pagination .ajax-next a:hover{background:var(--main-border-color);opacity:1}
|
||||
.forum-tab-pane .theme-pagination .ajax-next .fa,.plate-tab .theme-pagination .ajax-next .fa{margin-right:15px;transition:.3s}
|
||||
.forum-tab-pane .theme-pagination .ajax-next a:hover .fa,.plate-tab .theme-pagination .ajax-next a:hover .fa{margin-right:8px}
|
||||
.forum-tab-pane.is-loading .theme-pagination,.plate-tab .forum-tab-pane.is-loading .theme-pagination{display:none}
|
||||
|
||||
/* ── 版块面板 / 版块卡片 ────────────────────────────────────────── */
|
||||
.panel.panel-plate{border-color:transparent;margin-bottom:10px;background:var(--main-bg-color);border-radius:var(--main-radius);box-shadow:0 0 10px var(--main-shadow);padding:0 15px}
|
||||
.panel.panel-plate:first-of-type .panel-title{padding-top:10px}
|
||||
@@ -94,9 +103,10 @@
|
||||
.scroll-plate .plate-card.mini{padding:15px 5px;width:85px}
|
||||
.scroll-plate .plate-card .plate-thumb{width:50px!important;height:50px!important}
|
||||
.follow-plate .plate-card{width:90px}
|
||||
.plate-item{display:inline-flex;align-items:flex-start}
|
||||
.plate-item{display:inline-flex}
|
||||
.plate-lists{display:flex;align-content:flex-start;flex-flow:row wrap;margin:-3px}
|
||||
.plate-lists .plate-item{margin:3px;background:var(--main-bg-color);box-shadow:0 0 10px var(--main-shadow);border-color:transparent;border-radius:var(--main-radius);padding:15px 20px;width:calc(50% - 6px);position:relative;box-sizing:border-box}
|
||||
.sidebar .plate-lists .plate-item{width:calc(100% - 6px)}
|
||||
.plate-item .plate-thumb{margin-right:15px;flex-shrink:0;display:inline-block;width:60px;height:60px;position:relative}
|
||||
.plate-item .plate-thumb > img,.plate-thumb > img{border-radius:100px;width:100%;height:100%}
|
||||
.plate-item .forum-thumbnail{transition:all .2s;object-fit:cover;width:100%;height:100%}
|
||||
@@ -165,10 +175,10 @@
|
||||
.forum-posts.detail .user-info ~ *{margin-left:70px}
|
||||
.forum-posts.detail .user-info .display-name{font-size:16px}
|
||||
.forum-posts.detail .action-meta .btn-score:hover,.forum-posts.detail .action-meta a.item:hover{background:var(--main-border-color)}
|
||||
.forum-header .buts .but{min-width:87px}
|
||||
.blur-header .count-mates{--main-border-color:rgba(255,255,255,.08)}
|
||||
}
|
||||
@media(max-width:800px){
|
||||
#forum .jio-forum__layout{grid-template-columns:1fr}
|
||||
#forum .jio-forum__aside{border-left:0;padding-left:0}
|
||||
.forum-home .sidebar{width:100%;margin-left:0;margin-top:20px}
|
||||
.forum-home .content-layout{margin-right:0!important;margin-left:0!important}
|
||||
}
|
||||
@@ -301,35 +311,53 @@ body.dark-theme .panel.panel-plate,body.dark-theme .plate-lists .plate-item,body
|
||||
body.dark-theme .forum-header,body.dark-theme .forum-header .header-content{background:var(--main-bg-color)}
|
||||
|
||||
/* ── 版块 / 分类页面 ──────────────────────────────────────────── */
|
||||
.forum-listing .jio-forum__breadcrumbs{margin:0 0 12px}
|
||||
.forum-listing .jio-forum__list-main{min-width:0}
|
||||
.forum-listing .content-layout{min-width:0}
|
||||
.term-main{max-width:790px;margin:0 auto 20px}
|
||||
.plate-tab{padding:0}
|
||||
.plate-tab .affix-header-sm{padding:0 15px;background:var(--main-bg-color);border-radius:var(--main-radius) var(--main-radius) 0 0}
|
||||
.plate-tab .affix-header-sm.affix,.plate-tab .affix-header-sm.affix-bottom{padding:8px 25px}
|
||||
.plate-tab .tab-nav-theme{margin:0;border-bottom:1px solid var(--main-border-color)}
|
||||
.plate-tab .tab-nav-theme li a{font-size:16px;color:var(--muted-2-color);display:block;padding:12px 14px}
|
||||
.plate-tab .tab-nav-theme li.active a{font-weight:bold;color:var(--focus-color)}
|
||||
.plate-tab .tab-nav-theme{margin:0}
|
||||
.plate-tab .tab-nav-theme li a{font-size:16px;color:var(--muted-2-color);display:block;padding:0 5px}
|
||||
.plate-tab .tab-nav-theme li.active a{font-weight:700;color:var(--focus-color)}
|
||||
.plate-tab .tab-content{padding:10px 15px}
|
||||
.plate-tab .tab-content > .tab-pane{display:none}
|
||||
.plate-tab .tab-content > .tab-pane.active{display:block}
|
||||
.plate-tab .forum-tab-pane{min-height:120px}
|
||||
.forum-header.blur-header{overflow:hidden;color:#fff}
|
||||
.forum-header.blur-header .header-content{background:transparent;color:#fff;padding:28px 30px 22px}
|
||||
.forum-header.blur-header .forum-title,.forum-header.blur-header .forum-title a{color:#fff}
|
||||
.forum-header.blur-header{overflow:hidden;color:#ddd}
|
||||
.forum-header.blur-header .header-content{background:none;color:#fff;padding:70px 50px 50px}
|
||||
.forum-header.blur-header .forum-title,.forum-header.blur-header .forum-title a,.forum-header.blur-header a{color:#fff}
|
||||
.forum-header.blur-header .desc,.forum-header.blur-header .px12-sm{color:rgba(255,255,255,.86)}
|
||||
.forum-header .abs-blur-bg img{width:100%;height:100%;object-fit:cover}
|
||||
.forum-header .forum-mask{position:absolute;inset:0;background:rgba(76,80,87,.6)}
|
||||
.forum-header.blur-header .plate-thumb{width:90px;height:90px;flex-shrink:0}
|
||||
.forum-header.blur-header .plate-thumb > img{border-radius:var(--main-radius)}
|
||||
.forum-header.blur-header .plate-thumb{width:115px;height:115px;flex-shrink:0}
|
||||
.forum-header.blur-header .plate-thumb > img{border-radius:4px}
|
||||
.forum-header .more-btns{position:absolute;right:5px;top:3px;z-index:1;justify-content:flex-end}
|
||||
.forum-header .more-btns .item{padding:5px 7px;opacity:.8;font-size:1.2em;color:#fff;border:0;background:none;cursor:pointer}
|
||||
.forum-header .more-btns .item text{display:none}
|
||||
.forum-header .moderator-btns{display:flex;flex-wrap:wrap;align-items:center;gap:6px}
|
||||
.forum-header .moderator-btns .avatar-mini{--this-size:22px;margin-right:4px}
|
||||
.forum-header .moderator-btns .avatar-mini img{border-radius:100px}
|
||||
.forum-header .moderator-btns .but{font-size:12px;padding:3px 10px}
|
||||
.forum-header .moderator-btns .avatar-mini{--this-size:22px;margin-right:4px;display:inline-block}
|
||||
.forum-header .moderator-btns .avatar-mini img{border-radius:100px;width:100%;height:100%}
|
||||
.forum-header .moderator-btns .but{font-size:12px;padding:3px 10px;line-height:21px;min-width:90px}
|
||||
.forum-header .count-mates{margin-top:10px}
|
||||
.forum-header .count-mates item{display:inline-block}
|
||||
.forum-header .count-mates > item + item{border-left:1px solid rgba(255,255,255,.08);padding-left:20px;margin-left:20px}
|
||||
.blur-header .c-white{--this-bg:rgba(255,255,255,.12);--this-color:#fff}
|
||||
.forum-header .more-btns .btn-follow{color:#fff;border:0;background:none;cursor:pointer;opacity:.85;padding:5px 7px;font-size:1.2em}
|
||||
.forum-header .more-btns .btn-follow.active{color:#ff7800;opacity:1}
|
||||
|
||||
/* ── 帖子详情页 ───────────────────────────────────────────────── */
|
||||
.forum-post .single-wrap{width:100%}
|
||||
.single-fixed-btns{display:none}
|
||||
@media (min-width:768px){
|
||||
.forum-post .fixed-wrap-nav.single-fixed-btns{display:block}
|
||||
.single-fixed-btns .score-btns{display:block;text-align:center}
|
||||
.single-fixed-btns .score-btns text{display:block;font-size:12px;color:var(--muted-2-color);min-width:30px;margin:5px}
|
||||
.single-fixed-btns .btn-score{font-size:24px;color:var(--muted-color);display:inline-flex;align-items:center}
|
||||
.single-fixed-btns .btn-score.extra.active{color:#40a1ff}
|
||||
.single-fixed-btns .btn-score.deduct.active{color:#ff556d}
|
||||
}
|
||||
.forum-single-cover{border-radius:var(--main-radius);overflow:hidden}
|
||||
.forum-article{padding:20px 26px}
|
||||
.forum-article{padding:0 30px;overflow:hidden}
|
||||
.forum-article .article-header{margin-bottom:15px;padding-bottom:12px;margin-top:5px;border-bottom:1px solid var(--main-border-color)}
|
||||
.forum-article .article-title{font-size:24px;line-height:1.4;margin:0 0 10px;font-weight:600}
|
||||
.forum-article .article-title a{color:var(--key-color)}
|
||||
@@ -340,18 +368,32 @@ body.dark-theme .forum-header,body.dark-theme .forum-header .header-content{back
|
||||
.forum-article .wp-posts-content{font-size:15px;line-height:1.9;overflow-wrap:anywhere}
|
||||
.forum-article .article-tags{display:flex;flex-wrap:wrap;gap:6px}
|
||||
.forum-article .article-tags .but{font-size:12px;padding:4px 10px}
|
||||
.forum-article .score-box.single-footer{margin:10px 0 20px}
|
||||
.forum-article .score-box .score-btns{margin-bottom:10px;border-radius:100px;padding:8px 24px;box-shadow:0 2px 10px 4px var(--main-shadow);display:inline-flex;align-items:center}
|
||||
.forum-article .score-box .btn-score{font-size:24px;color:var(--muted-color);padding:2px}
|
||||
.forum-article .score-box .btn-score.extra.active{color:#40a1ff}
|
||||
.forum-article .score-box .btn-score.deduct.active{color:#ff556d}
|
||||
.forum-article .score-box .score-btns text{font-size:12px;color:var(--muted-2-color);min-width:30px;margin:5px}
|
||||
.forum-single-author{background-color:var(--muted-bg-2-color);box-shadow:none}
|
||||
.forum-single-author .card-content{display:flex;gap:40px;padding:15px 40px}
|
||||
.forum-single-author .user-content{display:flex;align-items:center;gap:20px}
|
||||
.forum-single-author .count-info{display:flex;flex-direction:column;gap:6px}
|
||||
.forum-single-author .user-info .border-bottom{padding-bottom:10px;margin-bottom:10px}
|
||||
.forum-single-author .user-desc{font-size:13px}
|
||||
.forum-single-author .more-posts-mini .item{padding:3px 0}
|
||||
.forum-single-author .more-posts-mini a{display:block;color:var(--muted-2-color);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
||||
.footer-actions{margin:18px -10px 10px;padding-top:14px;border-top:1px solid var(--main-border-color)}
|
||||
.footer-actions .item{display:flex;align-items:center;padding:4px 8px;margin:0 4px;color:var(--muted-color);border:0;background:none;cursor:pointer;border-radius:4px}
|
||||
.footer-actions .item:hover{background:var(--muted-border-color)}
|
||||
.footer-actions .item > i{font-size:18px;margin-right:5px}
|
||||
.footer-actions .item{display:flex;align-items:center;padding:0 4px;margin:0 4px;color:var(--muted-color);border:0;background:none;cursor:pointer}
|
||||
.footer-actions .item:hover{color:var(--focus-color)}
|
||||
.footer-actions .item > i,.footer-actions .item > .icon{font-size:20px;margin-right:4px}
|
||||
.footer-actions .item text{font-size:12px}
|
||||
.single-footer .but{font-size:12px;padding:4px 12px}
|
||||
.vote-box.forum-vote{padding:20px 0}
|
||||
.vote-box.forum-vote{padding:15px 30px}
|
||||
.vote-box.forum-vote h2{font-size:17px}
|
||||
.vote-item{position:relative;overflow:hidden;padding:8px 3.5em 8px 15px;margin-bottom:6px;border-radius:50px;background:var(--muted-border-color);color:var(--muted-color);display:block;cursor:pointer;text-overflow:ellipsis;white-space:nowrap}
|
||||
.vote-item{position:relative;overflow:hidden;padding:5px 3.5em 5px 15px;margin-bottom:6px;border-radius:50px;background:var(--main-bg-color);color:var(--muted-color);display:block;cursor:pointer;text-overflow:ellipsis;white-space:nowrap}
|
||||
.vote-item input{margin-right:8px}
|
||||
.vote-progress{position:absolute;left:0;top:0;bottom:0;background:rgba(130,130,130,.15);transition:width .6s,background .2s;border-radius:50px;width:0;z-index:-1}
|
||||
.vote-item .vote-count{position:absolute;right:14px;font-size:.9em;opacity:.8}
|
||||
.vote-progress{position:absolute;left:0;top:0;bottom:0;background:rgba(130,130,130,.15);transition:width 1s,background .2s;border-radius:50px;width:0;z-index:-1}
|
||||
.vote-item .vote-count{position:absolute;right:14px;font-size:.9em;margin-top:.1em;opacity:.8}
|
||||
.vote-box.forum-vote button{display:block;margin:16px auto 0}
|
||||
|
||||
/* ── 发帖 / 编辑页 ────────────────────────────────────────────── */
|
||||
@@ -384,3 +426,21 @@ body.dark-theme .forum-header,body.dark-theme .forum-header .header-content{back
|
||||
.forum-header.blur-header .plate-thumb{width:64px;height:64px}
|
||||
}
|
||||
body.dark-theme .forum-header.blur-header .forum-mask{background:rgba(20,22,26,.72)}
|
||||
|
||||
/* ── 详情页侧栏版块信息卡(参考 .plate-info-sidebar) ─────────────── */
|
||||
.plate-info-sidebar .forum-header{box-shadow:0 0 10px var(--main-shadow);border-radius:var(--main-radius)}
|
||||
.plate-info-sidebar .header-content{padding:55px 20px 25px;background:var(--main-bg-color);border-radius:var(--main-radius)}
|
||||
.plate-info-sidebar .plate-thumb{width:100px;height:100px;margin:0 auto 10px}
|
||||
.plate-info-sidebar .plate-thumb > img{border-radius:4px}
|
||||
.plate-info-sidebar .forum-title{font-size:16px;text-align:center}
|
||||
.plate-info-sidebar .count-mates{text-align:center;color:var(--muted-2-color)}
|
||||
.plate-info-sidebar .count-mates > item + item{border-left:1px solid var(--main-border-color);padding-left:12px;margin-left:12px}
|
||||
.plate-info-sidebar .follow-info{background:var(--main-border-color);box-shadow:none;color:var(--focus-color);padding:6px 12px;margin-top:38px;opacity:.9}
|
||||
@media (max-width:640px){
|
||||
.forum-single-author .card-content{flex-direction:column;gap:20px;padding:5px 12px}
|
||||
.forum-single-author .user-info .border-bottom{padding-bottom:10px;margin-bottom:10px}
|
||||
.forum-article{padding:0 15px}
|
||||
.forum-article .article-title{font-size:20px}
|
||||
.forum-header.blur-header .header-content{padding:60px 15px 30px}
|
||||
.forum-header.blur-header .plate-thumb{width:105px;height:105px;order:2;margin:0 0 0 20px}
|
||||
}
|
||||
@@ -359,6 +359,24 @@
|
||||
const label = button.querySelector('text')
|
||||
if (label) label.textContent = following ? '已关注' : '关注'
|
||||
else button.textContent = result.data?.label || button.textContent
|
||||
} else if (action === 'favorite') {
|
||||
const active = result.data?.active === true
|
||||
button.classList.toggle('active', active)
|
||||
const label = button.querySelector('text')
|
||||
if (label) label.textContent = active ? '已收藏' : '收藏'
|
||||
} else if (action === 'score') {
|
||||
// Card score group: flip the active arrow and refresh the shared counter.
|
||||
const group = button.closest('.score-btns')
|
||||
if (group) {
|
||||
const isUp = button.dataset.direction !== 'down'
|
||||
const userScore = Number(result.data?.user_score || 0)
|
||||
group.querySelectorAll('.btn-score').forEach((item) => {
|
||||
const own = (item.dataset.direction !== 'down') === isUp
|
||||
item.classList.toggle('active', own && userScore !== 0)
|
||||
})
|
||||
const counter = group.querySelector('text')
|
||||
if (counter) counter.textContent = Number(result.data?.score || 0) > 0 ? String(result.data.score) : '评分'
|
||||
}
|
||||
} else if (button.querySelector('text')) {
|
||||
button.querySelector('text').textContent = result.data?.label || result.message || button.querySelector('text').textContent
|
||||
} else {
|
||||
@@ -403,7 +421,7 @@
|
||||
const loadMore = async (link, pane) => {
|
||||
if (pane.dataset.loading === '1') return
|
||||
pane.dataset.loading = '1'
|
||||
const more = link.closest('.forum-more')
|
||||
const more = link.closest('.theme-pagination') || link.closest('.ajax-pag')
|
||||
const loader = [...pane.children].find((item) => item.classList.contains('post_ajax_loader'))
|
||||
more?.classList.add('is-loading')
|
||||
loader?.classList.add('is-loading')
|
||||
@@ -414,7 +432,7 @@
|
||||
const source = doc.getElementById(pane.id)
|
||||
if (!source) throw new Error('内容不存在')
|
||||
const anchor = more || null
|
||||
const incoming = [...source.children].filter((item) => !item.classList.contains('forum-tab-pane') && !item.classList.contains('forum-more') && !item.classList.contains('post_ajax_loader'))
|
||||
const incoming = [...source.children].filter((item) => !item.classList.contains('forum-tab-pane') && !item.classList.contains('theme-pagination') && !item.classList.contains('post_ajax_loader'))
|
||||
incoming.forEach((item) => pane.insertBefore(item, anchor))
|
||||
const next = source.querySelector('[data-forum-more]')
|
||||
if (next && anchor) anchor.querySelector('[data-forum-more]')?.setAttribute('href', next.getAttribute('href'))
|
||||
@@ -449,7 +467,10 @@
|
||||
}
|
||||
const more = event.target.closest('[data-forum-more]')
|
||||
if (more) {
|
||||
// The wrapper also carries .ajax-next for the theme's pagination styles;
|
||||
// stop the generic handler from firing a second request.
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
const pane = more.closest('.forum-tab-pane')
|
||||
if (pane) loadMore(more, pane)
|
||||
}
|
||||
|
||||
@@ -53,16 +53,17 @@ final class SchemaForum {
|
||||
self::field('jio_forum_home_follow_plate', '版块栏目显示已关注版块', 'switcher', true),
|
||||
self::field('jio_forum_home_recommend_plate', '关注栏目显示版块推荐', 'switcher', true),
|
||||
self::field('jio_forum_show_plate_cover', '显示版块封面', 'switcher', true),
|
||||
self::field('jio_forum_plate_tab_active', '版块页默认栏目', 'number', 1, ['min' => 1, 'max' => 20, 'description' => '打开版块页面时默认显示第几个栏目']),
|
||||
self::field('jio_forum_plate_tab_active', '版块页默认栏目', 'number', 2, ['min' => 1, 'max' => 20, 'description' => '打开版块页面时默认显示第几个栏目']),
|
||||
self::field('jio_forum_plate_tab_items', '版块页栏目', 'repeater', self::default_plate_tabs(), [
|
||||
'addText' => '添加栏目',
|
||||
'description' => '版块页顶部的栏目条;留空则使用「最新发布 / 最近回复 / 热门 / 精华」默认栏目',
|
||||
'description' => '版块页顶部的栏目条;留空则使用「全部 / 推荐 / 最新回复 / 热门 / 精华」默认栏目',
|
||||
'fields' => [
|
||||
self::field('title', '栏目标题', 'input', ''),
|
||||
self::field('orderby', '排序方式', 'select', 'date', ['options' => self::options([
|
||||
'date' => '发布时间',
|
||||
'modified' => '修改时间',
|
||||
'last_reply' => '最新回复',
|
||||
'popular' => '推荐指数',
|
||||
'views' => '阅读量',
|
||||
'score' => '评分',
|
||||
'comment_count' => '回复数量',
|
||||
@@ -116,8 +117,9 @@ final class SchemaForum {
|
||||
/** Initial plate-page tab rows; the listing falls back to these when unset. */
|
||||
private static function default_plate_tabs(): array {
|
||||
return [
|
||||
['title' => '最新发布', 'orderby' => 'date', 'filter' => '', 'style' => 'detail'],
|
||||
['title' => '最近回复', 'orderby' => 'last_reply', 'filter' => '', 'style' => 'detail'],
|
||||
['title' => '全部', 'orderby' => 'modified', 'filter' => '', 'style' => 'mini'],
|
||||
['title' => '推荐', 'orderby' => 'popular', 'filter' => '', 'style' => 'detail'],
|
||||
['title' => '最新回复', 'orderby' => 'last_reply', 'filter' => '', 'style' => 'detail'],
|
||||
['title' => '热门', 'orderby' => 'views', 'filter' => '', 'style' => 'detail'],
|
||||
['title' => '精华', 'orderby' => 'modified', 'filter' => 'essence', 'style' => 'detail'],
|
||||
];
|
||||
|
||||
@@ -66,6 +66,10 @@ final class Access {
|
||||
return $user_id > 0 && (bool) get_user_meta($user_id, '_jio_forum_follow_' . $plate_id, true);
|
||||
}
|
||||
|
||||
public static function favorites(int $user_id, int $post_id): bool {
|
||||
return $user_id > 0 && (bool) get_user_meta($user_id, '_jio_forum_favorite_' . $post_id, true);
|
||||
}
|
||||
|
||||
public static function can_view(int $user_id, int $post_id): bool {
|
||||
$post = get_post($post_id);
|
||||
if (!$post instanceof \WP_Post || $post->post_type !== Core::POST) {
|
||||
|
||||
+85
-18
@@ -7,8 +7,10 @@ defined('ABSPATH') || exit;
|
||||
final class Cards {
|
||||
/** @var array<int, \WP_Comment> */
|
||||
private static array $hot = [];
|
||||
/** @var array<int, string> */
|
||||
private static array $last_reply = [];
|
||||
|
||||
/** Prime authors, plates and hot replies for a page of posts in batch queries. */
|
||||
/** Prime authors, plates, hot replies and last replies for a page of posts in batch queries. */
|
||||
public static function prime(array $posts): void {
|
||||
$ids = $authors = $plates = [];
|
||||
foreach ($posts as $post) {
|
||||
@@ -26,6 +28,20 @@ final class Cards {
|
||||
$post_id = (int) $comment->comment_post_ID;
|
||||
if (isset($wanted[$post_id]) && !isset(self::$hot[$post_id])) self::$hot[$post_id] = $comment;
|
||||
}
|
||||
self::prime_last_replies($ids);
|
||||
}
|
||||
|
||||
/** @param int[] $ids */
|
||||
private static function prime_last_replies(array $ids): void {
|
||||
$missing = array_values(array_diff(array_unique(array_map('absint', $ids)), array_keys(self::$last_reply)));
|
||||
if (!$missing) return;
|
||||
global $wpdb;
|
||||
$placeholders = implode(',', array_fill(0, count($missing), '%d'));
|
||||
$sql = "SELECT comment_post_ID AS post_id, MAX(comment_date) AS last_date FROM {$wpdb->comments} WHERE comment_approved = '1' AND comment_post_ID IN ($placeholders) GROUP BY comment_post_ID";
|
||||
$rows = $wpdb->get_results($wpdb->prepare($sql, $missing)); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
||||
foreach ((array) $rows as $row) {
|
||||
self::$last_reply[(int) $row->post_id] = (string) $row->last_date;
|
||||
}
|
||||
}
|
||||
|
||||
public static function post_detail(\WP_Post $post, string $class = 'alone ajax-item', bool $show_plate = true, bool $show_topping = false): string {
|
||||
@@ -51,12 +67,21 @@ final class Cards {
|
||||
$html .= '<div class="mr20 forum-user">' . self::avatar($author, 'avatar-img forum-avatar') . '<span class="show-sm ml6 flex ac" style="width: 90%;">' . $name . '</span></div>';
|
||||
$html .= '<div class="entry-info">' . self::title($post, 'forum-title flex ac', 'text-ellipsis', $show_topping);
|
||||
$html .= '<div class="flex ac jsb item-meta"><div class="meta-left em09-sm flex"><span class="hide-sm">' . $name . '</span>';
|
||||
$html .= '<span class="icon-circle" title="' . esc_attr(sprintf('发布时间:%s', get_the_date('Y-m-d H:i:s', $post))) . '">' . esc_html(self::ago($post->post_date) . '发布') . '</span></div>';
|
||||
$html .= self::reply_time($post) . '</div>';
|
||||
$html .= '<div class="meta-right">' . self::icon_metas($post) . '</div></div></div>';
|
||||
return $html . '</article>';
|
||||
}
|
||||
|
||||
public static function title(\WP_Post $post, string $class, string $link_class = '', bool $show_topping = false): string {
|
||||
/** Reference mini-card meta: "最后回复" when replies exist, otherwise the publish time. */
|
||||
private static function reply_time(\WP_Post $post): string {
|
||||
$last = self::$last_reply[$post->ID] ?? '';
|
||||
if ($last !== '') {
|
||||
return '<span class="icon-circle" title="' . esc_attr(sprintf('最后回复:%s', $last)) . '">' . esc_html(self::ago($last) . '回复') . '</span>';
|
||||
}
|
||||
return '<span class="icon-circle" title="' . esc_attr(sprintf('发布时间:%s', get_the_date('Y-m-d H:i:s', $post))) . '">' . esc_html(self::ago($post->post_date) . '发布') . '</span>';
|
||||
}
|
||||
|
||||
public static function title(\WP_Post $post, string $class, string $link_class = '', bool $show_topping = false, string $tag = 'h2'): string {
|
||||
$id = $post->ID;
|
||||
$badges = '';
|
||||
if ($show_topping && get_post_meta($id, '_jio_forum_pinned', true)) $badges .= '<span class="badg badg-sm c-blue mr3">置顶</span>';
|
||||
@@ -70,7 +95,8 @@ final class Cards {
|
||||
}
|
||||
$url = $post->post_status === 'publish' ? get_permalink($post) : Core::edit_url($id);
|
||||
$link_class = $link_class !== '' ? ' class="' . esc_attr($link_class) . '"' : '';
|
||||
return '<h2 class="' . esc_attr($class) . '"><a' . $link_class . ' href="' . esc_url($url) . '" title="' . esc_attr($post->post_title) . '">' . $badges . esc_html($post->post_title) . '</a></h2>';
|
||||
$tag = in_array($tag, ['h1', 'h2'], true) ? $tag : 'h2';
|
||||
return '<' . $tag . ' class="' . esc_attr($class) . '"><a' . $link_class . ' href="' . esc_url($url) . '" title="' . esc_attr($post->post_title) . '">' . $badges . esc_html($post->post_title) . '</a></' . $tag . '>';
|
||||
}
|
||||
|
||||
/** Plate page header: blurred cover, title, stats and moderators (reference layout). */
|
||||
@@ -94,6 +120,7 @@ final class Cards {
|
||||
$excerpt = wp_trim_words(wp_strip_all_tags($plate->post_excerpt ?: $plate->post_content), 40);
|
||||
$html = '<div class="plate-header-wrap"><div class="forum-header blur-header relative-h mb20">';
|
||||
$html .= '<div class="abs-blur-bg">' . $thumb . '</div><div class="absolute forum-mask"></div>';
|
||||
$html .= self::plate_more_btns($plate);
|
||||
if (get_post_meta($id, '_jio_forum_hot', true)) {
|
||||
$html .= '<span class="img-badge top jb-red px12-sm">热门</span>';
|
||||
}
|
||||
@@ -107,18 +134,32 @@ final class Cards {
|
||||
return $html . '</div></div></div>';
|
||||
}
|
||||
|
||||
/** Header corner actions: follow, search and share (reference `.more-btns`). */
|
||||
private static function plate_more_btns(\WP_Post $plate): string {
|
||||
$html = '<div class="flex ac more-btns">' . self::follow_button($plate->ID, '');
|
||||
if (jio_get_setting('jio_forum_search_enabled', true)) {
|
||||
$html .= '<a class="main-search-btn item" href="' . esc_url(add_query_arg(['type' => 'plate', 's' => $plate->post_title], home_url('/'))) . '" title="搜索"><i class="fa fas fa-search"></i></a>';
|
||||
}
|
||||
if (function_exists('jio_get_post_share_btn')) {
|
||||
$html .= jio_get_post_share_btn($plate, 'item btn-share', true, true);
|
||||
}
|
||||
return $html . '</div>';
|
||||
}
|
||||
|
||||
/** Plate moderator avatars row under the header. */
|
||||
private static function plate_moderator_btns(\WP_Post $plate): string {
|
||||
$ids = array_values(array_unique(array_filter(array_merge(
|
||||
[(int) $plate->post_author],
|
||||
array_map('absint', (array) get_post_meta($plate->ID, '_jio_forum_moderators', true))
|
||||
))));
|
||||
if (!$ids) return '';
|
||||
$btns = '';
|
||||
foreach ($ids as $user_id) {
|
||||
$user = get_userdata($user_id);
|
||||
if (!$user) continue;
|
||||
$btns .= '<a class="but c-white mr6 mt6" href="' . esc_url(get_author_posts_url($user_id)) . '" title="' . esc_attr($user->display_name) . '"><span class="avatar-mini avatar-img">' . get_avatar($user_id, 40) . '</span><span class="ml6">' . esc_html($user->display_name) . '</span></a>';
|
||||
$btns .= '<a class="but c-white mr6 mt6" href="' . esc_url(get_author_posts_url($user_id)) . '" title="' . esc_attr($user->display_name) . '"><span class="avatar-mini mr6">' . get_avatar($user_id, 40) . '</span>' . esc_html($user->display_name) . '</a>';
|
||||
}
|
||||
if (is_user_logged_in() && Access::can_publish(get_current_user_id(), $plate->ID)) {
|
||||
$btns .= '<a rel="nofollow" class="but c-white mr6 mt6" href="' . esc_url(add_query_arg('plate', $plate->ID, Core::edit_url())) . '"><i class="fa fas fa-plus mr6"></i>发布</a>';
|
||||
}
|
||||
$html = '<div class="mt10 moderator-btns em09">' . $btns;
|
||||
if (is_user_logged_in() && !Access::is_moderator(get_current_user_id(), $plate->ID) && jio_get_setting('jio_forum_moderator_apply', true)) {
|
||||
@@ -127,7 +168,8 @@ final class Cards {
|
||||
return $html . '</div>';
|
||||
}
|
||||
|
||||
public static function plate_item(\WP_Post $plate): string { $url = get_permalink($plate);
|
||||
public static function plate_item(\WP_Post $plate): string {
|
||||
$url = get_permalink($plate);
|
||||
$counts = PlateStats::get($plate->ID);
|
||||
$today = $counts['today'] > 0 ? '<span class="badg but-plate hide-sm flex0" title="' . esc_attr(sprintf('今日新帖 %d', $counts['today'])) . '"><i class="fa fas fa-comment-dots c-red mr3"></i>' . esc_html(sprintf('今日:%s', jio_cut_count($counts['today']))) . '</span>' : '';
|
||||
$excerpt = wp_trim_words(wp_strip_all_tags($plate->post_excerpt ?: $plate->post_content), 30);
|
||||
@@ -165,10 +207,10 @@ final class Cards {
|
||||
|
||||
public static function follow_button(int $plate_id, string $class): string {
|
||||
if (!is_user_logged_in()) {
|
||||
return '<a class="btn-follow ' . esc_attr($class) . '" href="' . esc_url(jio_get_login_url(get_permalink($plate_id))) . '"><text>关注</text></a>';
|
||||
return '<a class="btn-follow ' . esc_attr($class) . '" href="' . esc_url(jio_get_login_url(get_permalink($plate_id))) . '"><text><i class="fa far fa-heart mr6 em12"></i></text></a>';
|
||||
}
|
||||
$followed = Access::follows(get_current_user_id(), $plate_id);
|
||||
return '<button type="button" class="btn-follow ' . esc_attr($class . ($followed ? ' active' : '')) . '" data-forum-action="follow" data-id="' . (int) $plate_id . '"><text>' . ($followed ? '已关注' : '关注') . '</text></button>';
|
||||
return '<button type="button" class="btn-follow ' . esc_attr($class . ($followed ? ' active' : '')) . '" data-forum-action="follow" data-id="' . (int) $plate_id . '"><text><i class="fa ' . ($followed ? 'fas' : 'far') . ' fa-heart mr6 em12"></i></text></button>';
|
||||
}
|
||||
|
||||
public static function plate_button(int $plate_id): string {
|
||||
@@ -185,15 +227,29 @@ final class Cards {
|
||||
}
|
||||
|
||||
private static function author_link(int $user_id): string {
|
||||
return '<a class="display-name text-ellipsis" href="' . esc_url(get_author_posts_url($user_id)) . '">' . esc_html((string) get_the_author_meta('display_name', $user_id)) . '</a>';
|
||||
$url = function_exists('jio_get_n') ? jio_get_n($user_id) : get_author_posts_url($user_id);
|
||||
return '<a class="display-name text-ellipsis" href="' . esc_url($url) . '">' . esc_html((string) get_the_author_meta('display_name', $user_id)) . '</a>';
|
||||
}
|
||||
|
||||
/** Reference author row: avatar, name, publish time + views, follow and message actions. */
|
||||
private static function author_box(\WP_Post $post): string {
|
||||
$author = (int) $post->post_author;
|
||||
$name = function_exists('jio_get_user_name') ? jio_get_user_name(['id' => $author, 'class' => 'flex ac flex1']) : self::author_link($author);
|
||||
$views = jio_cut_count((int) get_post_meta($post->ID, '_jio_forum_views', true));
|
||||
$desc = '<span title="' . esc_attr(get_the_date('Y-m-d H:i:s', $post)) . '">' . esc_html(self::ago($post->post_date)) . '</span><span class="icon-spot">' . esc_html(sprintf('%s次阅读', $views)) . '</span>';
|
||||
return '<div class="user-info flex ac mb10">' . self::avatar($author, 'avatar-img') . '<div class="user-right flex flex1 ac jsb ml10"><div class="flex1 overflow-hidden"><div class="flex ac">' . $name . '</div><div class="px12-sm muted-2-color text-ellipsis mt3">' . $desc . '</div></div></div></div>';
|
||||
$desc = '<span title="' . esc_attr(get_the_date('Y-m-d H:i:s', $post)) . '">' . esc_html(self::ago($post->post_date) . '发布') . '</span><span class="icon-spot">' . esc_html(sprintf('%s次阅读', $views)) . '</span>';
|
||||
$actions = '';
|
||||
if (function_exists('jio_get_user_follow')) {
|
||||
$actions .= jio_get_user_follow('px12-sm ml10 follow but c-red', $author);
|
||||
}
|
||||
if (function_exists('jio_get_messages_page_url')) {
|
||||
$messages = jio_get_messages_page_url();
|
||||
if ($messages !== '' && get_current_user_id() !== $author) {
|
||||
$actions .= '<a class="ml6 but c-blue px12-sm" href="' . esc_url($messages) . '"><i class="fa far fa-envelope mr3"></i>私信</a>';
|
||||
}
|
||||
}
|
||||
$html = '<div class="user-info flex ac mb10">' . self::avatar($author, 'avatar-img') . '<div class="user-right flex flex1 ac jsb ml10"><div class="flex1 overflow-hidden"><div class="flex ac">' . $name . '</div><div class="px12-sm muted-2-color text-ellipsis">' . $desc . '</div></div>';
|
||||
if ($actions !== '') $html .= '<div class="flex0 user-action">' . $actions . '</div>';
|
||||
return $html . '</div></div>';
|
||||
}
|
||||
|
||||
private static function status_badge(\WP_Post $post): string {
|
||||
@@ -205,6 +261,7 @@ final class Cards {
|
||||
if (!has_post_thumbnail($post)) return '';
|
||||
return '<div class="forum-lists-cover mb10"><div class="graphic imgbox-container" style="padding-bottom:45%">' . get_the_post_thumbnail($post, 'large', ['class' => 'fit-cover']) . '</div></div>';
|
||||
}
|
||||
|
||||
private static function content(\WP_Post $post, bool $can_view): string {
|
||||
if (!$can_view) {
|
||||
return '<div class="hide-post mt6"><i class="fa fas fa-unlock-alt mr6"></i>此处内容已隐藏</div>';
|
||||
@@ -237,23 +294,33 @@ final class Cards {
|
||||
return $html . '</div>';
|
||||
}
|
||||
|
||||
/** Reference action row: score up/down group, reply count and share. */
|
||||
private static function action_meta(\WP_Post $post): string {
|
||||
$id = $post->ID;
|
||||
$score = (int) get_post_meta($id, '_jio_forum_score', true);
|
||||
$reply = (int) $post->comment_count;
|
||||
$html = '<div class="action-meta flex0 flex jsb">';
|
||||
if (jio_get_setting('jio_forum_score_enabled', true)) {
|
||||
$html .= is_user_logged_in()
|
||||
? '<button type="button" class="item btn-score" data-forum-action="score" data-direction="up" data-id="' . $id . '"><i class="fa far fa-thumbs-up"></i><text>' . esc_html($score ? jio_cut_count($score) : '加分') . '</text></button>'
|
||||
: '<a class="item btn-score" href="' . esc_url(jio_get_login_url(get_permalink($post))) . '"><i class="fa far fa-thumbs-up"></i><text>' . esc_html($score ? jio_cut_count($score) : '加分') . '</text></a>';
|
||||
$user_id = get_current_user_id();
|
||||
$user_score = $user_id > 0 ? (int) get_user_meta($user_id, '_jio_forum_score_' . $id, true) : 0;
|
||||
$score = (int) get_post_meta($id, '_jio_forum_score', true);
|
||||
$html .= '<div class="score-btns">' . self::score_button($post, 'up', 'extra', $user_score > 0) . '<text>' . esc_html($score ? jio_cut_count($score) : '评分') . '</text>' . self::score_button($post, 'down', 'deduct', $user_score < 0) . '</div>';
|
||||
}
|
||||
$reply = (int) $post->comment_count;
|
||||
$html .= '<a rel="nofollow" href="' . esc_url(get_permalink($post) . '#comments') . '" class="item"><i class="fa far fa-comment"></i><text>' . esc_html($reply ? jio_cut_count($reply) : '回复') . '</text></a>';
|
||||
if ($post->post_status === 'publish' && function_exists('jio_get_post_share_btn')) {
|
||||
$html .= jio_get_post_share_btn($post, 'item btn-share', true, false);
|
||||
$html .= jio_get_post_share_btn($post, 'item btn-share', true, true);
|
||||
}
|
||||
return $html . '</div>';
|
||||
}
|
||||
|
||||
private static function score_button(\WP_Post $post, string $direction, string $kind, bool $active): string {
|
||||
$icon = '<i class="fa fas fa-' . ($direction === 'up' ? 'plus' : 'minus') . '-circle"></i>';
|
||||
$class = 'btn-score ' . $kind . ($active ? ' active' : '');
|
||||
if (!is_user_logged_in()) {
|
||||
return '<a href="' . esc_url(jio_get_login_url(get_permalink($post))) . '" class="' . esc_attr($class . ' signin-loader') . '" data-id="' . (int) $post->ID . '">' . $icon . '</a>';
|
||||
}
|
||||
return '<button type="button" class="' . esc_attr($class) . '" data-forum-action="score" data-direction="' . esc_attr($direction) . '" data-id="' . (int) $post->ID . '">' . $icon . '</button>';
|
||||
}
|
||||
|
||||
private static function icon_metas(\WP_Post $post): string {
|
||||
$id = $post->ID;
|
||||
return '<item><i class="fa far fa-eye mr3"></i>' . esc_html(jio_cut_count((int) get_post_meta($id, '_jio_forum_views', true))) . '</item>'
|
||||
|
||||
+20
-1
@@ -30,13 +30,32 @@ final class Core {
|
||||
add_action('untrashed_post', [self::class, 'restore_trashed_plate']);
|
||||
add_filter('wp_untrash_post_status', [self::class, 'restore_status'], 10, 2);
|
||||
add_filter('jio_is_show_sidebar', [self::class, 'show_home_sidebar']);
|
||||
add_filter('jio_is_show_sidebar', [self::class, 'show_forum_sidebar']);
|
||||
}
|
||||
|
||||
/** The forum home renders its own sidebar column, so keep the layout slot open. */
|
||||
public static function show_home_sidebar(bool $show): bool {
|
||||
if ($show || !self::enabled() || !is_page_template('templates/pages/page-forums.php')) return $show;
|
||||
return self::sidebar_has_widgets('forum_home');
|
||||
}
|
||||
|
||||
/** Forum routes own their widget areas; a configured forum sidebar must open the column. */
|
||||
public static function show_forum_sidebar(bool $show): bool {
|
||||
if ($show || !self::enabled()) return $show;
|
||||
$context = '';
|
||||
if (is_singular(self::POST)) $context = 'forum_post';
|
||||
elseif (is_singular(self::PLATE)) $context = 'forum_plate';
|
||||
elseif (is_tax([self::CATEGORY, self::TOPIC, self::TAG])) $context = 'forum_term';
|
||||
return $context !== '' && self::sidebar_has_widgets($context);
|
||||
}
|
||||
|
||||
private static function sidebar_has_widgets(string $context): bool {
|
||||
$cfg = function_exists('jio_get_sidebar_config_safe') ? jio_get_sidebar_config_safe() : [];
|
||||
return !empty($cfg['enabled']);
|
||||
if (empty($cfg['enabled'])) return false;
|
||||
foreach ([$context . '_sidebar', 'all_sidebar_top', 'all_sidebar_bottom'] as $area) {
|
||||
if (is_active_sidebar($area)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function enabled(): bool {
|
||||
|
||||
+11
-11
@@ -11,7 +11,7 @@ final class EditView {
|
||||
$post = $edit_id > 0 ? get_post($edit_id) : null;
|
||||
if ($edit_id > 0 && (!$post instanceof \WP_Post || !Access::can_manage_post(get_current_user_id(), $edit_id))) {
|
||||
status_header(403);
|
||||
echo '<main id="forum" class="jio-forum forum-edit"><div class="container"><div class="zib-widget full-widget-sm text-center" style="min-height:60vh;">' . jio_get_null('抱歉!您暂无编辑此内容的权限', 60, 'null-post.svg') . '</div></div></main>';
|
||||
echo '<main id="forum" class="jio-forum forum-edit"><div class="container"><div class="jio-panel full-widget-sm text-center" style="min-height:60vh;">' . jio_get_null('抱歉!您暂无编辑此内容的权限', 60, 'null-post.svg') . '</div></div></main>';
|
||||
get_footer();
|
||||
return;
|
||||
}
|
||||
@@ -25,7 +25,7 @@ final class EditView {
|
||||
|
||||
wp_enqueue_editor();
|
||||
echo '<main id="forum" class="jio-forum forum-edit"><form id="bbs-posts-edit" data-forum-form="post" data-id="' . (int) $edit_id . '"><div class="container"><div class="content-wrap"><div class="content-layout">';
|
||||
echo '<div class="zib-widget full-widget-sm editor-main-box" style="min-height:60vh">';
|
||||
echo '<div class="jio-panel full-widget-sm editor-main-box" style="min-height:60vh">';
|
||||
if ($user_id <= 0) {
|
||||
echo jio_get_null('请先登录后再发布', 40, 'null-user.svg') . '<p class="text-center"><a class="but jb-blue padding-lg" href="' . esc_url(jio_get_login_url(Core::edit_url($edit_id))) . '"><i class="fa fas fa-sign-in-alt mr6"></i>登录</a></p>';
|
||||
echo '</div>';
|
||||
@@ -73,7 +73,7 @@ final class EditView {
|
||||
echo self::vote_box($vote_options, $post);
|
||||
echo self::hide_box($post);
|
||||
if (!$post && function_exists('jio_render_captcha') && function_exists('jio_is_captcha_enabled_for') && jio_is_captcha_enabled_for('forum_post')) {
|
||||
echo '<div class="zib-widget mb10-sm mb20 jio-forum__captcha">';
|
||||
echo '<div class="jio-panel mb10-sm mb20 jio-forum__captcha">';
|
||||
jio_render_captcha('forum_post');
|
||||
echo '</div>';
|
||||
}
|
||||
@@ -90,7 +90,7 @@ final class EditView {
|
||||
|
||||
private static function submit_box(?\WP_Post $post): string {
|
||||
$last = $post ? get_the_modified_time('Y-m-d H:i:s', $post->ID) : '';
|
||||
$html = '<div class="zib-widget mb10-sm mb20"><div class="but-average mb20 main-radius">';
|
||||
$html = '<div class="jio-panel mb10-sm mb20"><div class="but-average mb20 main-radius">';
|
||||
if (!$post || !in_array($post->post_status, ['publish', 'pending'], true)) {
|
||||
$html .= '<button type="button" class="but jb-green padding-10" data-forum-draft><i class="fa far fa-save mr6"></i>保存草稿</button>';
|
||||
}
|
||||
@@ -109,7 +109,7 @@ final class EditView {
|
||||
foreach (['pending' => '待审核', 'draft' => '草稿', 'publish' => '发布'] as $key => $label) {
|
||||
$list .= '<span data-forum-status="' . $key . '" class="badg mr3 p2-10 pointer' . ($key === $status ? ' active' : '') . '">' . $label . '</span>';
|
||||
}
|
||||
return '<div class="zib-widget mb10 type-drop"><div class="flex ac jsb"><div class="flex ac c-red"><i class="fa fas fa-thumbtack mr10"></i>设置状态</div><div class="em09">' . $list . '</div></div><input type="hidden" name="post_status" value="' . esc_attr($status) . '"></div>';
|
||||
return '<div class="jio-panel mb10 type-drop"><div class="flex ac jsb"><div class="flex ac c-red"><i class="fa fas fa-thumbtack mr10"></i>设置状态</div><div class="em09">' . $list . '</div></div><input type="hidden" name="post_status" value="' . esc_attr($status) . '"></div>';
|
||||
}
|
||||
|
||||
private static function allow_view_box(string $current): string {
|
||||
@@ -118,7 +118,7 @@ final class EditView {
|
||||
foreach ($labels as $key => $label) {
|
||||
$options .= '<div data-forum-view="' . $key . '" class="pointer but p2-10 mb6' . ($key === $current ? ' active' : '') . '">' . esc_html($label) . '</div>';
|
||||
}
|
||||
return '<div class="allow-view-drop drop-select dropdown zib-widget mb10-sm mb20"><div data-toggle-class="open" data-target=".allow-view-drop" class="flex ac jsb drop-btn"><div class="flex ac"><i class="fa far fa-eye mr6"></i>阅读权限</div><div class="flex ac"><span name="view_limit" class="em09 muted-2-color">' . esc_html($labels[$current] ?? '公开') . '</span><i class="ml6 fa fas fa-angle-right em12"></i></div></div><div class="dropdown-menu fluid"><div class="padding-10 flex jsb muted-2-color em09">设置阅读权限<span data-toggle-class="close" data-target=".allow-view-drop" class="pointer">完成</span></div><div class="mini-scrollbar padding-w10 select-drop-box">' . $options . '</div></div></div>';
|
||||
return '<div class="allow-view-drop drop-select dropdown jio-panel mb10-sm mb20"><div data-toggle-class="open" data-target=".allow-view-drop" class="flex ac jsb drop-btn"><div class="flex ac"><i class="fa far fa-eye mr6"></i>阅读权限</div><div class="flex ac"><span name="view_limit" class="em09 muted-2-color">' . esc_html($labels[$current] ?? '公开') . '</span><i class="ml6 fa fas fa-angle-right em12"></i></div></div><div class="dropdown-menu fluid"><div class="padding-10 flex jsb muted-2-color em09">设置阅读权限<span data-toggle-class="close" data-target=".allow-view-drop" class="pointer">完成</span></div><div class="mini-scrollbar padding-w10 select-drop-box">' . $options . '</div></div></div>';
|
||||
}
|
||||
|
||||
private static function plate_box(int $current): string {
|
||||
@@ -128,7 +128,7 @@ final class EditView {
|
||||
$options .= '<div data-forum-plate="' . (int) $plate->ID . '" class="pointer but p2-10 mb6' . ((int) $plate->ID === $current ? ' active' : '') . '">' . esc_html($plate->post_title) . '</div>';
|
||||
}
|
||||
$name = $current > 0 ? get_the_title($current) : '请选择';
|
||||
return '<div class="plate-drop drop-select dropdown zib-widget mb10-sm mb20"><div data-toggle-class="open" data-target=".plate-drop" class="flex ac jsb drop-btn"><div class="flex ac"><i class="fa fas fa-cube mr6"></i>版块</div><div class="flex ac"><span name="plate_id" class="em09 muted-2-color text-ellipsis">' . esc_html($name) . '</span><i class="ml6 fa fas fa-angle-right em12"></i></div></div><input type="hidden" name="plate_id" value="' . ($current ?: '') . '"><div class="dropdown-menu fluid"><div class="mini-scrollbar padding-w10 select-drop-box">' . $options . '</div></div></div>';
|
||||
return '<div class="plate-drop drop-select dropdown jio-panel mb10-sm mb20"><div data-toggle-class="open" data-target=".plate-drop" class="flex ac jsb drop-btn"><div class="flex ac"><i class="fa fas fa-cube mr6"></i>版块</div><div class="flex ac"><span name="plate_id" class="em09 muted-2-color text-ellipsis">' . esc_html($name) . '</span><i class="ml6 fa fas fa-angle-right em12"></i></div></div><input type="hidden" name="plate_id" value="' . ($current ?: '') . '"><div class="dropdown-menu fluid"><div class="mini-scrollbar padding-w10 select-drop-box">' . $options . '</div></div></div>';
|
||||
}
|
||||
|
||||
/** @param string[] $selected */
|
||||
@@ -140,7 +140,7 @@ final class EditView {
|
||||
$active = in_array($term->name, $selected, true);
|
||||
$options .= '<label class="but p2-10 mb6 pointer' . ($active ? ' active' : '') . '"><input type="checkbox" data-forum-' . esc_attr($field) . ' value="' . esc_attr($term->name) . '"' . checked($active, true, false) . ' hidden> ' . esc_html($term->name) . '</label>';
|
||||
}
|
||||
return '<div class="' . esc_attr($field) . '-drop drop-select dropdown zib-widget mb10-sm mb20"><div data-toggle-class="open" data-target=".' . esc_attr($field) . '-drop" class="flex ac jsb drop-btn"><div class="flex ac"><i class="fa fas ' . esc_attr($icon) . ' mr6"></i>' . esc_html($label) . '</div><div class="flex ac"><span class="em09 muted-2-color text-ellipsis" data-forum-' . esc_attr($field) . '-label>' . esc_html($selected ? implode('、', array_slice($selected, 0, 2)) : '请选择') . '</span><i class="ml6 fa fas fa-angle-right em12"></i></div></div><input type="hidden" name="' . esc_attr($field) . '" value="' . esc_attr(implode(',', $selected)) . '"><div class="dropdown-menu fluid"><div class="mini-scrollbar padding-w10 select-drop-box">' . $options . '</div></div></div>';
|
||||
return '<div class="' . esc_attr($field) . '-drop drop-select dropdown jio-panel mb10-sm mb20"><div data-toggle-class="open" data-target=".' . esc_attr($field) . '-drop" class="flex ac jsb drop-btn"><div class="flex ac"><i class="fa fas ' . esc_attr($icon) . ' mr6"></i>' . esc_html($label) . '</div><div class="flex ac"><span class="em09 muted-2-color text-ellipsis" data-forum-' . esc_attr($field) . '-label>' . esc_html($selected ? implode('、', array_slice($selected, 0, 2)) : '请选择') . '</span><i class="ml6 fa fas fa-angle-right em12"></i></div></div><input type="hidden" name="' . esc_attr($field) . '" value="' . esc_attr(implode(',', $selected)) . '"><div class="dropdown-menu fluid"><div class="mini-scrollbar padding-w10 select-drop-box">' . $options . '</div></div></div>';
|
||||
}
|
||||
|
||||
private static function type_box(string $current): string {
|
||||
@@ -153,7 +153,7 @@ final class EditView {
|
||||
foreach ($options as $key => $label) {
|
||||
$list .= '<span data-forum-type-set="' . $key . '" class="but p2-10 pointer' . ($key === $current ? ' active' : '') . '">' . esc_html($label) . '</span>';
|
||||
}
|
||||
return '<div class="type-drop zib-widget mb10-sm mb20"><div class="flex ac jsb"><div class="flex ac"><i class="fa fas fa-delicious mr6"></i>发布类型</div><div class="but-average radius em09">' . $list . '</div></div></div>';
|
||||
return '<div class="type-drop jio-panel mb10-sm mb20"><div class="flex ac jsb"><div class="flex ac"><i class="fa fas fa-delicious mr6"></i>发布类型</div><div class="but-average radius em09">' . $list . '</div></div></div>';
|
||||
}
|
||||
|
||||
/** Hidden-content composer: the block becomes a site visibility shortcode on save. */
|
||||
@@ -162,7 +162,7 @@ final class EditView {
|
||||
foreach (['logged' => '登录可见', 'reply' => '评论可见', 'vip1' => '会员可见', 'payshow' => '付费可见'] as $key => $label) {
|
||||
$types .= '<span data-forum-hide-type="' . $key . '" class="mb6 mr6 badg p2-10 pointer' . ($key === 'logged' ? ' active' : '') . '">' . esc_html($label) . '</span>';
|
||||
}
|
||||
return '<div class="hide-type-drop drop-select dropdown zib-widget mb10-sm mb20"><div data-toggle-class="open" data-target=".hide-type-drop" class="flex ac jsb drop-btn"><span class="flex ac"><i class="far fa-eye-slash mr6"></i>隐藏内容</span><i class="ml6 fa fas fa-angle-right em12"></i></div>'
|
||||
return '<div class="hide-type-drop drop-select dropdown jio-panel mb10-sm mb20"><div data-toggle-class="open" data-target=".hide-type-drop" class="flex ac jsb drop-btn"><span class="flex ac"><i class="far fa-eye-slash mr6"></i>隐藏内容</span><i class="ml6 fa fas fa-angle-right em12"></i></div>'
|
||||
. '<input type="hidden" name="hide_type" value="">'
|
||||
. '<div class="dropdown-menu fluid"><div class="mini-scrollbar padding-w10 select-drop-box"><div class="em09 muted-3-color mb10">添加额外的隐藏内容</div><div class="flex hh">' . $types . '</div>'
|
||||
. '<textarea rows="6" name="hide_content" class="form-control input-textarea" placeholder="在此输入需要隐藏的内容"></textarea></div></div></div>';
|
||||
@@ -171,7 +171,7 @@ final class EditView {
|
||||
/** @param string[] $options */
|
||||
private static function vote_box(array $options, ?\WP_Post $post): string {
|
||||
$type = $post ? (string) get_post_meta($post->ID, '_jio_forum_type', true) : 'normal';
|
||||
return '<div class="type-drop zib-widget mb10-sm mb20 forum-type-vote"' . ($type === 'vote' ? '' : ' hidden') . '><div class="mb10"><i class="fa fas fa-poll mr6"></i>投票设置</div>'
|
||||
return '<div class="type-drop jio-panel mb10-sm mb20 forum-type-vote"' . ($type === 'vote' ? '' : ' hidden') . '><div class="mb10"><i class="fa fas fa-poll mr6"></i>投票设置</div>'
|
||||
. '<input class="form-control mb6" name="vote_title" maxlength="60" placeholder="投票标题" value="' . esc_attr($post ? (string) get_post_meta($post->ID, '_jio_forum_vote_title', true) : '') . '">'
|
||||
. '<select class="form-control mb6" name="vote_type"><option value="single">单选</option><option value="multiple">多选</option><option value="pk">双选 PK</option></select>'
|
||||
. '<textarea class="form-control mb6" name="vote_options" rows="4" placeholder="每行一个选项">' . esc_textarea(implode("\n", $options)) . '</textarea>'
|
||||
|
||||
@@ -114,7 +114,7 @@ final class HomeContent {
|
||||
if ($html === '') {
|
||||
$html = jio_get_null('暂时没有版块', 60, 'null.svg', '', 0, 170) . '<div class="text-center mt20">' . self::create_plate_button('but hollow c-blue padding-lg') . '</div>';
|
||||
}
|
||||
return '<div class="ajax-item">' . $html . '</div>';
|
||||
return '<div class="ajax-item">' . $html . '</div><div class="ajax-pag hide"><div class="next-page ajax-next"><a href="#"></a></div></div>';
|
||||
}
|
||||
|
||||
/** @param \WP_Post[] $plates */
|
||||
@@ -171,7 +171,7 @@ final class HomeContent {
|
||||
}
|
||||
if ($page < (int) $query->max_num_pages) {
|
||||
$next = add_query_arg(['index' => $index, 'fpage' => $page + 1], remove_query_arg(['index', 'fpage']));
|
||||
$html .= '<div class="text-center theme-pagination forum-more"><a class="but hollow c-blue" href="' . esc_url($next) . '" data-forum-more>加载更多</a></div>';
|
||||
$html .= '<div class="text-center theme-pagination ajax-pag"><div class="next-page ajax-next"><a href="' . esc_url($next) . '" data-forum-more><i class="fas fa-angle-right"></i>加载更多</a></div></div>';
|
||||
}
|
||||
$html .= '<div class="post_ajax_loader">' . HomeTabs::placeholder('posts', 2) . '</div>';
|
||||
return $html;
|
||||
|
||||
@@ -44,7 +44,7 @@ final class HomeTabs {
|
||||
];
|
||||
}
|
||||
if (Access::is_admin(get_current_user_id())) {
|
||||
$tabs[] = ['title' => '待审核', 'type' => 'pending', 'orderby' => 'date', 'filter' => '', 'style' => 'mini'];
|
||||
$tabs[] = ['title' => '<i class="fa fas fa-check-circle mr3"></i>待审核', 'type' => 'pending', 'orderby' => 'date', 'filter' => '', 'style' => 'mini'];
|
||||
}
|
||||
return $tabs ? array_combine(range(1, count($tabs)), $tabs) : [];
|
||||
}
|
||||
@@ -64,12 +64,12 @@ final class HomeTabs {
|
||||
foreach ($tabs as $index => $tab) {
|
||||
$id = 'home-tab-' . $index;
|
||||
$href = add_query_arg('index', $index, $base);
|
||||
$label = esc_html($tab['title']);
|
||||
$nav .= '<li' . ($index === $active ? ' class="active"' : '') . '><a href="' . esc_url($href) . '" data-forum-tab="#' . $id . '">' . $label . '</a></li>';
|
||||
$panes .= '<div class="forum-tab-pane tab-pane fade' . ($index === $active ? ' in active' : '') . '" id="' . $id . '" data-href="' . esc_url($href) . '">';
|
||||
$nav .= '<li' . ($index === $active ? ' class="active"' : '') . '><a href="' . esc_url($href) . '" data-forum-tab="#' . $id . '">' . $tab['title'] . '</a></li>';
|
||||
$panes .= '<div class="forum-tab-pane ajaxpager tab-pane fade' . ($index === $active ? ' in active' : '') . '" id="' . $id . '" data-href="' . esc_url($href) . '">';
|
||||
if ($index === $active) {
|
||||
$panes .= HomeContent::render($tab, $index);
|
||||
} else {
|
||||
$panes .= '<span class="post_ajax_trigger hide"><a href="' . esc_url($href) . '" class="ajax_load ajax-next ajax-open"></a></span>';
|
||||
$panes .= '<div class="post_ajax_loader">' . self::placeholder($tab['type'] === 'plate' ? 'plate' : 'posts', $tab['type'] === 'plate' ? 2 : 4) . '</div>';
|
||||
}
|
||||
$panes .= '</div>';
|
||||
|
||||
+11
-25
@@ -16,43 +16,29 @@ final class HomeView {
|
||||
echo '<main id="forum" class="jio-forum forum-home">';
|
||||
\Jio\WidgetSystem\WidgetAreas::render('forum_home_top_fluid', 'fluid-widget-wrap');
|
||||
echo '<div class="container"><div class="content-wrap"><div class="content-layout">';
|
||||
echo '<div class="forum-home__main">';
|
||||
HomeTabs::render();
|
||||
echo '</div></div></div>';
|
||||
self::sidebar();
|
||||
echo '</div>';
|
||||
self::sidebar();
|
||||
echo '</div></div>';
|
||||
\Jio\WidgetSystem\WidgetAreas::render('forum_home_bottom_fluid', 'fluid-widget-wrap');
|
||||
if (get_current_user_id() > 0 && (Access::is_admin(get_current_user_id()) || jio_get_setting('jio_forum_user_plates', true))) {
|
||||
self::plate_dialog();
|
||||
}
|
||||
echo '</main>';
|
||||
get_footer();
|
||||
}
|
||||
|
||||
/** Sidebar is widget-only, exactly like the reference home column. */
|
||||
private static function sidebar(): void {
|
||||
$plate_name = (string) jio_get_setting('jio_forum_plate_name', '版块') ?: '版块';
|
||||
echo '<div class="sidebar forum-home__sidebar">';
|
||||
if (is_user_logged_in()) {
|
||||
echo '<div class="jio-widget-box"><a class="but jb-blue btn-block" href="' . esc_url(Core::edit_url()) . '"><i class="fa fas fa-edit mr6"></i>发布' . esc_html((string) jio_get_setting('jio_forum_post_name', '帖子')) . '</a>';
|
||||
if (jio_get_setting('jio_forum_user_plates', true)) {
|
||||
echo '<button type="button" class="but hollow c-blue btn-block mt10" data-forum-open="plate">创建' . esc_html($plate_name) . '</button>';
|
||||
self::plate_dialog();
|
||||
}
|
||||
echo '</div>';
|
||||
} else {
|
||||
echo '<div class="jio-widget-box"><a class="but jb-blue btn-block" href="' . esc_url(jio_get_login_url(Core::edit_url())) . '"><i class="fa fas fa-sign-in-alt mr6"></i>登录后发帖</a></div>';
|
||||
}
|
||||
if (!jio_is_show_sidebar()) return;
|
||||
echo '<div class="sidebar">';
|
||||
\Jio\WidgetSystem\WidgetAreas::render('all_sidebar_top');
|
||||
\Jio\WidgetSystem\WidgetAreas::render('forum_home_sidebar');
|
||||
$plates = get_posts(['post_type' => Core::PLATE, 'post_status' => 'publish', 'posts_per_page' => 8, 'orderby' => 'modified']);
|
||||
if ($plates) {
|
||||
PlateStats::prime(wp_list_pluck($plates, 'ID'));
|
||||
echo '<div class="jio-widget-box"><h4 class="title-theme mb10">热门' . esc_html($plate_name) . '</h4>';
|
||||
foreach ($plates as $plate) {
|
||||
$stats = PlateStats::get($plate->ID);
|
||||
echo '<a class="jio-forum__widget-link" href="' . esc_url(get_permalink($plate)) . '"><span class="text-ellipsis">' . esc_html($plate->post_title) . '</span><span>' . esc_html(jio_cut_count($stats['posts'])) . '</span></a>';
|
||||
}
|
||||
echo '</div>';
|
||||
}
|
||||
\Jio\WidgetSystem\WidgetAreas::render('all_sidebar_bottom');
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
/** Plate creation dialog, triggered by `data-forum-open="plate"` anywhere on the page. */
|
||||
private static function plate_dialog(): void {
|
||||
echo '<dialog class="jio-forum__dialog" data-forum-dialog="plate"><form data-forum-form="plate"><h2>创建版块</h2>'
|
||||
. '<label>名称<input name="title" required maxlength="80"></label>'
|
||||
|
||||
+29
-28
@@ -14,11 +14,9 @@ final class ListingView {
|
||||
return;
|
||||
}
|
||||
self::open($plate->post_title, 'plate', $plate);
|
||||
\Jio\WidgetSystem\WidgetAreas::render('forum_plate_top_fluid');
|
||||
echo '<div class="fixed-wrap"><div class="fixed-wrap-content">';
|
||||
\Jio\WidgetSystem\WidgetAreas::render('forum_plate_top_fluid', 'fluid-widget-wrap');
|
||||
echo Cards::plate_header($plate); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo self::tab_bar($plate); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo '</div></div>';
|
||||
self::close('plate');
|
||||
}
|
||||
|
||||
@@ -31,43 +29,41 @@ final class ListingView {
|
||||
return;
|
||||
}
|
||||
self::open($term->name, 'term', null, $term);
|
||||
\Jio\WidgetSystem\WidgetAreas::render('forum_term_top_fluid');
|
||||
echo '<div class="zib-widget">';
|
||||
\Jio\WidgetSystem\WidgetAreas::render('forum_term_top_fluid', 'fluid-widget-wrap');
|
||||
echo self::term_header($term); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo self::tab_bar(null, $term); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo '</div>';
|
||||
self::close('term');
|
||||
}
|
||||
|
||||
private static function term_header(\WP_Term $term): string {
|
||||
return '<div class="term-main text-center mb20"><h1 class="forum-title em14">' . esc_html($term->name) . '</h1>'
|
||||
. ($term->description !== '' ? '<p class="muted-2-color em09 mt6">' . esc_html($term->description) . '</p>' : '')
|
||||
. '</div>';
|
||||
}
|
||||
|
||||
private static function open(string $title, string $context, ?\WP_Post $plate, ?\WP_Term $term = null): void {
|
||||
echo '<main id="forum" class="jio-forum forum-listing forum-listing--' . esc_attr($context) . '">';
|
||||
echo '<div class="container"><div class="content-wrap"><div class="content-layout">';
|
||||
echo '<div class="jio-forum__list-main">';
|
||||
if ($plate) {
|
||||
$plate_name = (string) jio_get_setting('jio_forum_plate_name', '版块') ?: '版块';
|
||||
echo '<nav class="jio-forum__breadcrumbs" aria-label="路径"><a href="' . esc_url(home_url('/')) . '">首页</a><span>/</span><a href="' . esc_url(Core::home_url()) . '">论坛</a><span>/</span><span>' . esc_html($title !== '' ? $title : $plate_name) . '</span></nav>';
|
||||
} elseif ($term instanceof \WP_Term) {
|
||||
echo '<div class="zib-widget"><div class="box-body notop"><div class="title-theme">' . esc_html($term->name) . '</div></div>';
|
||||
if ($term->description !== '') echo '<p class="muted-2-color em09 padding-w10">' . esc_html($term->description) . '</p>';
|
||||
echo '</div>';
|
||||
}
|
||||
}
|
||||
|
||||
private static function close(string $context): void {
|
||||
echo '</div>';
|
||||
self::sidebar($context);
|
||||
echo '</div></div>';
|
||||
\Jio\WidgetSystem\WidgetAreas::render('forum_' . $context . '_bottom_fluid');
|
||||
\Jio\WidgetSystem\WidgetAreas::render('forum_' . $context . '_bottom_fluid', 'fluid-widget-wrap');
|
||||
echo '</main>';
|
||||
}
|
||||
|
||||
private static function sidebar(string $context): void {
|
||||
if (!jio_is_show_sidebar()) return;
|
||||
echo '<div class="sidebar">';
|
||||
\Jio\WidgetSystem\WidgetAreas::render('all_sidebar_top');
|
||||
\Jio\WidgetSystem\WidgetAreas::render('forum_' . $context . '_sidebar');
|
||||
\Jio\WidgetSystem\WidgetAreas::render('all_sidebar_bottom');
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
/** Plate tab bar + panes; the first tab renders server-side, the rest load by `?plate_tab=N`. */
|
||||
/** Plate tab bar + panes; the active tab renders server-side, the rest load by `?plate_tab=N`. */
|
||||
public static function tab_bar(?\WP_Post $plate = null, ?\WP_Term $term = null): string {
|
||||
$tabs = self::tabs($plate);
|
||||
if (!$tabs) return '';
|
||||
@@ -78,14 +74,17 @@ final class ListingView {
|
||||
foreach ($tabs as $index => $tab) {
|
||||
$id = 'plate-tab-' . $index;
|
||||
$href = add_query_arg('plate_tab', $index, is_string($base) ? $base : Core::home_url());
|
||||
$nav .= '<li' . ($index === $active ? ' class="active"' : '') . '><a href="' . esc_url($href) . '" data-forum-tab="#' . $id . '" data-plate-tab="' . $index . '">' . $tab['title'] . '</a></li>';
|
||||
$panes .= '<div class="forum-tab-pane tab-pane fade' . ($index === $active ? ' in active' : '') . '" id="' . $id . '" data-href="' . esc_url($href) . '">';
|
||||
$panes .= $index === $active
|
||||
? self::pane($tab, $plate, $term, $index)
|
||||
: '<div class="post_ajax_loader">' . HomeTabs::placeholder('posts', 3) . '</div>';
|
||||
$nav .= '<li' . ($index === $active ? ' class="active"' : '') . '><a href="' . esc_url($href) . '" data-forum-tab="#' . $id . '">' . $tab['title'] . '</a></li>';
|
||||
$panes .= '<div class="forum-tab-pane ajaxpager tab-pane fade' . ($index === $active ? ' in active' : '') . '" id="' . $id . '" data-href="' . esc_url($href) . '">';
|
||||
if ($index === $active) {
|
||||
$panes .= self::pane($tab, $plate, $term, $index);
|
||||
} else {
|
||||
$panes .= '<span class="post_ajax_trigger hide"><a href="' . esc_url($href) . '" class="ajax_load ajax-next ajax-open"></a></span>';
|
||||
$panes .= '<div class="post_ajax_loader">' . HomeTabs::placeholder('posts', 3) . '</div>';
|
||||
}
|
||||
$panes .= '</div>';
|
||||
}
|
||||
return '<div class="plate-tab zib-widget"><div class="affix-header-sm" offset-top="7"><ul class="list-inline scroll-x mini-scrollbar tab-nav-theme" role="tablist">' . $nav . '</ul></div><div class="tab-content">' . $panes . '</div></div>';
|
||||
return '<div class="plate-tab jio-panel"><div class="affix-header-sm" offset-top="7"><ul class="list-inline scroll-x mini-scrollbar tab-nav-theme" role="tablist">' . $nav . '</ul></div><div class="tab-content bbs-main-tab-content">' . $panes . '</div></div>';
|
||||
}
|
||||
|
||||
/** @return array<int, array<string, mixed>> */
|
||||
@@ -104,8 +103,9 @@ final class ListingView {
|
||||
}
|
||||
} else {
|
||||
foreach ([
|
||||
['最新发布', 'date', '', 'detail'],
|
||||
['最近回复', 'last_reply', '', 'detail'],
|
||||
['全部', 'modified', '', 'mini'],
|
||||
['推荐', 'popular', '', 'detail'],
|
||||
['最新回复', 'last_reply', '', 'detail'],
|
||||
['热门', 'views', '', 'detail'],
|
||||
['精华', 'modified', 'essence', 'detail'],
|
||||
] as [$title, $orderby, $filter, $style]) {
|
||||
@@ -117,12 +117,13 @@ final class ListingView {
|
||||
$tabs[] = ['title' => '待审核', 'orderby' => 'date', 'filter' => '', 'style' => 'mini', 'status' => 'pending'];
|
||||
$tabs[] = ['title' => '<i class="fa fas fa-trash-alt mr3"></i>回收站', 'orderby' => 'date', 'filter' => '', 'style' => 'mini', 'status' => 'trash'];
|
||||
}
|
||||
return $tabs;
|
||||
// `?plate_tab=N` is 1-based, matching the reference tab numbering.
|
||||
return $tabs ? array_combine(range(1, count($tabs)), $tabs) : [];
|
||||
}
|
||||
|
||||
public static function active_index(int $count): int {
|
||||
$raw = $_GET['plate_tab'] ?? 0;
|
||||
$index = (is_scalar($raw) ? absint($raw) : 0) ?: (int) jio_get_setting('jio_forum_plate_tab_active', 1);
|
||||
$index = (is_scalar($raw) ? absint($raw) : 0) ?: (int) jio_get_setting('jio_forum_plate_tab_active', 2);
|
||||
return $index >= 1 && $index <= $count ? $index : 1;
|
||||
}
|
||||
|
||||
@@ -166,7 +167,7 @@ final class ListingView {
|
||||
$base = $plate instanceof \WP_Post ? get_permalink($plate) : ($term instanceof \WP_Term ? get_term_link($term) : Core::home_url());
|
||||
$next = add_query_arg(['plate_tab' => $index, 'fpage' => $page + 1], is_string($base) ? $base : Core::home_url());
|
||||
if ($page < (int) $query->max_num_pages) {
|
||||
$html .= '<div class="text-center theme-pagination forum-more"><a class="but hollow c-blue" href="' . esc_url($next) . '" data-forum-more>加载更多</a></div>';
|
||||
$html .= '<div class="text-center theme-pagination ajax-pag"><div class="next-page ajax-next"><a href="' . esc_url($next) . '" data-forum-more><i class="fas fa-angle-right"></i>加载更多</a></div></div>';
|
||||
}
|
||||
$html .= '<div class="post_ajax_loader">' . HomeTabs::placeholder('posts', 3) . '</div>';
|
||||
if ($html !== '' && trim(wp_strip_all_tags($html)) !== '') return $html;
|
||||
|
||||
+80
-7
@@ -18,30 +18,103 @@ final class PostView {
|
||||
$can_view = Access::can_view($user_id, $id);
|
||||
|
||||
echo '<main id="forum" class="jio-forum forum-post"><div class="container"><div class="content-wrap"><div class="content-layout">';
|
||||
echo '<div class="fixed-wrap single-wrap"><div class="fixed-wrap-content">';
|
||||
\Jio\WidgetSystem\WidgetAreas::render('forum_post_top_fluid');
|
||||
\Jio\WidgetSystem\WidgetAreas::render('forum_post_top_fluid', 'fluid-widget-wrap');
|
||||
echo '<div class="fixed-wrap single-wrap">';
|
||||
echo self::fixed_actions($post); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo '<div class="fixed-wrap-content">';
|
||||
do_action('bbs_posts_page_content_top');
|
||||
if ($can_view) echo self::cover($post);
|
||||
echo self::breadcrumbs($post);
|
||||
echo '<article id="article" class="article zib-widget forum-article relative">';
|
||||
echo '<article id="article" class="article jio-panel forum-article relative">';
|
||||
echo '<div class="article-header clearfix">' . self::title($post) . self::meta($post) . '</div>';
|
||||
echo self::content($post, $can_view);
|
||||
if ($can_view) echo self::score_box($post);
|
||||
if ($can_view) echo self::author_card($post);
|
||||
echo self::footer($post);
|
||||
echo '</article>';
|
||||
if ($can_view) {
|
||||
self::comments($id);
|
||||
}
|
||||
do_action('bbs_posts_page_content_bottom');
|
||||
\Jio\WidgetSystem\WidgetAreas::render('forum_post_bottom_fluid');
|
||||
echo '</div></div></div>';
|
||||
echo '</div></div>';
|
||||
\Jio\WidgetSystem\WidgetAreas::render('forum_post_bottom_fluid', 'fluid-widget-wrap');
|
||||
echo '</div>';
|
||||
if (jio_is_show_sidebar()) {
|
||||
echo '<div class="sidebar">';
|
||||
\Jio\WidgetSystem\WidgetAreas::render('all_sidebar_top');
|
||||
\Jio\WidgetSystem\WidgetAreas::render('forum_post_sidebar');
|
||||
\Jio\WidgetSystem\WidgetAreas::render('all_sidebar_bottom');
|
||||
echo '</div>';
|
||||
}
|
||||
echo '</div></div></main>';
|
||||
}
|
||||
|
||||
/** Desktop left rail: score group, favorite and share (reference `.single-fixed-btns`). */
|
||||
private static function fixed_actions(\WP_Post $post): string {
|
||||
$id = (int) $post->ID;
|
||||
$user_id = get_current_user_id();
|
||||
$user_score = $user_id > 0 ? (int) get_user_meta($user_id, '_jio_forum_score_' . $id, true) : 0;
|
||||
$html = '<div class="fixed-wrap-nav single-fixed-btns"><div><div class="score-box"><div class="score-btns">';
|
||||
if (jio_get_setting('jio_forum_score_enabled', true)) {
|
||||
$html .= self::score_action($post, 'up', 'extra', $user_score > 0);
|
||||
$html .= '<text>' . esc_html(((int) get_post_meta($id, '_jio_forum_score', true)) ?: '评分') . '</text>';
|
||||
$html .= self::score_action($post, 'down', 'deduct', $user_score < 0);
|
||||
}
|
||||
$html .= '</div></div>';
|
||||
$html .= '<button type="button" class="btn-favorite' . (Access::favorites($user_id, $id) ? ' active' : '') . '" data-forum-action="favorite" data-id="' . $id . '"><i class="far fa-bookmark"></i><text></text></button>';
|
||||
if (function_exists('jio_get_post_share_btn')) $html .= jio_get_post_share_btn($post, 'btn-share', true, true);
|
||||
return $html . '</div></div>';
|
||||
}
|
||||
|
||||
private static function score_action(\WP_Post $post, string $direction, string $kind, bool $active): string {
|
||||
$class = 'btn-score ' . $kind . ($active ? ' active' : '');
|
||||
$icon = '<i class="fa fas fa-' . ($direction === 'up' ? 'plus' : 'minus') . '-circle"></i>';
|
||||
if (!is_user_logged_in()) {
|
||||
return '<a href="' . esc_url(jio_get_login_url(get_permalink($post))) . '" class="' . esc_attr($class . ' signin-loader') . '" data-id="' . (int) $post->ID . '">' . $icon . '</a>';
|
||||
}
|
||||
return '<button type="button" class="' . esc_attr($class) . '" data-forum-action="score" data-direction="' . esc_attr($direction) . '" data-id="' . (int) $post->ID . '">' . $icon . '</button>';
|
||||
}
|
||||
|
||||
/** Article score footer: pill-shaped group with the shared counter. */
|
||||
private static function score_box(\WP_Post $post): string {
|
||||
if (!jio_get_setting('jio_forum_score_enabled', true)) return '';
|
||||
$id = (int) $post->ID;
|
||||
$user_score = get_current_user_id() > 0 ? (int) get_user_meta(get_current_user_id(), '_jio_forum_score_' . $id, true) : 0;
|
||||
$score = (int) get_post_meta($id, '_jio_forum_score', true);
|
||||
return '<div class="score-box single-footer text-center"><div class="score-btns">'
|
||||
. self::score_action($post, 'up', 'extra', $user_score > 0)
|
||||
. '<text>' . esc_html($score ? jio_cut_count($score) : '评分') . '</text>'
|
||||
. self::score_action($post, 'down', 'deduct', $user_score < 0)
|
||||
. '</div><div class="score-box-detail"><div class="desc em09 muted-3-color mt6 mb10">' . ($score ? esc_html(sprintf('%d 人已评分', $score)) : '欢迎为Ta评分') . '</div></div></div>';
|
||||
}
|
||||
|
||||
/** Author card under the article body (reference `.forum-single-author`). */
|
||||
private static function author_card(\WP_Post $post): string {
|
||||
$author = (int) $post->post_author;
|
||||
$user = get_userdata($author);
|
||||
if (!$user) return '';
|
||||
$url = function_exists('jio_get_n') ? jio_get_n($author) : get_author_posts_url($author);
|
||||
$count = (int) count_user_posts($author, Core::POST, true);
|
||||
$followers = (int) get_user_meta($author, '_jio_follow_count', true);
|
||||
$desc = (string) get_user_meta($author, 'description', true);
|
||||
$recent = get_posts(['post_type' => Core::POST, 'post_status' => 'publish', 'author' => $author, 'post__not_in' => [$post->ID], 'posts_per_page' => 6, 'fields' => 'ids']);
|
||||
$links = '';
|
||||
foreach ($recent as $recent_id) {
|
||||
$links .= '<div class="item"><a class="icon-circle text-ellipsis" href="' . esc_url(get_permalink($recent_id)) . '">' . esc_html(get_the_title($recent_id)) . '</a></div>';
|
||||
}
|
||||
$html = '<div class="user-card jio-panel forum-single-author"><div class="card-content mt10 relative flex"><div class="user-content flex xx ac gap20">';
|
||||
$html .= '<div class="user-avatar"><a href="' . esc_url($url) . '">' . Cards::avatar($author, 'avatar-img avatar-lg') . '</a></div>';
|
||||
$html .= '<div class="count-info flex xx gap6"><div class="count-info-item"><a class="muted-color" href="' . esc_url(add_query_arg('tab', 'forum', $url)) . '">' . esc_html(sprintf('%d 篇帖子', $count)) . '</a></div>';
|
||||
$html .= '<div class="count-info-item"><a class="muted-color" href="' . esc_url(add_query_arg('tab', 'follow', $url)) . '">' . esc_html(sprintf('%d 位粉丝', $followers)) . '</a></div></div></div>';
|
||||
$html .= '<div class="user-info flex1"><div class="border-bottom flex jsb at"><div class="ellipsis-box"><div class="user-name">' . (function_exists('jio_get_user_name') ? jio_get_user_name(['id' => $author, 'class' => 'flex1 flex ac']) : '<name class="flex1 flex ac"><a class="display-name text-ellipsis" href="' . esc_url($url) . '">' . esc_html($user->display_name) . '</a></name>') . '</div>';
|
||||
if ($desc !== '') $html .= '<div class="user-desc mt10 muted-2-color">' . esc_html(wp_trim_words($desc, 40)) . '</div>';
|
||||
$html .= '</div>';
|
||||
if (function_exists('jio_get_user_follow')) $html .= jio_get_user_follow('ml10 but c-red follow flex0', $author);
|
||||
$html .= '</div>';
|
||||
if ($links !== '') $html .= '<div class="user-posts mln6 ellipsis-box"><div class="more-posts-mini">' . $links . '</div></div>';
|
||||
return $html . '</div></div></div>';
|
||||
}
|
||||
|
||||
private static function breadcrumbs(\WP_Post $post): string {
|
||||
$plate_id = (int) get_post_meta($post->ID, '_jio_forum_plate_id', true);
|
||||
$icon = '<i class="fa fas fa-map-marker-alt"></i> ';
|
||||
@@ -65,7 +138,7 @@ final class PostView {
|
||||
}
|
||||
|
||||
private static function title(\WP_Post $post): string {
|
||||
return Cards::title($post, 'article-title', '', true);
|
||||
return Cards::title($post, 'article-title', '', true, 'h1');
|
||||
}
|
||||
|
||||
private static function meta(\WP_Post $post): string {
|
||||
@@ -125,7 +198,7 @@ final class PostView {
|
||||
$expired = $deadline > 0 && current_time('timestamp') > $deadline;
|
||||
$display = (string) jio_get_setting('jio_forum_vote_number_type', 'percentage');
|
||||
$voted = get_current_user_id() > 0 && get_user_meta(get_current_user_id(), '_jio_forum_vote_' . $id, true) !== '';
|
||||
$html = '<form class="vote-box forum-vote zib-widget" data-forum-form="vote" data-id="' . $id . '"><h2 class="mb20">' . esc_html((string) get_post_meta($id, '_jio_forum_vote_title', true) ?: '参与投票') . '</h2>';
|
||||
$html = '<form class="vote-box forum-vote jio-panel" data-forum-form="vote" data-id="' . $id . '"><h2 class="mb20">' . esc_html((string) get_post_meta($id, '_jio_forum_vote_title', true) ?: '参与投票') . '</h2>';
|
||||
foreach ($options as $index => $option) {
|
||||
$count = (int) ($counts[$index] ?? 0);
|
||||
$percent = $total > 0 ? (int) round(100 * $count / $total) : 0;
|
||||
|
||||
+14
-17
@@ -8,23 +8,22 @@ final class QuickPost {
|
||||
/** Inline "publish now" box shown on the configured home tab (reference layout). */
|
||||
public static function render(): string {
|
||||
$user_id = get_current_user_id();
|
||||
$post_name = (string) jio_get_setting('jio_forum_post_name', '帖子') ?: '帖子';
|
||||
$plate_name = (string) jio_get_setting('jio_forum_plate_name', '版块') ?: '版块';
|
||||
$topic_name = (string) jio_get_setting('jio_forum_topic_name', '话题') ?: '话题';
|
||||
$plates = get_posts(['post_type' => Core::PLATE, 'post_status' => 'publish', 'posts_per_page' => 200, 'orderby' => 'title', 'order' => 'ASC']);
|
||||
if (!$plates) return '';
|
||||
|
||||
$html = '<form class="quick-posts-box zib-widget mb10-sm mb20" data-forum-form="post"><div class="quick-input-group mb10">';
|
||||
$html = '<form class="quick-posts-box jio-panel mb10-sm mb20" data-forum-form="post"><div class="quick-input-group mb10">';
|
||||
$html .= '<div class="relative edit-posts-title"><textarea class="line-form-input input-lg new-title" name="title" rows="1" maxlength="120" tabindex="1" placeholder="' . esc_attr((string) jio_get_setting('jio_forum_title_placeholder', '请输入标题')) . '"></textarea><i class="line-form-line"></i></div>';
|
||||
$html .= '<div class="relative edit-posts-content"><textarea class="form-control" name="content" tabindex="2" rows="4" placeholder="' . esc_attr((string) jio_get_setting('jio_forum_content_placeholder', '请输入内容')) . '"></textarea></div>';
|
||||
if (jio_get_setting('jio_forum_upload_image', true)) {
|
||||
$html .= '<div class="' . ($user_id ? 'quick-upload' : 'signin-loader') . '"><div class="preview"><div class="add"></div></div><input type="file" accept="image/*" data-forum-file data-kind="image" hidden></div>';
|
||||
}
|
||||
$html .= '<div class="quick-selected-tags"><span name="topics" class="flex ac flex1"></span></div>';
|
||||
$html .= '</div>';
|
||||
|
||||
// More options: plate / topic / access / hidden content
|
||||
// More options: topic / access / hidden content (plate sits in the submit row).
|
||||
$html .= '<div class="flex ac quick-more-btns hh">';
|
||||
$html .= self::plate_dropdown($plates, $plate_name, $user_id);
|
||||
$html .= self::topic_dropdown($topic_name, $user_id);
|
||||
$html .= self::access_dropdown($user_id);
|
||||
if ($user_id) {
|
||||
@@ -32,8 +31,7 @@ final class QuickPost {
|
||||
}
|
||||
$html .= '</div>';
|
||||
|
||||
// Submit row + captcha
|
||||
$html .= '<div class="flex ac jsb hh quick-posts-submit mt10">';
|
||||
$html .= '<div class="flex ac jsb hh quick-posts-submit mt10">' . self::plate_dropdown($plates, $plate_name, $user_id) . '<div class="flex ac">';
|
||||
if (function_exists('jio_render_captcha') && function_exists('jio_is_captcha_enabled_for') && jio_is_captcha_enabled_for('forum_post')) {
|
||||
$html .= '<div class="quick-captcha">';
|
||||
ob_start();
|
||||
@@ -41,7 +39,6 @@ final class QuickPost {
|
||||
$html .= (string) ob_get_clean();
|
||||
$html .= '</div>';
|
||||
}
|
||||
$html .= '<div class="flex ac">';
|
||||
if ($user_id) {
|
||||
$html .= '<button type="button" class="but c-green mr6" data-forum-draft tabindex="3">保存</button>';
|
||||
$html .= '<button type="submit" class="but jb-blue" tabindex="4">发布</button>';
|
||||
@@ -49,45 +46,45 @@ final class QuickPost {
|
||||
$html .= '<a class="but jb-blue signin-loader" href="' . esc_url(jio_get_login_url(Core::home_url())) . '">登录后发布</a>';
|
||||
}
|
||||
$html .= '</div></div>';
|
||||
$html .= '<input type="hidden" name="plate_id" value=""><input type="hidden" name="topics" value=""><input type="hidden" name="view_limit" value="all"><input type="hidden" name="hide_type" value="">';
|
||||
$html .= '<input type="hidden" name="view_limit" value="all">';
|
||||
$html .= '<p class="jio-forum__message mt6 muted-2-color" role="status"></p>';
|
||||
return $html . '</form>';
|
||||
}
|
||||
|
||||
/** @param \WP_Post[] $plates */
|
||||
private static function plate_dropdown(array $plates, string $plate_name, int $user_id): string {
|
||||
if ($user_id <= 0) {
|
||||
return '<div class="plate-drop drop-select dropdown mr20 mt10 signin-loader"><div class="flex ac jsb drop-btn"><div class="flex ac jsb but-plate but"><span class="flex ac"><i class="fa fas fa-cube mr6"></i><span>请选择</span>' . esc_html($plate_name) . '</span><i class="ml6 fa fas fa-angle-right em12"></i></div></div></div>';
|
||||
}
|
||||
$options = '';
|
||||
foreach ($plates as $plate) {
|
||||
$options .= '<div data-forum-plate="' . (int) $plate->ID . '" class="pointer but p2-10 mb6">' . esc_html($plate->post_title) . '</div>';
|
||||
}
|
||||
if ($user_id <= 0) {
|
||||
return '<div class="plate-drop signin-loader mr20 mt10"><div class="flex ac jsb drop-btn"><span class="flex ac"><i class="fa fas fa-cube mr6"></i>请选择' . esc_html($plate_name) . '</span><i class="ml6 fa fas fa-angle-right em12"></i></div></div>';
|
||||
}
|
||||
return '<div class="plate-drop drop-select dropdown mr20 mt10"><div data-toggle-class="open" data-target=".plate-drop" class="flex ac jsb drop-btn"><span class="flex ac" name="plate_id"><i class="fa fas fa-cube mr6"></i><span>请选择' . esc_html($plate_name) . '</span></span><i class="ml6 fa fas fa-angle-right em12"></i></div><div class="dropdown-menu fluid"><div class="mini-scrollbar padding-w10 select-drop-box">' . $options . '</div></div></div>';
|
||||
return '<div class="plate-drop drop-select dropdown mr20 mt10"><div data-toggle-class="open" data-target=".plate-drop" class="flex ac jsb drop-btn"><div class="flex ac jsb but-plate but"><span class="flex ac" name="plate_id"><i class="fa fas fa-cube mr6"></i><span>请选择</span>' . esc_html($plate_name) . '</span><i class="ml6 fa fas fa-angle-right em12"></i></div></div><div class="dropdown-menu fluid"><div class="mini-scrollbar padding-w10 select-drop-box">' . $options . '</div></div></div>';
|
||||
}
|
||||
|
||||
private static function topic_dropdown(string $topic_name, int $user_id): string {
|
||||
if ($user_id <= 0) {
|
||||
return '<div class="flex ac jsb drop-btn mr20 signin-loader"><i class="fa fas fa-hashtag mr6"></i>' . esc_html($topic_name) . '</div>';
|
||||
return '<div class="flex ac jsb drop-btn mr20 signin-loader"><i class="fa fas fa-hashtag mr3"></i>' . esc_html($topic_name) . '</div>';
|
||||
}
|
||||
$terms = get_terms(['taxonomy' => Core::TOPIC, 'hide_empty' => false, 'number' => 100, 'orderby' => 'count', 'order' => 'DESC']);
|
||||
$options = '<div data-forum-topic-none class="pointer but p2-10 mb6"><i class="fa fas fa-ban mr6"></i>不添加' . esc_html($topic_name) . '</div>';
|
||||
foreach (is_array($terms) ? $terms : [] as $term) {
|
||||
$options .= '<div data-forum-topic="' . esc_attr($term->name) . '" class="pointer but p2-10 mb6">' . esc_html($term->name) . '</div>';
|
||||
}
|
||||
return '<div class="topic-drop drop-select dropdown mr20"><div data-toggle-class="open" data-target=".topic-drop" class="flex ac jsb drop-btn"><span class="flex ac" name="topics"><i class="fa fas fa-hashtag mr6"></i>' . esc_html($topic_name) . '</span><i class="ml6 fa fas fa-angle-right em12"></i></div><div class="dropdown-menu fluid"><div class="mini-scrollbar padding-w10 select-drop-box">' . $options . '</div></div></div>';
|
||||
return '<div class="topic-drop drop-select dropdown mr20"><div data-toggle-class="open" data-target=".topic-drop" class="flex ac jsb drop-btn"><i class="fa fas fa-hashtag mr3"></i>' . esc_html($topic_name) . '</div><input type="hidden" name="topics" value=""><div class="dropdown-menu fluid"><div class="mini-scrollbar padding-w10 select-drop-box">' . $options . '</div></div></div>';
|
||||
}
|
||||
|
||||
private static function access_dropdown(int $user_id): string {
|
||||
$labels = ['all' => '公开', 'login' => '登录后可查看', 'follow' => '关注版块后可查看', 'points' => '支付积分查看', 'pay' => '付费查看'];
|
||||
if ($user_id <= 0) {
|
||||
return '<div class="flex ac jsb drop-btn mr20 signin-loader"><i class="fa far fa-eye mr6"></i><span name="view_limit">公开</span></div>';
|
||||
return '<div class="flex ac jsb drop-btn mr20 signin-loader"><i class="far fa-eye mr3"></i><span name="view_limit">公开</span></div>';
|
||||
}
|
||||
$options = '';
|
||||
foreach ($labels as $key => $label) {
|
||||
$options .= '<div data-forum-view="' . $key . '" class="pointer but p2-10 mb6' . ($key === 'all' ? ' active' : '') . '">' . esc_html($label) . '</div>';
|
||||
}
|
||||
return '<div class="allow-view-drop drop-select dropdown mr20"><div data-toggle-class="open" data-target=".allow-view-drop" class="flex ac jsb drop-btn"><span class="flex ac"><i class="far fa-eye mr6"></i><span name="view_limit">公开</span></span><i class="ml6 fa fas fa-angle-right em12"></i></div><div class="dropdown-menu fluid"><div class="mini-scrollbar padding-w10 select-drop-box">' . $options . '</div></div></div>';
|
||||
return '<div class="allow-view-drop drop-select dropdown mr20"><div data-toggle-class="open" data-target=".allow-view-drop" class="flex ac jsb drop-btn"><i class="far fa-eye mr3"></i><span name="view_limit">公开</span></div><div class="dropdown-menu fluid"><div class="padding-10 flex jsb muted-2-color em09">设置阅读权限<span data-toggle-class="close" data-target=".allow-view-drop" class="pointer">完成</span></div><div class="mini-scrollbar padding-w10 select-drop-box">' . $options . '</div></div></div>';
|
||||
}
|
||||
|
||||
private static function hide_dropdown(): string {
|
||||
@@ -95,6 +92,6 @@ final class QuickPost {
|
||||
foreach (['logged' => '登录可见', 'reply' => '评论可见', 'vip1' => '会员可见', 'payshow' => '付费可见'] as $key => $label) {
|
||||
$items .= '<span data-forum-hide-type="' . $key . '" class="mb6 mr6 badg p2-10 pointer' . ($key === 'logged' ? ' active' : '') . '">' . esc_html($label) . '</span>';
|
||||
}
|
||||
return '<div class="hide-type-drop drop-select dropdown mr20"><div data-toggle-class="open" data-target=".hide-type-drop" class="flex ac jsb drop-btn"><i class="fa far fa-eye-slash mr6"></i><span>隐藏内容</span><i class="ml6 fa fas fa-angle-right em12"></i></div><div class="dropdown-menu fluid"><div class="mini-scrollbar padding-w10 select-drop-box"><div class="em09 muted-3-color mb10">添加额外的隐藏内容</div><div class="flex hh">' . $items . '</div><textarea rows="6" name="hide_content" class="form-control input-textarea" placeholder="在此输入需要隐藏的内容"></textarea></div></div></div>';
|
||||
return '<div class="hide-type-drop drop-select dropdown mr20"><div data-toggle-class="open" data-target=".hide-type-drop" class="flex ac jsb drop-btn"><i class="far fa-eye-slash mr3"></i><span>隐藏内容</span></div><div class="dropdown-menu fluid"><div class="mini-scrollbar padding-w10 select-drop-box"><div class="em09 muted-3-color mb10">添加额外的隐藏内容</div><div class="flex hh">' . $items . '</div><input type="hidden" name="hide_type" value="logged"><textarea rows="6" name="hide_content" class="form-control input-textarea" placeholder="在此输入需要隐藏的内容"></textarea></div></div></div>';
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,7 @@ test('post detail pages use the reference article shell', () => {
|
||||
const post = read('src/Forum/PostView.php')
|
||||
const template = read('templates/pages/page-forum-post.php')
|
||||
assert.match(template, /PostView::render\(\)/)
|
||||
for (const token of ['fixed-wrap single-wrap', 'fixed-wrap-content', 'forum-single-cover', 'breadcrumb', 'id="article"', 'article zib-widget forum-article', 'article-header clearfix', 'forum-article-meta', 'wp-posts-content', 'article-tags', 'forum-article-footer', 'footer-actions', 'vote-box forum-vote', 'comments-card']) {
|
||||
for (const token of ['fixed-wrap single-wrap', 'fixed-wrap-content', 'forum-single-cover', 'breadcrumb', 'id="article"', 'article jio-panel forum-article', 'article-header clearfix', 'forum-article-meta', 'wp-posts-content', 'article-tags', 'forum-article-footer', 'footer-actions', 'vote-box forum-vote', 'comments-card']) {
|
||||
assert.ok(post.includes(token), `post page missing ${token}`)
|
||||
}
|
||||
// Banners, permissions and actions stay server-side.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"generated_at": "2026-11-11T08:37:24+00:00",
|
||||
"generated_at": "2026-11-11T10:06:02+00:00",
|
||||
"errors": [],
|
||||
"warnings": [
|
||||
"customPage tools-update section 'tools/update' not in PHP schema (ok if pure operational page)",
|
||||
|
||||
Reference in new issue
Block a user