Files
wordpress-theme-aksrt/assets/css/frontend/modal-runtime.css
T
kate522 a4af024f32 feat(ban): align ban prompts with the reference theme modals and block page
对照参考主题(Zibll)修正四项偏差,申诉链路从页面整体迁移至弹窗:

- feat(ban): 新增三个 1:1 复刻弹窗(REST /user-ban/{info,appeal,log}-modal):
  查看禁封状态(多彩头 c-gray + 信息行 + 申诉按钮)、禁封申诉(edit-header
  gavel/c-blue + 信息框 + 资料项 data[key] 输入 + 审核中态 + 禁止申诉态)、
  禁封记录(多彩头 c-yellow + 计数 + 逐条卡片);user-ban.js 增加
  data-aksrt-ban-info/appeal/log 委托与 admin-ajax 申诉提交
- feat(ban): 禁封/解封弹窗的「当前用户已有N次禁封记录」静态文案改为可点击
  黄链(N>1),打开禁封记录弹窗;解封视图信息行改复用统一数据源
- refactor(ban): 治理展示态收敛至 Restriction::state_badges()(封号=c-red
  违规已封号 / 小黑屋=c-yellow 小黑屋禁封中 / 禁言=c-gray 禁言中,颜色与
  字段统一管理)+ get_ban_info()(状态/起止时间/原因/说明/申诉权限,
  三弹窗与禁封页共用)
- feat(ban): 登录行为对齐参考主题——移除登录期拦截(enforce_login_ban)
  与 complete_login 禁封闸门,封号用户可正常登录;新增 template_redirect
  前台禁封页(1:1 zib_user_ban_restrict_login/zib_die_page:红盒提示 +
  信息行 + 申诉权限 + 退出登录/申诉按钮,模板 templates/parts/user/ban-block.php)
- feat(profile): 公开主页禁封状态从资料卡下方提示框改为占据身份行元信息位
  的 badg 徽章(参考主题 author_header_identity 语义);用户中心元信息改为
  but 按钮(徽章+箭头)打开查看禁封状态弹窗;评论拒绝态链接同源
- refactor: 移除申诉页面模板(page-ban-appeal.php)及其资产/注册/入队、
  get_profile_notice/profile_notice 链、state_labels/state_notices/
  login_ban_message、UserRuntime 的 public_notice/ban_notice_text 死配置、
  report_settings 死键、无消费方的 aksrt_ban_appeal_status 端点
- feat(ban): BanAppeal::ajax_submit 兼容弹窗 data[key] 表单结构
  (逐项清洗入库,申诉说明取 data['申诉说明'],旧平铺字段保持兼容)
- chore: 重新构建 public.css/public.min.css(三个新弹窗几何与头部样式)
- test: 契约测试重写(徽章元信息位、三弹窗与记录链接、禁封页、允许登录 +
  前台拦截、死代码移除断言),全量 362 项通过
2026-09-22 19:14:02 +08:00

611 lines
17 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Modal runtime + ajax list primitives (shared).
*
* @package AKSRT
*/
/* ---- portal token bridge ----
*
* 弹窗由 runtime portal 到 <body>,因此它位于任何「页面级 token 作用域」之外。
* 典型陷阱:路由样式把语义别名挂在页面上,例如
*
* .aksrt-orders-page { --orders-ink: var(--color-ink, #333); }
*
* 弹窗内部再去 `var(--orders-ink)` 时该变量不存在,整条声明会被静默丢弃——
* 表现为边框消失、次级文字变透明,而不是抛错,排查成本很高。
*
* 因此共享调色板在这里声明:本壳层永远在 portal 内,任何弹窗都能直接消费
* `--modal-*`。路由样式应把自己的局部别名映射到这里,而不是映射到页面级变量。
*/
.aksrt-modal-runtime {
--modal-ink: var(--color-ink, #333333);
--modal-ink-2: var(--color-ink-2, #4e5358);
--modal-muted: var(--color-ink-3, #777777);
--modal-line: var(--color-line-stronger, rgba(50, 50, 50, 0.12));
--modal-line-soft: var(--color-line, rgba(50, 50, 50, 0.06));
--modal-surface: var(--surface-1, #ffffff);
--modal-surface-2: var(--surface-2, #eeeeee);
--modal-surface-3: var(--surface-4, #f8f8f8);
--modal-primary: var(--color-primary, #f04494);
--modal-on-primary: var(--color-on-primary, #ffffff);
--modal-warning: var(--color-warning, #f59e0b);
--modal-success: var(--color-success, #10b981);
--modal-danger: var(--color-danger, #ef4444);
}
/* ---- scroll lock ---- */
html.aksrt-modal-runtime-open,
body.aksrt-modal-runtime-open {
overflow: hidden;
}
/* ---- 对话框宽度类不得作用于壳 ----
触发器沿用参考主题的 data-class 语义(modal-mini/full-sm 等),
但这些类落在 fixed 全屏壳上时,.modal-mini 的 width:400px +
auto 边距会把壳压成居中单列,蒙版随之只覆盖一列。 */
.aksrt-modal-runtime.modal-mini,
.aksrt-modal-runtime.full-sm {
width: auto;
max-width: none;
margin: 0;
}
/* ---- modal runtime shell ---- */
.aksrt-modal-runtime {
position: fixed;
inset: 0;
z-index: 100050;
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
visibility: hidden;
transition: opacity 0.2s ease, visibility 0.2s ease;
pointer-events: none;
}
.aksrt-modal-runtime.is-open {
opacity: 1;
visibility: visible;
pointer-events: auto;
}
.aksrt-modal-runtime__overlay {
position: absolute;
inset: 0;
/* 参考主题 .modal-backdrop 同款:纯黑 50%,无模糊、无色调偏移 */
background: rgba(0, 0, 0, 0.5);
}
.aksrt-modal-runtime__dialog {
position: relative;
z-index: 1;
width: min(440px, calc(100vw - 32px));
max-height: min(88vh, 720px);
overflow: auto;
background: var(--surface-1, #fff);
border-radius: 16px;
box-shadow: 0 18px 48px rgba(15, 18, 28, 0.22);
transform: translateY(12px) scale(0.98);
transition: transform 0.22s cubic-bezier(0.22, 1, 0.36, 1);
color: var(--color-ink, #1f2937);
}
.aksrt-modal-runtime.is-open .aksrt-modal-runtime__dialog {
transform: translateY(0) scale(1);
}
.aksrt-modal-runtime--bottom {
align-items: flex-end;
}
.aksrt-modal-runtime--bottom .aksrt-modal-runtime__dialog {
width: 100%;
max-width: 100%;
border-radius: 16px 16px 0 0;
max-height: 90vh;
transform: translateY(24px);
}
.aksrt-modal-runtime--bottom.is-open .aksrt-modal-runtime__dialog {
transform: translateY(0);
}
.aksrt-modal-runtime__header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
padding: 16px 18px 0;
}
.aksrt-modal-runtime__title {
margin: 0;
font-size: 17px;
line-height: 1.35;
}
.aksrt-modal-runtime__content {
padding: 18px 18px 16px;
}
.aksrt-modal-runtime__loading,
.aksrt-modal-runtime__error-body {
padding: 28px 8px;
text-align: center;
color: var(--color-ink-2, #6b7280);
font-size: 14px;
}
.aksrt-modal-runtime__skeleton {
display: grid;
gap: 12px;
padding: 8px 2px;
}
.aksrt-modal-runtime__skeleton-line,
.aksrt-modal-runtime__skeleton-block {
display: block;
border-radius: 8px;
background: linear-gradient(90deg, rgba(148, 163, 184, 0.16), rgba(148, 163, 184, 0.3), rgba(148, 163, 184, 0.16));
background-size: 200% 100%;
animation: aksrt-modal-skeleton 1.2s ease-in-out infinite;
}
.aksrt-modal-runtime__skeleton-line {
width: 72%;
height: 12px;
}
.aksrt-modal-runtime__skeleton-line.is-wide {
width: 92%;
height: 18px;
}
.aksrt-modal-runtime__skeleton-line.is-short {
width: 44%;
}
.aksrt-modal-runtime__skeleton-block {
width: 100%;
min-height: 84px;
}
.aksrt-modal-runtime__retry {
cursor: pointer;
}
@keyframes aksrt-modal-skeleton {
0% { background-position: 100% 0; }
100% { background-position: -100% 0; }
}
.aksrt-modal-runtime .touch.border-title,
.aksrt-modal-runtime .border-title {
font-size: 16px;
font-weight: 700;
margin: 0 0 14px;
display: flex;
align-items: baseline;
flex-wrap: wrap;
gap: 6px;
}
.aksrt-modal-runtime .aksrt-modal-runtime__close {
position: absolute;
top: 10px;
right: 10px;
width: 32px;
height: 32px;
border: 0;
border-radius: 999px;
background: transparent;
color: var(--color-ink-3, #9ca3af);
cursor: pointer;
font-size: 18px;
line-height: 1;
}
.aksrt-modal-runtime .but-average.modal-buts,
.aksrt-modal-runtime .modal-buts {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
margin-top: 16px;
}
.aksrt-modal-runtime .but-average.modal-buts .but,
.aksrt-modal-runtime .modal-buts .but,
.aksrt-modal-runtime .modal-buts button {
min-height: 40px;
border-radius: 10px;
border: 1px solid var(--color-line, #e5e7eb);
background: var(--surface-4, #f3f4f6);
color: var(--color-ink, #111);
font-weight: 600;
cursor: pointer;
}
.aksrt-modal-runtime .modal-buts .but.c-blue,
.aksrt-modal-runtime .modal-buts button.c-blue,
.aksrt-modal-runtime .modal-buts .btn-primary {
background: var(--color-primary, #f04494);
border-color: color-mix(in srgb, var(--color-primary, #f04494) 70%, #000 0%);
color: var(--color-on-primary, #fff);
}
/* ---- 签到详情弹窗(参考主题 refresh_modal modal-mini 同构壳) ----
内容为服务端 HTML(modal-colorful-header + modal-body),与参考主题
.modal-dialog.modal-mini 几何 1:1:宽 400px、圆角 var(--main-radius)。 */
.aksrt-modal-runtime.aksrt-checkin-details-modal:not(.aksrt-modal-runtime--bottom) .aksrt-modal-runtime__dialog {
width: min(400px, calc(100vw - 32px));
border-radius: var(--main-radius, 8px);
background: var(--main-bg-color, #fff);
}
.aksrt-modal-runtime.aksrt-checkin-details-modal .aksrt-modal-runtime__content {
padding: 0;
}
.aksrt-modal-runtime.aksrt-checkin-details-modal .aksrt-modal-runtime__skeleton {
padding: 24px 18px;
}
/* ---- ajax list ---- */
.ajaxpager.is-ajax-loading {
position: relative;
min-height: 80px;
}
.ajaxpager .post_ajax_loader,
.ajaxpager .post-ajax-loader {
display: none;
}
.ajaxpager .post_ajax_loader.is-loading,
.ajaxpager .post-ajax-loader.is-loading {
display: block;
}
.ajax-item.is-fading {
opacity: 0.35;
transition: opacity 0.15s ease;
}
/* ---- 举报弹窗(参考主题报告弹窗几何 1:1)----
宽度对齐参考主题 Bootstrap 默认模态(>=768px 600px),圆角/底色走
--main-radius / --main-bg-color;移动端仍由 --bottom 底部抽屉接管。 */
.aksrt-report-modal:not(.aksrt-modal-runtime--bottom) .aksrt-modal-runtime__dialog {
width: min(600px, calc(100vw - 32px));
border-radius: var(--main-radius, 8px);
background: var(--main-bg-color, #fff);
}
/* edit-header:参考主题弹窗头(关闭钮靠右,红色警示徽标 + 标题居左)。 */
.aksrt-report-modal .edit-header {
position: relative;
padding-right: 32px;
}
.aksrt-report-modal .edit-header .close {
position: absolute;
right: 0;
top: 50%;
transform: translateY(-50%);
float: none;
font-size: 20px;
line-height: 1;
cursor: pointer;
background: none;
border: 0;
padding: 2px 6px;
}
/* 原因徽章行:与参考主题一致,徽章可换行且间距走 mr6/mb6 工具类。 */
.aksrt-report-modal .form-but-radio .badg {
cursor: pointer;
user-select: none;
}
/* ---- 禁封用户弹窗(参考主题 set_user_ban 模态框几何 1:1)----
参考主题 zib_get_edit_user_ban_link 未传 data-class → 走 Bootstrap 默认
.modal-dialog(>=768px 宽 600px);data-height=360 → .modal-content 初始
高度 360 后动画至内容高度;mobile-bottom → <769px 底部抽屉。
此处以 min-height:360px 复刻初始高度契约,桌面宽取 600px。 */
.aksrt-user-ban-modal:not(.aksrt-modal-runtime--bottom) .aksrt-modal-runtime__dialog {
width: min(600px, calc(100vw - 32px));
border-radius: var(--main-radius, 8px);
background: var(--main-bg-color, #fff);
}
/* ---- 查看禁封状态 / 禁封申诉 / 禁封记录弹窗(参考主题 modal-mini 几何 1:1)----
参考主题三个链接均传 data_class='modal-mini'(宽 400px)、data-height=240。 */
.aksrt-user-ban-info-modal:not(.aksrt-modal-runtime--bottom) .aksrt-modal-runtime__dialog,
.aksrt-user-ban-appeal-modal:not(.aksrt-modal-runtime--bottom) .aksrt-modal-runtime__dialog,
.aksrt-user-ban-log-modal:not(.aksrt-modal-runtime--bottom) .aksrt-modal-runtime__dialog {
width: min(400px, calc(100vw - 32px));
border-radius: var(--main-radius, 8px);
background: var(--main-bg-color, #fff);
}
.aksrt-user-ban-info-modal .aksrt-modal-runtime__skeleton,
.aksrt-user-ban-appeal-modal .aksrt-modal-runtime__skeleton,
.aksrt-user-ban-log-modal .aksrt-modal-runtime__skeleton {
padding: 24px 18px;
}
.aksrt-user-ban-modal .aksrt-modal-runtime__skeleton {
padding: 24px 18px;
}
/* edit-header:与禁封表单头部同构(关闭钮靠右,红色警示徽标 + 标题居左)。 */
.aksrt-user-ban-modal .edit-header,
.aksrt-user-ban-appeal-modal .edit-header {
position: relative;
padding-right: 32px;
}
.aksrt-user-ban-modal .edit-header .close,
.aksrt-user-ban-appeal-modal .edit-header .close {
position: absolute;
right: 0;
top: 50%;
transform: translateY(-50%);
float: none;
font-size: 20px;
line-height: 1;
cursor: pointer;
background: none;
border: 0;
padding: 2px 6px;
}
/* 解封视图多彩横幅(参考主题 zib_get_modal_colorful_header('c-yellow', ...)):
120px 高绝对定位横幅 + 旋转彩斑,后续表单整体下移 120px。 */
.aksrt-user-ban-modal .modal-colorful-header,
.aksrt-user-ban-modal .colorful-bg,
.aksrt-user-ban-info-modal .modal-colorful-header,
.aksrt-user-ban-info-modal .colorful-bg,
.aksrt-user-ban-log-modal .modal-colorful-header,
.aksrt-user-ban-log-modal .colorful-bg {
position: relative;
overflow: hidden;
color: var(--this-color);
background: var(--this-bg);
background-size: 120%;
}
.aksrt-user-ban-modal .modal-colorful-header,
.aksrt-user-ban-info-modal .modal-colorful-header,
.aksrt-user-ban-log-modal .modal-colorful-header {
position: absolute;
top: 0;
right: 0;
left: 0;
display: flex;
align-items: center;
justify-content: center;
height: 120px;
border-radius: var(--main-radius, 8px) var(--main-radius, 8px) 0 0;
}
.aksrt-user-ban-modal .modal-colorful-header + *,
.aksrt-user-ban-info-modal .modal-colorful-header + *,
.aksrt-user-ban-log-modal .modal-colorful-header + * {
margin-top: 120px;
}
.aksrt-user-ban-modal .modal-colorful-header > .close,
.aksrt-user-ban-info-modal .modal-colorful-header > .close,
.aksrt-user-ban-log-modal .modal-colorful-header > .close {
position: absolute;
top: 10px;
right: 10px;
z-index: 9;
color: var(--this-color);
font-size: 18px;
opacity: 0.6;
}
.aksrt-user-ban-modal .colorful-bg > .colorful-make,
.aksrt-user-ban-modal .colorful-bg > .colorful-make::before,
.aksrt-user-ban-modal .colorful-bg > .colorful-make::after,
.aksrt-user-ban-info-modal .colorful-bg > .colorful-make,
.aksrt-user-ban-info-modal .colorful-bg > .colorful-make::before,
.aksrt-user-ban-info-modal .colorful-bg > .colorful-make::after,
.aksrt-user-ban-log-modal .colorful-bg > .colorful-make,
.aksrt-user-ban-log-modal .colorful-bg > .colorful-make::before,
.aksrt-user-ban-log-modal .colorful-bg > .colorful-make::after {
position: absolute;
color: var(--this-color);
background: var(--this-bg);
border-radius: 100%;
content: '';
}
.aksrt-user-ban-modal .colorful-bg > .colorful-make,
.aksrt-user-ban-info-modal .colorful-bg > .colorful-make,
.aksrt-user-ban-log-modal .colorful-bg > .colorful-make {
top: 60%;
bottom: 0;
width: 323px;
height: 290px;
animation: aksrt-ban-colorful 120s linear infinite;
}
.aksrt-user-ban-modal .colorful-bg > .colorful-make::before,
.aksrt-user-ban-info-modal .colorful-bg > .colorful-make::before,
.aksrt-user-ban-log-modal .colorful-bg > .colorful-make::before {
top: -325px;
right: -558px;
bottom: 0;
width: 677px;
height: 300px;
opacity: 0.6;
transform: rotate(341deg);
}
.aksrt-user-ban-modal .colorful-bg > .colorful-make::after,
.aksrt-user-ban-info-modal .colorful-bg > .colorful-make::after,
.aksrt-user-ban-log-modal .colorful-bg > .colorful-make::after {
top: -170px;
bottom: 0;
left: -262px;
width: 402px;
height: 214px;
opacity: 0.4;
transform: rotate(326deg);
}
.aksrt-user-ban-modal .colorful-bg > .colorful-make + *,
.aksrt-user-ban-info-modal .colorful-bg > .colorful-make + *,
.aksrt-user-ban-log-modal .colorful-bg > .colorful-make + * {
position: relative;
}
/* 单选徽章行(参考主题 .form-but-radio 契约):input 由 main.css 隐藏,
label 可点;选中态由 main.css 的 input:checked + .but-radio 驱动。 */
.aksrt-user-ban-modal .form-but-radio label {
cursor: pointer;
}
.aksrt-user-ban-modal .form-but-radio .but-radio {
user-select: none;
}
/* 开关行(删除全部内容 / 禁止用户申诉):原生 checkbox 隐藏,
视觉态由 main.css 的 input:checked ~ .form-switch 驱动。 */
.aksrt-user-ban-modal .aksrt-user-ban-form label {
user-select: none;
}
@keyframes aksrt-ban-colorful {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* ---- order review modal content ---- */
.order-comment-from .shop-score-box {
display: flex;
align-items: center;
gap: 8px;
min-height: 36px;
}
.order-comment-from .score-title {
width: 4.5em;
flex: 0 0 auto;
font-size: 13px;
color: var(--color-ink-2, #6b7280);
}
.order-comment-from .score-icon {
display: inline-flex;
gap: 4px;
align-items: center;
height: 30px;
}
.order-comment-from .icon-star {
display: inline-flex;
width: 22px;
height: 22px;
color: #d1d5db;
cursor: pointer;
transition: color 0.12s ease, transform 0.12s ease;
}
.order-comment-from .icon-star svg {
width: 22px;
height: 22px;
fill: currentColor;
}
.order-comment-from .icon-star.active,
.order-comment-from .icon-star.hover {
color: #fc7049;
}
.order-comment-from .icon-star.hover {
transform: scale(1.08);
}
.order-comment-from .score-text {
min-width: 3em;
font-size: 13px;
color: var(--color-ink-2, #6b7280);
}
.order-comment-from textarea.form-control {
width: 100%;
border: 1px solid var(--color-line, #e5e7eb);
border-radius: 10px;
padding: 10px 12px;
font-size: 14px;
resize: vertical;
min-height: 96px;
background: var(--surface-1, #fff);
color: var(--color-ink, #111);
}
:is(.order-comment-from, .aksrt-report-modal) .form-upload .preview {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
:is(.order-comment-from, .aksrt-report-modal) .form-upload .preview .add,
:is(.order-comment-from, .aksrt-report-modal) .form-upload .preview .preview-item {
width: 80px;
height: 80px;
border-radius: 10px;
border: 1px dashed var(--color-line, #d1d5db);
background: var(--surface-4, #f9fafb);
position: relative;
overflow: hidden;
cursor: pointer;
}
/* 加号图标不在此重复定义:main.css 已有参考主题原生实现
(.preview .add:before/:after —— 25px 圆角杠,inset:0 + margin:auto 居中)。
此前这里的 left/top:50% + translate 版本与该规则叠加导致过约束,
加号被推到 75%/75% 只剩“L”形,故整体删除、统一走主样式包。 */
:is(.order-comment-from, .aksrt-report-modal) .form-upload .preview .preview-item img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
:is(.order-comment-from, .aksrt-report-modal) .form-upload .preview .preview-item .remove {
position: absolute;
top: 2px;
right: 2px;
width: 20px;
height: 20px;
border: 0;
border-radius: 999px;
background: rgba(0, 0, 0, 0.55);
color: #fff;
font-size: 12px;
line-height: 1;
cursor: pointer;
}
:is(.order-comment-from, .aksrt-report-modal) .form-upload .hide {
display: none !important;
}
.order-comment-from .review-error {
color: #ef4444;
font-size: 13px;
margin-top: 8px;
}
@media (max-width: 768px) {
.aksrt-modal-runtime:not(.aksrt-modal-runtime--bottom) .aksrt-modal-runtime__dialog {
width: calc(100vw - 20px);
}
}