feat(forum): rebuild plate, post and compose pages
Match the reference layouts for the remaining forum routes: plate pages get the blurred header card, moderator row and the affix tab bar with per-tab filtering, topping posts and moderator-only pending/trash tabs; post pages get the article shell with breadcrumbs, cover, meta row, vote box, tag row and footer actions; compose pages get the reference editor plus settings sidebar (submit/draft, status, access, plate, topic, tag, type, vote) with a cover picker. Saving now honours draft state and the featured image through the REST contract. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
eceddb5f7d
commit
5d3358d844
13 files changed
+891
-199
No files matched your search
@@ -181,6 +181,7 @@
|
||||
.forum-posts.detail .avatar-img{--this-size:38px}
|
||||
.lists-imgs.count-3{--img-count:3}
|
||||
.lists-imgs.count-2,.lists-imgs.count-4{--img-count:2}
|
||||
}
|
||||
@media(max-width:480px){
|
||||
#forum .jio-forum__wrap{width:calc(100% - 24px)}
|
||||
#forum h1{font-size:23px}
|
||||
@@ -282,3 +283,88 @@ body.dark-theme .panel.panel-plate,body.dark-theme .plate-lists .plate-item,body
|
||||
.forum-header .count-mates > item + item{padding-left:15px;margin-left:15px}
|
||||
}
|
||||
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}
|
||||
.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-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 .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 .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-post .single-wrap{width:100%}
|
||||
.forum-single-cover{border-radius:var(--main-radius);overflow:hidden}
|
||||
.forum-article{padding:20px 26px}
|
||||
.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)}
|
||||
.forum-article-meta,.forum-article-meta a{color:var(--muted-2-color);font-size:13px}
|
||||
.forum-article-meta .meta-left{display:flex;align-items:center;gap:8px}
|
||||
.forum-article-meta .meta-right{display:flex;align-items:center}
|
||||
.forum-article-meta .item{margin-left:18px;display:inline-flex;align-items:center;color:var(--muted-2-color)}
|
||||
.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}
|
||||
.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 text{font-size:12px}
|
||||
.single-footer .but{font-size:12px;padding:4px 12px}
|
||||
.vote-box.forum-vote{padding:20px 0}
|
||||
.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 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-box.forum-vote button{display:block;margin:16px auto 0}
|
||||
|
||||
/* ── 发帖 / 编辑页 ────────────────────────────────────────────── */
|
||||
.forum-edit .content-layout{margin-right:calc(var(--sidebar-width,311px) + 15px)}
|
||||
.forum-edit .sidebar{float:left;width:var(--sidebar-width,311px);margin-left:calc(0px - var(--sidebar-width,311px))}
|
||||
.forum-edit .editor-main-box{padding:20px 26px}
|
||||
.forum-edit .edit-posts-featured{display:flex;align-items:center;gap:12px}
|
||||
.forum-edit .forum-cover-preview{width:180px;height:101px;border-radius:var(--main-radius);overflow:hidden;background:var(--muted-border-color);display:flex;align-items:center;justify-content:center;color:var(--muted-3-color)}
|
||||
.forum-edit .forum-cover-preview img{width:100%;height:100%;object-fit:cover}
|
||||
.forum-edit .edit-posts-title{position:relative;margin:10px 0 14px}
|
||||
.forum-edit .line-form-input{width:100%;border:0;border-bottom:1px solid var(--main-border-color);background:transparent;font-size:22px;font-weight:600;padding:8px 0;resize:none;overflow:hidden;outline:none;color:var(--key-color)}
|
||||
.forum-edit .line-form-input:focus{border-bottom-color:var(--focus-color)}
|
||||
.forum-edit .line-form-line{display:none}
|
||||
.forum-edit .sidebar .zib-widget{padding:0}
|
||||
.forum-edit .drop-btn{padding:12px 15px;cursor:pointer}
|
||||
.forum-edit .drop-select .dropdown-menu{width:100%;left:0;right:0}
|
||||
.forum-edit .select-drop-box .but{display:block;width:100%;text-align:left;margin-bottom:4px;border-radius:4px}
|
||||
.forum-edit .select-drop-box .but.active{background:var(--focus-color);color:#fff}
|
||||
.forum-edit .type-drop{padding:12px 15px}
|
||||
.forum-edit .type-drop .but.active{--this-bg:var(--focus-color);--this-color:#fff}
|
||||
.forum-edit .forum-type-vote .form-control{width:100%;margin-bottom:6px}
|
||||
.forum-edit .jio-forum__editor-tools .but{font-size:13px}
|
||||
@media (max-width:800px){
|
||||
.forum-edit .content-layout{margin-right:0}
|
||||
.forum-edit .sidebar{width:100%;margin-left:0;margin-top:16px}
|
||||
.forum-edit .editor-main-box{padding:15px}
|
||||
.forum-article{padding:15px}
|
||||
.forum-article .article-title{font-size:20px}
|
||||
.forum-header.blur-header .header-content{padding:20px 15px}
|
||||
.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)}
|
||||
@@ -95,6 +95,93 @@
|
||||
typeSelect?.addEventListener('change', syncType)
|
||||
syncType()
|
||||
|
||||
// 发帖页:下拉式设置项(阅读权限 / 版块 / 话题 / 标签 / 类型)统一走隐藏输入。
|
||||
const syncHidden = (name, value) => {
|
||||
root.querySelectorAll(`input[type="hidden"][name="${name}"]`).forEach((input) => { input.value = value })
|
||||
}
|
||||
const syncTypeBox = () => {
|
||||
const box = root.querySelector('.forum-type-vote')
|
||||
const current = root.querySelector('input[type="hidden"][name="type"]')?.value || 'normal'
|
||||
if (box) box.hidden = current !== 'vote'
|
||||
}
|
||||
root.addEventListener('click', (event) => {
|
||||
const type = event.target.closest('[data-forum-type-set]')
|
||||
if (type) {
|
||||
root.querySelectorAll('[data-forum-type-set]').forEach((item) => item.classList.toggle('active', item === type))
|
||||
syncHidden('type', type.dataset.forumTypeSet)
|
||||
syncTypeBox()
|
||||
return
|
||||
}
|
||||
const view = event.target.closest('[data-forum-view]')
|
||||
if (view) {
|
||||
root.querySelectorAll('[data-forum-view]').forEach((item) => item.classList.toggle('active', item === view))
|
||||
syncHidden('view_limit', view.dataset.forumView)
|
||||
const label = root.querySelector('span[name="view_limit"]')
|
||||
if (label) label.textContent = view.textContent.trim()
|
||||
return
|
||||
}
|
||||
const plate = event.target.closest('[data-forum-plate]')
|
||||
if (plate) {
|
||||
root.querySelectorAll('[data-forum-plate]').forEach((item) => item.classList.toggle('active', item === plate))
|
||||
syncHidden('plate_id', plate.dataset.forumPlate)
|
||||
const label = root.querySelector('span[name="plate_id"]')
|
||||
if (label) label.textContent = plate.textContent.trim()
|
||||
return
|
||||
}
|
||||
const status = event.target.closest('[data-forum-status]')
|
||||
if (status) {
|
||||
root.querySelectorAll('[data-forum-status]').forEach((item) => item.classList.toggle('active', item === status))
|
||||
syncHidden('post_status', status.dataset.forumStatus)
|
||||
return
|
||||
}
|
||||
const pick = event.target.closest('[data-forum-cover-pick]')
|
||||
if (pick) {
|
||||
root.querySelector('[data-forum-cover-file]')?.click()
|
||||
return
|
||||
}
|
||||
const draft = event.target.closest('[data-forum-draft]')
|
||||
if (draft) {
|
||||
const form = draft.closest('[data-forum-form]')
|
||||
if (form) {
|
||||
syncHidden('post_status', 'draft')
|
||||
form.requestSubmit()
|
||||
}
|
||||
}
|
||||
})
|
||||
root.addEventListener('change', (event) => {
|
||||
const term = event.target.closest('[data-forum-topics],[data-forum-tags]')
|
||||
if (term) {
|
||||
const field = term.matches('[data-forum-topics]') ? 'topics' : 'tags'
|
||||
const values = [...root.querySelectorAll(`[data-forum-${field}]:checked`)].map((input) => input.value)
|
||||
syncHidden(field, values.join(','))
|
||||
term.closest('label')?.classList.toggle('active', term.checked)
|
||||
const label = root.querySelector(`[data-forum-${field}-label]`)
|
||||
if (label) label.textContent = values.length ? values.slice(0, 2).join('、') : '请选择'
|
||||
}
|
||||
})
|
||||
root.addEventListener('change', async (event) => {
|
||||
const cover = event.target.closest('[data-forum-cover-file]')
|
||||
if (!cover?.files?.[0]) return
|
||||
const data = new FormData()
|
||||
data.append('file', cover.files[0])
|
||||
try {
|
||||
const response = await fetch(config.api + 'upload/image', { method: 'POST', credentials: 'same-origin', headers: { 'X-WP-Nonce': config.nonce }, body: data })
|
||||
const payload = await response.json()
|
||||
if (!response.ok || !payload.success) throw new Error(payload.message || '上传失败')
|
||||
const preview = root.querySelector('.forum-cover-preview')
|
||||
if (preview) {
|
||||
preview.classList.remove('is-empty')
|
||||
preview.innerHTML = '<img src="' + payload.data.url + '" alt="">'
|
||||
}
|
||||
const hidden = root.querySelector('input[name="featured_image_id"]')
|
||||
if (hidden) hidden.value = payload.data.id || ''
|
||||
} catch (error) {
|
||||
message(cover.closest('.edit-posts-featured') || root, error.message)
|
||||
} finally {
|
||||
cover.value = ''
|
||||
}
|
||||
})
|
||||
|
||||
const insertMedia = (kind, url, name) => {
|
||||
const element = document.createElement(kind === 'image' ? 'img' : kind === 'video' ? 'video' : 'a')
|
||||
if (kind === 'resource') { element.href = url; element.textContent = name || '下载附件' }
|
||||
|
||||
Reference in new issue
Block a user