fix 更多栏目
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
## 目标与口径
|
||||
|
||||
将 AKSRT 小工具系统中 12 个小工具对照 Zibll(仅参考"(新)"模块,忽略一切"旧版即将删除")做全量 1:1 复刻:后台配置项(字段、类型、选项、默认值、依赖、min/max/step、分组小标题)与前端 DOM/样式/状态全部对齐参考主题。已确认口径:
|
||||
- **专题全部移除**:本项目无 topics 分类法,12 个小工具范围内所有"专题限制"字段与 `PostQuery` 的 topics 查询分支一并删除,测试同步更新。
|
||||
- **修正参考源码明显 bug 的文案**(如排序 label 颠倒、最近评论 style 默认值 'card' 不在选项中),数据值与行为保持一致。
|
||||
- **省略 AKSRT 无法支撑的排序选项**(销售价格/积分售价/销售数量),排序值域 = views/like/comment_count/favorite/modified/date/rand。
|
||||
- **新增"搜索式多选+拖拽排序"分类选择字段**(terms 类型)。
|
||||
- 不写双路/迁移;清理被替换的死代码;不做 Docker 视觉验收;不改 37 个 slug 与 REST 路由形态。
|
||||
|
||||
## 复用基础(已核实)
|
||||
|
||||
- 文章 item DOM 契约已在 `inc/helpers/posts-renderer/markup.php`(posts-item/posts-mini/badges/meta,9.0 契约);`main.css` 已含 `.zci-*`、`.zps-*`、`.graphic*` 等 Zibll 同款 CSS(76 处命中);`frontend.css:179-228` 已有 tab/slider 的 Zibll 契约块;runtime `main.js` 已有 `.swiper-scroll`/`.new-swiper` 初始化。复刻 = 补齐缺失部分并对齐 markup,而非从零移植。
|
||||
- 前次复刻先例:tab_posts/slider/buttons/notice 走 `FrontendRenderer` "特殊壳"路径(before_widget + reference_title + 内容自闭环),本次 12 个中需要 Zibll 壳的一并加入该列表。
|
||||
|
||||
## 实施步骤
|
||||
|
||||
### Phase A 基础设施
|
||||
1. `FieldSchema.php`/`FormRenderer.php`:新增 `terms` 字段类型(动态 get_terms 分类选项、搜索过滤、拖拽排序、按选择顺序保存 int 数组;支持 taxonomy 参数以供合作伙伴的链接分类复用);spinner/slider 渲染 `unit` 后缀(此前 unit 是死键)。
|
||||
2. `PostQuery.php`:删除 topics 分支;tabs 段支持 `zibpay_type`(数组,沿用 apply_pay_type 映射 1/2/5/6);orderby 值域与 allowlist 对齐。
|
||||
3. `PostRenderer.php`:分页三态对齐 Zibll —— `''`→隐藏 `.ajax-pag.hide` 占位、`ajax`→"加载更多" `.ajax-pag .next-page.ajax-next`、`number`→`.pagenav.ajax-pag` 数字页码(全部带 `ajaxpager-target=".widget-ajaxpager"` 契约,REST 数据属性保留);`mini_opt` 应用于 posts;热榜从通用分支拆出专用渲染。
|
||||
4. `FrontendRenderer.php`:特殊壳列表加入 `posts, oneline_posts, hot_posts, term_cards, term_aggregation, media_cards, combo_info, partners, recent_comments, posts_toc`。
|
||||
5. `frontend.js`:移植/新增 ①IAS IntersectionObserver 懒加载(列表 `load_mode=ajax` 与加载更多自动触发,替代 Zibll lazysizes ias);②合作伙伴滚动初始化(测量 seed 组宽→克隆→`--zps-duration`,resize 重算,Zibll main.js:4204-4296);③幻灯片组合卡 footer 重算 `--cover-ratio`(widget-slider.php:848-875);④目录树逻辑(section-navs 移植:h1-h4 抓取、排除 `.item-heading`/`.no-nav`、`wznav_{i}`、scrollspy offset 105、>380px 折叠、hash 定位);保持 role=status/aria-busy/reduced-motion a11y 契约。
|
||||
6. `admin.js`/`admin-core.js`/`admin.css`:terms 字段交互(搜索、拖拽排序、选序同步)。
|
||||
|
||||
### Phase B 逐个小工具(schema+render+CSS+JS+空态,均以参考文件为准逐字段移植)
|
||||
|
||||
| # | AKSRT slug | 参考定义(行号) | 要点 |
|
||||
|---|---|---|---|
|
||||
| 1 | posts 文章列表 | widget-posts.php:1881-2006 | load_mode radio(detail/ajax 默认 ajax)、cat(reference_ids)、zibpay_type checkbox、limit_day、orderby、order、style(list/card/mini)+mini_opt、count 4..20 默认 12、paginate radio ''/ajax/number;壳 `widget-main-post mb20 style-X`(mini 加 `zib-widget posts-mini-lists`);删旧 tag_ids/paginate select |
|
||||
| 2 | tab_posts 多栏目文章 | widget-posts.php:2008-2155 | tabs 子字段 title/cat/zibpay_type/limit_day/orderby/order;移除 topics;**删除现有 legacy `post_ajax_trigger` 双路**,翻页三态;mini 骨架含缩略图变体 |
|
||||
| 3 | oneline_posts 横向滚动文章 | widget-posts.php:2157-2234 | cat/zibpay_type/orderby/order/style 默认 card/count;移除 limit_day/paginate/autoplay(参考无);swiper-scroll DOM 已对齐,清 data-autoplay |
|
||||
| 4 | hot_posts 热榜文章 | widget-posts.php:1803-1851 + zib-posts-list.php:769-888 | orderby radio 4 榜单、limit_day、count 默认 6、target_blank;`zib-widget hot-posts`、TOP1 大图+linear-mask+TOP 徽章(jb-red/jb-yellow/b-gray)、行布局与计数文案(人收藏/人点赞/条讨论/人已阅读);删 show_thumbnail/通用样式字段 |
|
||||
| 5 | term_cards 分类图文卡片 | widget-posts.php:1565-1694 + functions.php:1939-2046 | 模块级 obs_animation/animation_repeat(common.animation 关)、terms 选择器、type style-1..4、height_scale、pc_row(1/2/3/4/6/12 默认 2)/m_row、mask_opacity 默认 10、target_blank;`row gutters-5` + `graphic hover-zoom-img` + `--cover-height-scale` + graphic-mask,style-2/3/4 文案差异与 tooltip;新建共享助手 `aksrt_graphic_card()`(inc/helpers),term 分类默认封面回退 |
|
||||
| 6 | term_aggregation → 改名"分类聚合卡片" | widget-posts.php:1696-1801 + zib-category.php:606-751 | 仅分类(去标签/专题):模块级动画、pc_row slider 1..2 默认 2、terms、orderby/order、count 1..20 默认 4、target_blank;移植 `zib-widget term-aggregation`(term-img+img-badge 浏览合计、term-title/meta/更多文章、按 orderby 的行内 meta、--delay 交错);Catalog 名称/描述/共同字段更新;服务端仅 category |
|
||||
| 7 | media_cards 图文视频封面卡片 | widget-more.php:2005-2191 | 模块级动画、pc_row/m_row(1..12,默认 4/2)、mask_opacity、height_scale 默认 30、font_size_pc/m、font_bold、font_color、covers group{image,video,hide,title,link};`widget-graphic-cover` + this-font 变量 + 移动端回退图片;删旧 description/image_dark 卡片字段 |
|
||||
| 8 | slider_media_combo 幻灯片加图文视频卡片 | widget-slider.php:361-887 | 模块级动画;补 5 个 subheading 分组;option 默认值逐项核对(源文件为准);m_layout_type=default 时 m_row=pc_row;clamp 上限 4/6 修正;footer 重算 JS 接入 |
|
||||
| 9 | partners 横向滚动合作伙伴 | widget-more.php:2317-2581 | rows/m_rows 1..6 默认 3、style_type card/logo/chip、card_width/height(依赖)、card_bg/card_radius、speed slider 0.1..10 步 0.1、direction/pause_hover/show_widget_bg/go_link/end_fade、link_type(link 类别多选用 terms 类型 taxonomy=link_category/link_limit/link_orderby/page_links_order)、partners group{title,desc,image,link};zps-* DOM、round-robin 行分配、get_bookmarks 来源、go_link 走 aksrt_go_link、CSS 动画(已有)+JS 初始化 |
|
||||
| 10 | combo_info 复合信息卡片 | widget-more.php:2583-2833 | 模块级动画、pc_row 2/3/4/6 默认 4、m_row 1/2、pc_gap/m_gap(gutters)、card_radius、top_band/top_band_height、go_link、cta_text/cta_color、cards group{title,icon,icon_image,tags 嵌套 group{text,color},desc,link,cta_text,cta_color,band_color auto/7色};zci-* DOM + band auto 循环 + --delay 交错;markup 改挂到已有 `.aksrt-combo-info-card` CSS;删 aksrt-combo-card 死代码 |
|
||||
| 11 | recent_comments 最近评论 | widget-more.php:3315-3363 + zib-comments-list.php:340-407 | limit 1..50 默认 8、outer/outpost、show_source 默认 false、style radio(''简约/style_2 风格2,默认修正为 '');`box-body comment-mini-lists zib-widget` + comment-widget-item(avatar box、昵称+icon-spot 时间、点赞、con-link text-ellipsis-5、style_2 盒装、来源行);复用 inc/helpers/aksrt-comments.php 时间/头像,内容过滤图片→[图片] |
|
||||
| 12 | posts_toc 文章目录树 | widget-more.php:445-532 | 改旧式字段:title 默认"文章目录"、mini_title、in_affix(删 min_headings/collapsed/offset);渲染空占位 `.posts-nav-box[data-title]`;目录构建/scrollspy/折叠全部移入 frontend.js;`.posts-nav-lists` CSS 若缺则从 main.css:4835-4946 补 |
|
||||
|
||||
### Phase C 死代码清理
|
||||
- 删除被替换的渲染分支与 CSS:aksrt-term-cards、aksrt-term-aggregation、aksrt-combo-card、aksrt-widget-partners 旧轨、aksrt-widget-media-cards/comments/toc/pagination/load-more 旧标记、tab_posts legacy trigger、hot_posts 的 show_thumbnail、oneline 的 autoplay;`media_card_fields()` 仍被 knowledge_product 组使用故保留,仅解除 12 个目标对它的引用。
|
||||
|
||||
### Phase D 测试与校验
|
||||
- `tests/widget-system/run.php`:query_contract 移除 topics、加 tab zibpay_type;modern_widget_contract 扩充 12 个的 schema/DOM 断言;保持既有断言全绿。
|
||||
- 新增 `tests/widget-system/zibll-parity-widgets-contract.test.cjs`(node --test 源码 token 契约:每 widget 的字段 id 清单、关键 DOM 类、CSS token、frontend.js 行为、死类负向断言)。
|
||||
- 更新受影响的 zibll-modern-widgets / post-visual / a11y 契约测试(保持 aria-busy、role=status、reduced-motion)。
|
||||
- 重新生成 `tests/fixtures/widget-golden-v1.json`(php tools/generate-widget-golden-fixture.php)并跑 php tools/validate-widget-golden.php(不带 --require-results)。
|
||||
- 验证:`php -l` 全部改动 PHP;`node --test tests/widget-system/` 全量;`composer dump-autoload -o`(优先不新增类,仅改现有文件)。
|
||||
|
||||
### 明确不做
|
||||
不做旧设置迁移与双路渲染;不做真实视觉/Docker 验收;不参考"(旧版即将删除)"模块;不改 37 slug 顺序、REST 路由形态、其他 25 个小工具。
|
||||
|
||||
### 主要参考文件
|
||||
zibll:`inc/widgets/widget-posts.php`、`widget-more.php`、`widget-slider.php`、`inc/functions/{zib-posts-list,zib-category,functions}.php`、`js/section-navs.js`、`js/main.js`、`css/main.css`;AKSRT:`src/WidgetSystem/*`、`inc/helpers/*`、`assets/widgets/*`、`tests/widget-system/*`。
|
||||
@@ -0,0 +1,47 @@
|
||||
# 侧栏空槽/挤压修复(全站,单一决策源)
|
||||
|
||||
## 根因
|
||||
"是否渲染侧栏列"有两套脱节的决策:
|
||||
- **body 布局类**(`site-layout-1/2/3`,决定 CSS 留白)来自 `aksrt_is_show_sidebar_filter()`,但"小工具是否为空"检查只对 `is_single()` 生效(`inc/helpers/template-tags/site-layout.php:150-152`)。
|
||||
- **aside 渲染**各自为政:固定首页 `aksrt_homepage_render_sidebar()` 额外检查小工具(`inc/helpers/homepage/content.php:146-162`),空时整个不渲染;`sidebar.php`(page/search/archive 用)却渲染空列 div("legacy parity")。
|
||||
|
||||
于是"开关开 + 无小工具":首页 body 仍是 `site-layout-2` → `layout.css:156-162` 保留 `margin-right: 侧栏宽+15px` → 主内容挤压、右侧 326px 空槽;其他页面则是空列占位同样挤压。后台关开关的路径本身自洽(layout-1),但因上述不一致,任何"列被保留而无内容"的场景都出现挤压。
|
||||
|
||||
参考 Zibll(`zib-theme.php` 判断 + `sidebar.php:14-16` 早退 + `main.css` 留白只挂 `site-layout-2/3`):判断集中一处,body class 承载几何,渲染与判定同源。AKSRT 骨架已具备,只缺"小工具为空"一维的全局化。
|
||||
|
||||
## 修改
|
||||
|
||||
### 1. `inc/helpers/template-tags/site-layout.php` — 核心(覆盖所有页面)
|
||||
- `aksrt_is_show_sidebar_filter()`:把 `is_single() && !aksrt_has_current_sidebar_widgets()` 提升为无条件 `if (!aksrt_has_current_sidebar_widgets()) { return false; }`(空侧栏列 = 空槽,全部场景折叠为 layout-1;single 既有行为不变,home/category/tag/search/page/日期归档一并对齐)。
|
||||
- `aksrt_resolve_sidebar_id()`:把 `is_home() || is_front_page()` 分支移到 `is_page()` 之前——静态首页目前解析成 `page_sidebar_{id}` 但渲染器输出 `home_sidebar`,判定/渲染不匹配;重排后一致(该函数仅 sidebar.php 与小工具检查两处调用,重排安全)。
|
||||
|
||||
### 2. `inc/helpers/homepage/content.php` — 删双路
|
||||
- 删除 `aksrt_homepage_has_sidebar()`(修复后与 `aksrt_is_show_sidebar()` 完全等价);`aksrt_homepage_render_sidebar()` 守卫直接用 `!aksrt_is_show_sidebar()`。
|
||||
|
||||
### 3. `sidebar.php` — Zibll 式早退
|
||||
- 顶部加 `if (!function_exists('aksrt_is_show_sidebar') || !aksrt_is_show_sidebar()) { return; }`(覆盖 `search.php:126` 的无条件 `get_sidebar()`)。
|
||||
- 删除"Keep the column even if widgets are empty (legacy parity)"注释与空列行为(此后不可能渲染空列:is_show_sidebar 为真 ⇔ 至少一个 zone 有小工具);删除 `elseif ((is_home() || is_front_page()) && ...home_sidebar...)` 死分支与 `$sidebar_id` 兜底。
|
||||
|
||||
### 4. `inc/helpers/aksrt-archive.php` + `category.php` / `tag.php` — 死参数清理
|
||||
- `aksrt_archive_has_sidebar(string $preferred = '', bool $enabled = true)` → `(bool $enabled = true)`(`$preferred` 自注释 "compat only" 后即 unset,死参数);删除 `return !wp_is_mobile();` 死兜底(主题已明确弃用 wp_is_mobile 布局门控,见 site-layout.php:141-143)。
|
||||
- 更新调用点:`category.php:49`、`tag.php:30` 改为 `aksrt_archive_has_sidebar(!empty($archive_settings['show_sidebar']))`。
|
||||
|
||||
### 5. 死类/死代码清理
|
||||
- `single.php:45`:删除无任何 CSS/JS 引用的 `container--no-sidebar` 输出。
|
||||
- `front-page.php:14-29`:删除不可达的 `function_exists('aksrt_homepage_render_layout')` 兜底双路(`inc/bootstrap.php:33` 无条件加载),模板直接 `get_header(); aksrt_homepage_render_layout(); get_footer();`。
|
||||
- `index.php:23-25`:注释"widget activity never changes the body layout after render"与新契约矛盾,更新为单一决策源描述。
|
||||
- 保留:`layout.css:149-153` 的 `content-layout--no-sidebar` compat 规则(go.php/archive-resources.php/page-ban-appeal.php/page-user-home.php 仍在用)。
|
||||
|
||||
### 6. 测试
|
||||
- `tests/widget-system/post-visual-contract.test.cjs:359-367`:更新测试名与 :364 正则为全局检查 `if \(!aksrt_has_current_sidebar_widgets\(\)\) \{\s*return false;`;新增断言钉住:homepage 渲染守卫用 `aksrt_is_show_sidebar()` 且 `aksrt_homepage_has_sidebar` 已不存在、sidebar.php 早退、resolver 中 home 分支先于 page 分支、archive helper 无 `$preferred` 参数。
|
||||
- 运行 `node --test tests/widget-system/`(至少 post-visual-contract)与 `php -l` 全部改动 PHP 文件。
|
||||
|
||||
## 修复后行为矩阵(每场景验证推演)
|
||||
| 状态 | body 类 | aside |
|
||||
|---|---|---|
|
||||
| 开关开 + 有小工具 | layout-2/3 | 渲染,留白匹配 |
|
||||
| 开关开 + 无小工具 | **layout-1** | 不渲染,主内容占满(首页/分类/标签/页面/搜索/归档统一) |
|
||||
| 开关关 | layout-1 | 不渲染 |
|
||||
|
||||
## 不改动
|
||||
SPA schema(`sidebar_home_enabled` 等字段已齐全)、`get_sidebar_config()` 缺省语义、主题的响应式 CSS 隐藏策略(弃用 wp_is_mobile 的既有决定)、single 页既有判定(已被测试钉住,保持原样)。
|
||||
@@ -900,17 +900,11 @@ ul.breadcrumb > li:last-child,
|
||||
* - scale(1.02) thumbnail hover
|
||||
* - Lazy-load animations (blur/fade/scale)
|
||||
* - Full responsive: 1200/991/767/640px breakpoints
|
||||
*
|
||||
* Tab nav / tab panes / sort menu use the legacy class contract
|
||||
* (.index-tab, .ajax-option, .ajaxpager) styled by assets/css/main.css.
|
||||
*/
|
||||
|
||||
/* ================================================================
|
||||
0. ANIMATIONS
|
||||
================================================================ */
|
||||
|
||||
@keyframes aksrt-skeleton-pulse {
|
||||
0%, 100% { opacity: 1; }
|
||||
50% { opacity: 0.4; }
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
1. HOMEPAGE CONTAINER & TYPOGRAPHY
|
||||
================================================================ */
|
||||
@@ -931,10 +925,6 @@ ul.breadcrumb > li:last-child,
|
||||
transition: color 0.2s, background 0.3s, opacity 0.3s, box-shadow 0.3s, transform 0.3s;
|
||||
}
|
||||
|
||||
.aksrt-homepage .aksrt-skeleton {
|
||||
animation: aksrt-skeleton-pulse 1.5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
2. LAYOUT SHELL
|
||||
================================================================ */
|
||||
@@ -949,16 +939,6 @@ ul.breadcrumb > li:last-child,
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.aksrt-homepage__hero {
|
||||
width: 100vw;
|
||||
max-width: 100vw;
|
||||
margin: 0 calc(-50vw + 50%) 24px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__hero .header-components-container {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.aksrt-homepage__shell.content-shell {
|
||||
padding-top: 0;
|
||||
/* 36px + a bit more breathing room before footer */
|
||||
@@ -999,29 +979,6 @@ ul.breadcrumb > li:last-child,
|
||||
display: block;
|
||||
}
|
||||
|
||||
.aksrt-homepage__system-modules {
|
||||
gap: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.aksrt-homepage__content-zone.aksrt-homepage__system-modules {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__content-zone--featured {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__content-zone--operated,
|
||||
.aksrt-homepage__content-zone--mid,
|
||||
.aksrt-homepage__content-zone--supplement {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__content-zone--supplement {
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__content-zone .widget-card:last-child,
|
||||
.aksrt-homepage__aside .widget:last-child,
|
||||
.aksrt-homepage__fluid-zone .widget-fluid:last-child {
|
||||
@@ -1061,269 +1018,9 @@ ul.breadcrumb > li:last-child,
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
4. STREAM CONTAINER
|
||||
4. STREAM TITLE BOX (legacy title-theme / 第N页)
|
||||
================================================================ */
|
||||
|
||||
.aksrt-homepage__stream-header {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
margin-bottom: 10px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.aksrt-homepage__stream-intro {
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__stream-title {
|
||||
margin: 0;
|
||||
color: var(--color-ink);
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.aksrt-homepage__stream-subtitle {
|
||||
margin: 0;
|
||||
color: var(--color-ink-3, #777);
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.aksrt-homepage__stream,
|
||||
.aksrt-homepage__stream.widget-card {
|
||||
overflow: visible;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
5. TABS
|
||||
================================================================ */
|
||||
|
||||
.aksrt-homepage__tabs,
|
||||
.aksrt-homepage__titlebox {
|
||||
margin-bottom: 6px;
|
||||
padding-bottom: 0;
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.aksrt-homepage__tabs.box-body,
|
||||
.aksrt-homepage__titlebox.box-body {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.aksrt-homepage__tabs-sentinel {
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
margin: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.aksrt-homepage__tabs.home-tab-nav-box {
|
||||
position: static;
|
||||
z-index: auto;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.aksrt-homepage__tabs.home-tab-nav-box[data-sticky-tabs="true"] {
|
||||
position: sticky;
|
||||
top: var(--nav-height, 60px);
|
||||
z-index: 995;
|
||||
background: transparent;
|
||||
transition: background-color 0.2s ease,
|
||||
box-shadow 0.2s ease,
|
||||
border-radius 0.2s ease,
|
||||
padding 0.2s ease,
|
||||
margin 0.2s ease,
|
||||
backdrop-filter 0.2s ease,
|
||||
-webkit-backdrop-filter 0.2s ease;
|
||||
}
|
||||
|
||||
.aksrt-homepage__tabs.home-tab-nav-box[data-sticky-tabs="true"].is-stuck,
|
||||
.aksrt-homepage__tabs.home-tab-nav-box[data-sticky-tabs="true"].is-affixed {
|
||||
margin-bottom: 14px;
|
||||
padding: 10px 16px;
|
||||
background: rgba(255, 255, 255, 0.92);
|
||||
border: none;
|
||||
border-radius: var(--radius-2xl, 16px);
|
||||
box-shadow: var(--shadow);
|
||||
backdrop-filter: saturate(1.6) blur(20px);
|
||||
-webkit-backdrop-filter: saturate(1.6) blur(20px);
|
||||
}
|
||||
|
||||
.aksrt-homepage__tabs.home-tab-nav-box[data-sticky-tabs="true"].is-affixed {
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
html.dark .aksrt-homepage__tabs.home-tab-nav-box[data-sticky-tabs="true"].is-stuck,
|
||||
html.dark .aksrt-homepage__tabs.home-tab-nav-box[data-sticky-tabs="true"].is-affixed,
|
||||
html.dark .aksrt-homepage__tabs.home-tab-nav-box[data-sticky-tabs="true"].is-stuck,
|
||||
html.dark .aksrt-homepage__tabs.home-tab-nav-box[data-sticky-tabs="true"].is-affixed {
|
||||
background: rgba(24, 24, 24, 0.82);
|
||||
box-shadow: 0 12px 30px rgba(0, 0, 0, 0.24);
|
||||
}
|
||||
|
||||
.aksrt-homepage__tab-list {
|
||||
list-style: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.aksrt-homepage__admin-link {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.scroll-x {
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.no-scrollbar {
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
.no-scrollbar::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.aksrt-homepage__tab-item {
|
||||
display: inline-flex;
|
||||
flex: 0 0 auto;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border-radius: 20px;
|
||||
font-weight: 500;
|
||||
transition: background 0.2s ease, color 0.2s ease;
|
||||
}
|
||||
|
||||
.aksrt-homepage__tab-button {
|
||||
padding: 6px 14px;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
color: var(--color-ink);
|
||||
font-family: inherit;
|
||||
font-size: 14px;
|
||||
font-weight: inherit;
|
||||
line-height: 1.2;
|
||||
white-space: nowrap;
|
||||
border-radius: inherit;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.aksrt-homepage__tab-button:hover {
|
||||
color: var(--color-primary, var(--color-primary));
|
||||
}
|
||||
|
||||
.aksrt-homepage__tab-item.is-active {
|
||||
background: var(--color-primary, var(--color-primary));
|
||||
}
|
||||
|
||||
.aksrt-homepage__tab-item.is-active .aksrt-homepage__tab-button,
|
||||
.aksrt-homepage__tab-button[aria-selected="true"] {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
6. SORTBAR + VIEW TOGGLE
|
||||
================================================================ */
|
||||
|
||||
.aksrt-homepage__sortbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-bottom: 10px;
|
||||
padding: 0 0 8px;
|
||||
border-bottom: 1px solid var(--color-line, rgba(50, 50, 50, 0.06));
|
||||
color: var(--color-ink-3, #777);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__sortbar-links {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 0;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.aksrt-homepage__sortbar-link {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 0 12px;
|
||||
color: var(--color-ink-3, #777);
|
||||
text-decoration: none;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.aksrt-homepage__sortbar-link:first-child {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.aksrt-homepage__sortbar-link + .aksrt-homepage__sortbar-link::before {
|
||||
content: "\00b7";
|
||||
position: absolute;
|
||||
left: -2px;
|
||||
color: var(--color-ink-4, #b1b1b1);
|
||||
}
|
||||
|
||||
.aksrt-homepage__sortbar-link:hover,
|
||||
.aksrt-homepage__sortbar-link.is-active {
|
||||
color: var(--color-ink);
|
||||
}
|
||||
|
||||
.aksrt-homepage__view-toggle {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
margin-left: auto;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.aksrt-homepage__view-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
color: var(--color-ink-4, #999);
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: color 0.2s, background 0.2s;
|
||||
}
|
||||
|
||||
.aksrt-homepage__view-btn:hover {
|
||||
color: var(--color-ink);
|
||||
background: var(--surface-2, #eee);
|
||||
}
|
||||
|
||||
.aksrt-homepage__view-btn.is-active {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.aksrt-homepage__view-btn svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
fill: currentColor;
|
||||
}
|
||||
|
||||
.title-theme {
|
||||
position: relative;
|
||||
padding-left: 1.2em;
|
||||
@@ -1344,54 +1041,6 @@ html.dark .aksrt-homepage__tabs.home-tab-nav-box[data-sticky-tabs="true"].is-aff
|
||||
box-shadow: 1px 1px 3px -1px var(--color-primary);
|
||||
}
|
||||
|
||||
.aksrt-homepage__page-indicator {
|
||||
margin-left: 10px;
|
||||
font-size: 80%;
|
||||
font-weight: 400;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.aksrt-homepage__panel[hidden],
|
||||
.index-tab-main .tab-pane[hidden],
|
||||
.home-tab-content .tab-pane[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.aksrt-homepage__panels,
|
||||
.home-tab-content {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.aksrt-homepage__panel {
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.aksrt-homepage__panel.is-active,
|
||||
.aksrt-homepage__panel.active,
|
||||
.aksrt-homepage__panel.fade.in,
|
||||
.aksrt-homepage__panel.tab-pane.active,
|
||||
#index-tab-main.aksrt-homepage__panel,
|
||||
.home-tab-content .tab-pane.is-active,
|
||||
.home-tab-content .tab-pane.show,
|
||||
.home-tab-content .tab-pane.active,
|
||||
.aksrt-homepage__panel.show {
|
||||
display: block !important;
|
||||
visibility: visible !important;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
.home-tab-content .tab-pane.fade.is-active,
|
||||
.home-tab-content .tab-pane.fade.show,
|
||||
.home-tab-content .tab-pane.fade.active,
|
||||
#index-tab-main.fade {
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
.aksrt-homepage__panel-contract {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.flex {
|
||||
/* No !important: the site-layout-1 / fluid-widget-wrap wide-mode rule
|
||||
(.posts-item:not(.card) { display: inline-flex }) must out-rank this
|
||||
@@ -1421,47 +1070,9 @@ html.dark .aksrt-homepage__tabs.home-tab-nav-box[data-sticky-tabs="true"].is-aff
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
11. PAGINATION
|
||||
5. PAGINATION
|
||||
================================================================ */
|
||||
|
||||
.aksrt-homepage__panel-footer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 18px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__more,
|
||||
.aksrt-homepage .aksrt-load-more-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 34px;
|
||||
padding: 0 14px;
|
||||
border: 1px solid var(--color-line, rgba(50, 50, 50, 0.06));
|
||||
border-radius: var(--radius, 8px);
|
||||
background: var(--surface-1, #fff);
|
||||
color: var(--color-ink-3, #777);
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
transition: border-color 0.2s ease, color 0.2s ease, background 0.2s ease;
|
||||
}
|
||||
|
||||
.aksrt-homepage__more:hover,
|
||||
.aksrt-homepage .aksrt-load-more-btn:hover {
|
||||
color: var(--color-primary, var(--color-primary));
|
||||
border-color: var(--color-primary, var(--color-primary));
|
||||
box-shadow: none;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.aksrt-homepage .ajax-pagination {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.aksrt-homepage .navigation.pagination .nav-links,
|
||||
.aksrt-homepage .pagination {
|
||||
gap: 0;
|
||||
@@ -1496,7 +1107,7 @@ html.dark .aksrt-homepage__tabs.home-tab-nav-box[data-sticky-tabs="true"].is-aff
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
12. SIDEBAR
|
||||
6. SIDEBAR
|
||||
================================================================ */
|
||||
|
||||
.aksrt-homepage__aside > .aksrt-panel,
|
||||
@@ -1611,189 +1222,3 @@ html.dark .aksrt-homepage__tabs.home-tab-nav-box[data-sticky-tabs="true"].is-aff
|
||||
box-shadow: none;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
13. LOADING & EMPTY STATES
|
||||
================================================================ */
|
||||
|
||||
.aksrt-homepage .aksrt-loading-indicator {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
color: var(--color-ink-3, #777);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__stream .no-results {
|
||||
padding: 32px 16px;
|
||||
text-align: center;
|
||||
color: var(--color-ink-4, #999);
|
||||
}
|
||||
|
||||
/* source: assets/css/frontend/homepage-fixed/ajax-tab-skeleton-placeholder.css */
|
||||
/* AJAX tab skeleton placeholder */
|
||||
.aksrt-homepage__tab-skeleton {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.aksrt-homepage__tab-skeleton-item {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
padding: 20px;
|
||||
background: var(--surface-1, #fff);
|
||||
border: none;
|
||||
border-radius: var(--main-radius, var(--radius, 8px));
|
||||
box-shadow: var(--shadow-sm);
|
||||
animation: aksrt-skeleton-pulse 1.5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.aksrt-homepage__tab-skeleton-thumb {
|
||||
width: 190px;
|
||||
min-width: 190px;
|
||||
height: 133px;
|
||||
background: var(--surface-2, #eee);
|
||||
border-radius: var(--radius, 8px);
|
||||
}
|
||||
|
||||
.aksrt-homepage__tab-skeleton-body {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__tab-skeleton-line {
|
||||
height: 14px;
|
||||
background: var(--surface-2, #eee);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__tab-skeleton-line:first-child {
|
||||
width: 70%;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__tab-skeleton-line:nth-child(2) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.aksrt-homepage__tab-skeleton-line:nth-child(3) {
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
/* source: assets/css/frontend/homepage-fixed/ajax-tab-error-state.css */
|
||||
/* AJAX tab error state */
|
||||
.aksrt-homepage__tab-error {
|
||||
padding: 32px 16px;
|
||||
text-align: center;
|
||||
color: var(--color-ink-4, #999);
|
||||
font-size: 14px;
|
||||
background: var(--surface-1);
|
||||
border: none;
|
||||
border-radius: var(--main-radius, var(--radius, 8px));
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
.aksrt-homepage__tab-retry {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
margin-top: 12px;
|
||||
padding: 8px 16px;
|
||||
border: 1px solid var(--color-line);
|
||||
border-radius: var(--radius-btn, 4px);
|
||||
background: var(--surface-4, #fff);
|
||||
color: var(--color-ink-3, #777);
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
transition: color 0.2s, border-color 0.2s, background 0.2s;
|
||||
}
|
||||
|
||||
.aksrt-homepage__tab-retry:hover {
|
||||
color: var(--color-primary, var(--color-primary));
|
||||
border-color: var(--color-primary, var(--color-primary));
|
||||
background: var(--color-primary-soft);
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
14. RESPONSIVE — TABLET (max-width: 991px)
|
||||
================================================================ */
|
||||
|
||||
@media (max-width: 991.98px) {
|
||||
.aksrt-homepage__shell.content-shell,
|
||||
.aksrt-homepage__fluid-zone.content-shell {
|
||||
padding-top: 16px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
15. RESPONSIVE — MOBILE (max-width: 767px)
|
||||
================================================================ */
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.aksrt-homepage__shell.content-shell {
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
/* Tab skeleton: smaller thumb */
|
||||
.aksrt-homepage__tab-skeleton-thumb {
|
||||
width: 120px;
|
||||
min-width: 120px;
|
||||
height: 84px;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
16. RESPONSIVE — SMALL MOBILE (max-width: 640px)
|
||||
================================================================ */
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.aksrt-homepage__stream-header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__stream-title {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__stream-subtitle {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__tabs,
|
||||
.aksrt-homepage__titlebox {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__admin-link {
|
||||
margin-left: 0;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__tabs.home-tab-nav-box[data-sticky-tabs="true"].is-stuck,
|
||||
.aksrt-homepage__tabs.home-tab-nav-box[data-sticky-tabs="true"].is-affixed {
|
||||
padding: 8px 10px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__sortbar {
|
||||
gap: 10px;
|
||||
margin-bottom: 12px;
|
||||
padding-bottom: 12px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
/* Tab skeleton: adapt */
|
||||
.aksrt-homepage__tab-skeleton-thumb {
|
||||
width: 96px;
|
||||
min-width: 96px;
|
||||
height: 67px;
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
@@ -3924,15 +3924,6 @@ body.site-layout-3 .sidebar,
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.content-stream__footer {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.content-stream__footer > .content-stream__footer-nav,
|
||||
.archive__ajax-wrap > .content-stream__footer-nav {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.content-stream__empty {
|
||||
padding: 28px 24px;
|
||||
border-radius: var(--radius-lg);
|
||||
@@ -6745,17 +6736,6 @@ body.aksrt-body-scroll .aksrt-show-on-scroll {
|
||||
|
||||
/* source: assets/css/frontend/pagination.css */
|
||||
/* ========== 分页 — 对齐 legacy pagination ========== */
|
||||
.content-stream__footer-nav {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.content-stream__footer-nav.aksrt-pagination,
|
||||
.content-stream__footer-nav.aksrt-pagination-ajax,
|
||||
.content-stream__footer .aksrt-pagination,
|
||||
.content-stream__footer .aksrt-pagination-ajax {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.pagination,
|
||||
.aksrt-pagination,
|
||||
.navigation.pagination .nav-links,
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
@@ -1,3 +1 @@
|
||||
@import url("homepage-fixed/base.css");
|
||||
@import url("homepage-fixed/ajax-tab-skeleton-placeholder.css");
|
||||
@import url("homepage-fixed/ajax-tab-error-state.css");
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
/* AJAX tab error state */
|
||||
.aksrt-homepage__tab-error {
|
||||
padding: 32px 16px;
|
||||
text-align: center;
|
||||
color: var(--color-ink-4, #999);
|
||||
font-size: 14px;
|
||||
background: var(--surface-1);
|
||||
border: none;
|
||||
border-radius: var(--main-radius, var(--radius, 8px));
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
.aksrt-homepage__tab-retry {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
margin-top: 12px;
|
||||
padding: 8px 16px;
|
||||
border: 1px solid var(--color-line);
|
||||
border-radius: var(--radius-btn, 4px);
|
||||
background: var(--surface-4, #fff);
|
||||
color: var(--color-ink-3, #777);
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
transition: color 0.2s, border-color 0.2s, background 0.2s;
|
||||
}
|
||||
|
||||
.aksrt-homepage__tab-retry:hover {
|
||||
color: var(--color-primary, var(--color-primary));
|
||||
border-color: var(--color-primary, var(--color-primary));
|
||||
background: var(--color-primary-soft);
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
14. RESPONSIVE — TABLET (max-width: 991px)
|
||||
================================================================ */
|
||||
|
||||
@media (max-width: 991.98px) {
|
||||
.aksrt-homepage__shell.content-shell,
|
||||
.aksrt-homepage__fluid-zone.content-shell {
|
||||
padding-top: 16px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
15. RESPONSIVE — MOBILE (max-width: 767px)
|
||||
================================================================ */
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.aksrt-homepage__shell.content-shell {
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
/* Tab skeleton: smaller thumb */
|
||||
.aksrt-homepage__tab-skeleton-thumb {
|
||||
width: 120px;
|
||||
min-width: 120px;
|
||||
height: 84px;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
16. RESPONSIVE — SMALL MOBILE (max-width: 640px)
|
||||
================================================================ */
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.aksrt-homepage__stream-header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__stream-title {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__stream-subtitle {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__tabs,
|
||||
.aksrt-homepage__titlebox {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__admin-link {
|
||||
margin-left: 0;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__tabs.home-tab-nav-box[data-sticky-tabs="true"].is-stuck,
|
||||
.aksrt-homepage__tabs.home-tab-nav-box[data-sticky-tabs="true"].is-affixed {
|
||||
padding: 8px 10px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__sortbar {
|
||||
gap: 10px;
|
||||
margin-bottom: 12px;
|
||||
padding-bottom: 12px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
/* Tab skeleton: adapt */
|
||||
.aksrt-homepage__tab-skeleton-thumb {
|
||||
width: 96px;
|
||||
min-width: 96px;
|
||||
height: 67px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
/* AJAX tab skeleton placeholder */
|
||||
.aksrt-homepage__tab-skeleton {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.aksrt-homepage__tab-skeleton-item {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
padding: 20px;
|
||||
background: var(--surface-1, #fff);
|
||||
border: none;
|
||||
border-radius: var(--main-radius, var(--radius, 8px));
|
||||
box-shadow: var(--shadow-sm);
|
||||
animation: aksrt-skeleton-pulse 1.5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.aksrt-homepage__tab-skeleton-thumb {
|
||||
width: 190px;
|
||||
min-width: 190px;
|
||||
height: 133px;
|
||||
background: var(--surface-2, #eee);
|
||||
border-radius: var(--radius, 8px);
|
||||
}
|
||||
|
||||
.aksrt-homepage__tab-skeleton-body {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__tab-skeleton-line {
|
||||
height: 14px;
|
||||
background: var(--surface-2, #eee);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__tab-skeleton-line:first-child {
|
||||
width: 70%;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__tab-skeleton-line:nth-child(2) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.aksrt-homepage__tab-skeleton-line:nth-child(3) {
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
@@ -9,17 +9,11 @@
|
||||
* - scale(1.02) thumbnail hover
|
||||
* - Lazy-load animations (blur/fade/scale)
|
||||
* - Full responsive: 1200/991/767/640px breakpoints
|
||||
*
|
||||
* Tab nav / tab panes / sort menu use the legacy class contract
|
||||
* (.index-tab, .ajax-option, .ajaxpager) styled by assets/css/main.css.
|
||||
*/
|
||||
|
||||
/* ================================================================
|
||||
0. ANIMATIONS
|
||||
================================================================ */
|
||||
|
||||
@keyframes aksrt-skeleton-pulse {
|
||||
0%, 100% { opacity: 1; }
|
||||
50% { opacity: 0.4; }
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
1. HOMEPAGE CONTAINER & TYPOGRAPHY
|
||||
================================================================ */
|
||||
@@ -40,10 +34,6 @@
|
||||
transition: color 0.2s, background 0.3s, opacity 0.3s, box-shadow 0.3s, transform 0.3s;
|
||||
}
|
||||
|
||||
.aksrt-homepage .aksrt-skeleton {
|
||||
animation: aksrt-skeleton-pulse 1.5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
2. LAYOUT SHELL
|
||||
================================================================ */
|
||||
@@ -58,16 +48,6 @@
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.aksrt-homepage__hero {
|
||||
width: 100vw;
|
||||
max-width: 100vw;
|
||||
margin: 0 calc(-50vw + 50%) 24px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__hero .header-components-container {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.aksrt-homepage__shell.content-shell {
|
||||
padding-top: 0;
|
||||
/* 36px + a bit more breathing room before footer */
|
||||
@@ -108,29 +88,6 @@
|
||||
display: block;
|
||||
}
|
||||
|
||||
.aksrt-homepage__system-modules {
|
||||
gap: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.aksrt-homepage__content-zone.aksrt-homepage__system-modules {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__content-zone--featured {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__content-zone--operated,
|
||||
.aksrt-homepage__content-zone--mid,
|
||||
.aksrt-homepage__content-zone--supplement {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__content-zone--supplement {
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__content-zone .widget-card:last-child,
|
||||
.aksrt-homepage__aside .widget:last-child,
|
||||
.aksrt-homepage__fluid-zone .widget-fluid:last-child {
|
||||
@@ -170,269 +127,9 @@
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
4. STREAM CONTAINER
|
||||
4. STREAM TITLE BOX (legacy title-theme / 第N页)
|
||||
================================================================ */
|
||||
|
||||
.aksrt-homepage__stream-header {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
margin-bottom: 10px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.aksrt-homepage__stream-intro {
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__stream-title {
|
||||
margin: 0;
|
||||
color: var(--color-ink);
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.aksrt-homepage__stream-subtitle {
|
||||
margin: 0;
|
||||
color: var(--color-ink-3, #777);
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.aksrt-homepage__stream,
|
||||
.aksrt-homepage__stream.widget-card {
|
||||
overflow: visible;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
5. TABS
|
||||
================================================================ */
|
||||
|
||||
.aksrt-homepage__tabs,
|
||||
.aksrt-homepage__titlebox {
|
||||
margin-bottom: 6px;
|
||||
padding-bottom: 0;
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.aksrt-homepage__tabs.box-body,
|
||||
.aksrt-homepage__titlebox.box-body {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.aksrt-homepage__tabs-sentinel {
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
margin: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.aksrt-homepage__tabs.home-tab-nav-box {
|
||||
position: static;
|
||||
z-index: auto;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.aksrt-homepage__tabs.home-tab-nav-box[data-sticky-tabs="true"] {
|
||||
position: sticky;
|
||||
top: var(--nav-height, 60px);
|
||||
z-index: 995;
|
||||
background: transparent;
|
||||
transition: background-color 0.2s ease,
|
||||
box-shadow 0.2s ease,
|
||||
border-radius 0.2s ease,
|
||||
padding 0.2s ease,
|
||||
margin 0.2s ease,
|
||||
backdrop-filter 0.2s ease,
|
||||
-webkit-backdrop-filter 0.2s ease;
|
||||
}
|
||||
|
||||
.aksrt-homepage__tabs.home-tab-nav-box[data-sticky-tabs="true"].is-stuck,
|
||||
.aksrt-homepage__tabs.home-tab-nav-box[data-sticky-tabs="true"].is-affixed {
|
||||
margin-bottom: 14px;
|
||||
padding: 10px 16px;
|
||||
background: rgba(255, 255, 255, 0.92);
|
||||
border: none;
|
||||
border-radius: var(--radius-2xl, 16px);
|
||||
box-shadow: var(--shadow);
|
||||
backdrop-filter: saturate(1.6) blur(20px);
|
||||
-webkit-backdrop-filter: saturate(1.6) blur(20px);
|
||||
}
|
||||
|
||||
.aksrt-homepage__tabs.home-tab-nav-box[data-sticky-tabs="true"].is-affixed {
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
html.dark .aksrt-homepage__tabs.home-tab-nav-box[data-sticky-tabs="true"].is-stuck,
|
||||
html.dark .aksrt-homepage__tabs.home-tab-nav-box[data-sticky-tabs="true"].is-affixed,
|
||||
html.dark .aksrt-homepage__tabs.home-tab-nav-box[data-sticky-tabs="true"].is-stuck,
|
||||
html.dark .aksrt-homepage__tabs.home-tab-nav-box[data-sticky-tabs="true"].is-affixed {
|
||||
background: rgba(24, 24, 24, 0.82);
|
||||
box-shadow: 0 12px 30px rgba(0, 0, 0, 0.24);
|
||||
}
|
||||
|
||||
.aksrt-homepage__tab-list {
|
||||
list-style: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.aksrt-homepage__admin-link {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.scroll-x {
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.no-scrollbar {
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
.no-scrollbar::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.aksrt-homepage__tab-item {
|
||||
display: inline-flex;
|
||||
flex: 0 0 auto;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border-radius: 20px;
|
||||
font-weight: 500;
|
||||
transition: background 0.2s ease, color 0.2s ease;
|
||||
}
|
||||
|
||||
.aksrt-homepage__tab-button {
|
||||
padding: 6px 14px;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
color: var(--color-ink);
|
||||
font-family: inherit;
|
||||
font-size: 14px;
|
||||
font-weight: inherit;
|
||||
line-height: 1.2;
|
||||
white-space: nowrap;
|
||||
border-radius: inherit;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.aksrt-homepage__tab-button:hover {
|
||||
color: var(--color-primary, var(--color-primary));
|
||||
}
|
||||
|
||||
.aksrt-homepage__tab-item.is-active {
|
||||
background: var(--color-primary, var(--color-primary));
|
||||
}
|
||||
|
||||
.aksrt-homepage__tab-item.is-active .aksrt-homepage__tab-button,
|
||||
.aksrt-homepage__tab-button[aria-selected="true"] {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
6. SORTBAR + VIEW TOGGLE
|
||||
================================================================ */
|
||||
|
||||
.aksrt-homepage__sortbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-bottom: 10px;
|
||||
padding: 0 0 8px;
|
||||
border-bottom: 1px solid var(--color-line, rgba(50, 50, 50, 0.06));
|
||||
color: var(--color-ink-3, #777);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__sortbar-links {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 0;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.aksrt-homepage__sortbar-link {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 0 12px;
|
||||
color: var(--color-ink-3, #777);
|
||||
text-decoration: none;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.aksrt-homepage__sortbar-link:first-child {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.aksrt-homepage__sortbar-link + .aksrt-homepage__sortbar-link::before {
|
||||
content: "\00b7";
|
||||
position: absolute;
|
||||
left: -2px;
|
||||
color: var(--color-ink-4, #b1b1b1);
|
||||
}
|
||||
|
||||
.aksrt-homepage__sortbar-link:hover,
|
||||
.aksrt-homepage__sortbar-link.is-active {
|
||||
color: var(--color-ink);
|
||||
}
|
||||
|
||||
.aksrt-homepage__view-toggle {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
margin-left: auto;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.aksrt-homepage__view-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
color: var(--color-ink-4, #999);
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: color 0.2s, background 0.2s;
|
||||
}
|
||||
|
||||
.aksrt-homepage__view-btn:hover {
|
||||
color: var(--color-ink);
|
||||
background: var(--surface-2, #eee);
|
||||
}
|
||||
|
||||
.aksrt-homepage__view-btn.is-active {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.aksrt-homepage__view-btn svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
fill: currentColor;
|
||||
}
|
||||
|
||||
.title-theme {
|
||||
position: relative;
|
||||
padding-left: 1.2em;
|
||||
@@ -453,54 +150,6 @@ html.dark .aksrt-homepage__tabs.home-tab-nav-box[data-sticky-tabs="true"].is-aff
|
||||
box-shadow: 1px 1px 3px -1px var(--color-primary);
|
||||
}
|
||||
|
||||
.aksrt-homepage__page-indicator {
|
||||
margin-left: 10px;
|
||||
font-size: 80%;
|
||||
font-weight: 400;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.aksrt-homepage__panel[hidden],
|
||||
.index-tab-main .tab-pane[hidden],
|
||||
.home-tab-content .tab-pane[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.aksrt-homepage__panels,
|
||||
.home-tab-content {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.aksrt-homepage__panel {
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.aksrt-homepage__panel.is-active,
|
||||
.aksrt-homepage__panel.active,
|
||||
.aksrt-homepage__panel.fade.in,
|
||||
.aksrt-homepage__panel.tab-pane.active,
|
||||
#index-tab-main.aksrt-homepage__panel,
|
||||
.home-tab-content .tab-pane.is-active,
|
||||
.home-tab-content .tab-pane.show,
|
||||
.home-tab-content .tab-pane.active,
|
||||
.aksrt-homepage__panel.show {
|
||||
display: block !important;
|
||||
visibility: visible !important;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
.home-tab-content .tab-pane.fade.is-active,
|
||||
.home-tab-content .tab-pane.fade.show,
|
||||
.home-tab-content .tab-pane.fade.active,
|
||||
#index-tab-main.fade {
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
.aksrt-homepage__panel-contract {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.flex {
|
||||
/* No !important: the site-layout-1 / fluid-widget-wrap wide-mode rule
|
||||
(.posts-item:not(.card) { display: inline-flex }) must out-rank this
|
||||
@@ -530,47 +179,9 @@ html.dark .aksrt-homepage__tabs.home-tab-nav-box[data-sticky-tabs="true"].is-aff
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
11. PAGINATION
|
||||
5. PAGINATION
|
||||
================================================================ */
|
||||
|
||||
.aksrt-homepage__panel-footer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 18px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__more,
|
||||
.aksrt-homepage .aksrt-load-more-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 34px;
|
||||
padding: 0 14px;
|
||||
border: 1px solid var(--color-line, rgba(50, 50, 50, 0.06));
|
||||
border-radius: var(--radius, 8px);
|
||||
background: var(--surface-1, #fff);
|
||||
color: var(--color-ink-3, #777);
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
transition: border-color 0.2s ease, color 0.2s ease, background 0.2s ease;
|
||||
}
|
||||
|
||||
.aksrt-homepage__more:hover,
|
||||
.aksrt-homepage .aksrt-load-more-btn:hover {
|
||||
color: var(--color-primary, var(--color-primary));
|
||||
border-color: var(--color-primary, var(--color-primary));
|
||||
box-shadow: none;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.aksrt-homepage .ajax-pagination {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.aksrt-homepage .navigation.pagination .nav-links,
|
||||
.aksrt-homepage .pagination {
|
||||
gap: 0;
|
||||
@@ -605,7 +216,7 @@ html.dark .aksrt-homepage__tabs.home-tab-nav-box[data-sticky-tabs="true"].is-aff
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
12. SIDEBAR
|
||||
6. SIDEBAR
|
||||
================================================================ */
|
||||
|
||||
.aksrt-homepage__aside > .aksrt-panel,
|
||||
@@ -720,21 +331,3 @@ html.dark .aksrt-homepage__tabs.home-tab-nav-box[data-sticky-tabs="true"].is-aff
|
||||
box-shadow: none;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
13. LOADING & EMPTY STATES
|
||||
================================================================ */
|
||||
|
||||
.aksrt-homepage .aksrt-loading-indicator {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
color: var(--color-ink-3, #777);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__stream .no-results {
|
||||
padding: 32px 16px;
|
||||
text-align: center;
|
||||
color: var(--color-ink-4, #999);
|
||||
}
|
||||
|
||||
@@ -455,15 +455,6 @@ body.site-layout-3 .sidebar,
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.content-stream__footer {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.content-stream__footer > .content-stream__footer-nav,
|
||||
.archive__ajax-wrap > .content-stream__footer-nav {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.content-stream__empty {
|
||||
padding: 28px 24px;
|
||||
border-radius: var(--radius-lg);
|
||||
|
||||
@@ -1,15 +1,4 @@
|
||||
/* ========== 分页 — 对齐 legacy pagination ========== */
|
||||
.content-stream__footer-nav {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.content-stream__footer-nav.aksrt-pagination,
|
||||
.content-stream__footer-nav.aksrt-pagination-ajax,
|
||||
.content-stream__footer .aksrt-pagination,
|
||||
.content-stream__footer .aksrt-pagination-ajax {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.pagination,
|
||||
.aksrt-pagination,
|
||||
.navigation.pagination .nav-links,
|
||||
|
||||
@@ -362,6 +362,9 @@
|
||||
if (link.closest("[data-aksrt-ajax-list='off']")) return;
|
||||
// The canonical pagination engine exclusively owns these controls.
|
||||
if (link.closest("[data-aksrt-pagination], .aksrt-comment-pagination")) return;
|
||||
// 排序菜单与 pane 触发器是 runtime post_ajax 管线(zib_ajax_option_menu /
|
||||
// zib_index_tab 契约)的专属控件,这里不能并行处理造成双请求。
|
||||
if (link.closest(".ajax-option, .post_ajax_trigger")) return;
|
||||
|
||||
var href = link.getAttribute("href") || link.getAttribute("ajax-href") || link.getAttribute("data-aksrt-ajax-url");
|
||||
if (!href && !link.getAttribute("data-aksrt-ajax-url")) return;
|
||||
|
||||
@@ -36,10 +36,12 @@
|
||||
var iasMax = isComment
|
||||
? ((window.aksrtData && typeof aksrtData.commentIasMax !== "undefined") ? parseInt(aksrtData.commentIasMax, 10) : 0)
|
||||
: ((window.aksrtData && typeof aksrtData.iasMax !== "undefined") ? parseInt(aksrtData.iasMax, 10) : 0);
|
||||
var homepagePanel = container.closest("[data-home-tab-panel]");
|
||||
var target = homepagePanel || container.previousElementSibling;
|
||||
if (!homepagePanel && target && target.classList && target.classList.contains("content-stream__footer")) {
|
||||
target = target.previousElementSibling;
|
||||
// legacy 契约:分页容器与列表同处一个 .ajaxpager 内(首页 tab pane、归档流),
|
||||
// 此时追加目标就是列表容器本身,新卡片插到分页控件之前。
|
||||
var listContainer = container.closest(".ajaxpager, .posts-row");
|
||||
var target = container.previousElementSibling;
|
||||
if (listContainer && container.parentNode === listContainer) {
|
||||
target = listContainer;
|
||||
}
|
||||
if (isComment) {
|
||||
var commentList = container.closest("#comment-list, .commentlist, ol.commentlist") ||
|
||||
@@ -165,9 +167,7 @@
|
||||
temp.innerHTML = res.data.html;
|
||||
var newItems = temp.children;
|
||||
while (newItems.length > 0) {
|
||||
if (homepagePanel && container.parentNode === target) {
|
||||
target.insertBefore(newItems[0], container);
|
||||
} else if (container.parentNode === target) {
|
||||
if (container.parentNode === target) {
|
||||
target.insertBefore(newItems[0], container);
|
||||
} else {
|
||||
target.appendChild(newItems[0]);
|
||||
|
||||
@@ -1,688 +0,0 @@
|
||||
/**
|
||||
* Homepage Fixed - Interactive Layer (v2.0 legacy-aligned)
|
||||
*
|
||||
* Unified AJAX protocol for homepage tabs, sort, and pagination.
|
||||
* Uses legacy-style ajaxpager DOM conventions and custom event flow:
|
||||
* post_ajax.before → fetch → post_ajax.ed → aksrt:posts:rendered
|
||||
*
|
||||
* @package AKSRT
|
||||
* @since 4.0.0
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var DEFAULT_SORT = 'modified';
|
||||
var REST_PATH = '/wp-json/aksrt/v1/homepage/tab-posts';
|
||||
|
||||
/* ============================================================
|
||||
* Utilities
|
||||
* ============================================================ */
|
||||
|
||||
function getRenderedPostCount(scope) {
|
||||
if (!scope) return 0;
|
||||
return scope.querySelectorAll('.posts-item, .posts-mini').length;
|
||||
}
|
||||
|
||||
function getHomepagePerPage(panel) {
|
||||
var panelCount = getRenderedPostCount(panel);
|
||||
if (panelCount > 0) return panelCount;
|
||||
|
||||
var configured = window.aksrtData && parseInt(aksrtData.homepagePostsPerPage, 10);
|
||||
if (configured && configured > 0) return configured;
|
||||
|
||||
var latestPanel = document.querySelector('[data-home-tab-panel="latest"]');
|
||||
var latestCount = getRenderedPostCount(latestPanel);
|
||||
return latestCount || 10;
|
||||
}
|
||||
|
||||
function getDefaultSort() {
|
||||
var configured = window.aksrtData && aksrtData.homepageDefaultSort;
|
||||
var allowed = ['modified', 'date', 'views', 'like', 'comment_count', 'favorite', 'rand'];
|
||||
return allowed.indexOf(configured) !== -1 ? configured : DEFAULT_SORT;
|
||||
}
|
||||
|
||||
function getDefaultView() {
|
||||
var panel = document.querySelector('[data-home-tab-panel][data-view]');
|
||||
return panel && panel.getAttribute('data-view') === 'card' ? 'card' : 'list';
|
||||
}
|
||||
|
||||
function isStickyTabsEnabled() {
|
||||
return !(window.aksrtData && aksrtData.homepageStickyTabs === false);
|
||||
}
|
||||
|
||||
function getRestBaseUrl() {
|
||||
var baseUrl = (window.aksrtData && aksrtData.siteUrl) || '/';
|
||||
return baseUrl.replace(/\/?$/, '');
|
||||
}
|
||||
|
||||
function getCurrentSort(stream) {
|
||||
var activeLink = stream ? stream.querySelector('.aksrt-homepage__sortbar-link.is-active, .aksrt-homepage__sortbar-dropdown-item.is-active') : null;
|
||||
return (activeLink && activeLink.getAttribute('data-sort')) || getDefaultSort();
|
||||
}
|
||||
|
||||
|
||||
function setActiveSortLink(sortbar, sort) {
|
||||
var links = sortbar.querySelectorAll('.aksrt-homepage__sortbar-link, .aksrt-homepage__sortbar-dropdown-item');
|
||||
links.forEach(function (link) {
|
||||
link.classList.toggle('is-active', link.getAttribute('data-sort') === sort);
|
||||
});
|
||||
// Update dropdown trigger text to match the active item
|
||||
var activeItem = sortbar.querySelector('.aksrt-homepage__sortbar-dropdown-item[data-sort="' + sort + '"]');
|
||||
var trigger = sortbar.querySelector('[data-sort-dropdown-trigger]');
|
||||
if (activeItem && trigger) {
|
||||
trigger.firstChild.textContent = activeItem.textContent;
|
||||
}
|
||||
}
|
||||
|
||||
function getStreamViewMode(stream) {
|
||||
var panel = getActivePanel(stream);
|
||||
return panel && panel.getAttribute('data-view') === 'card' ? 'card' : 'list';
|
||||
}
|
||||
|
||||
function getActivePanel(stream) {
|
||||
return stream.querySelector('.aksrt-homepage__panel.is-active, .aksrt-homepage__panel:not([hidden])');
|
||||
}
|
||||
|
||||
function getPanelTermId(panel) {
|
||||
if (!panel) return 0;
|
||||
var target = panel.getAttribute('data-home-tab-panel');
|
||||
if (target === 'latest') return 0;
|
||||
var match = target ? target.match(/^term-(\d+)$/) : null;
|
||||
return match ? parseInt(match[1], 10) : 0;
|
||||
}
|
||||
|
||||
function getPanelTabOrderby(panel) {
|
||||
if (!panel) return '';
|
||||
return panel.getAttribute('data-tab-orderby') || '';
|
||||
}
|
||||
|
||||
function buildRestUrl(options) {
|
||||
options = options || {};
|
||||
return getRestBaseUrl() + REST_PATH +
|
||||
'?term_id=' + encodeURIComponent(options.termId || 0) +
|
||||
'&page=' + encodeURIComponent(options.page || 1) +
|
||||
'&per_page=' + encodeURIComponent(options.perPage || 10) +
|
||||
'&sort=' + encodeURIComponent(options.sort || getDefaultSort()) +
|
||||
'&panel=' + encodeURIComponent(options.panel || 'latest') +
|
||||
'&tab_orderby=' + encodeURIComponent(options.tabOrderby || '');
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* legacy-style event dispatching
|
||||
* ============================================================ */
|
||||
|
||||
/**
|
||||
* Dispatch post_ajax.before — fired before AJAX request is sent.
|
||||
* Detail: { termId, page, sort, viewMode, panel, url }
|
||||
*/
|
||||
function dispatchBeforeEvent(container, detail) {
|
||||
try {
|
||||
container.dispatchEvent(new CustomEvent('post_ajax.before', {
|
||||
bubbles: true,
|
||||
detail: detail
|
||||
}));
|
||||
} catch (e) { /* */ }
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch post_ajax.ed — fired after AJAX response is injected.
|
||||
* Detail: { termId, page, sort, viewMode, panel, total, hasMore }
|
||||
*/
|
||||
function dispatchAfterEvent(container, detail) {
|
||||
try {
|
||||
container.dispatchEvent(new CustomEvent('post_ajax.ed', {
|
||||
bubbles: true,
|
||||
detail: detail
|
||||
}));
|
||||
} catch (e) { /* */ }
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch aksrt:posts:rendered — fired after DOM is hydrated (lazyload etc).
|
||||
* Detail: { viewMode, panel }
|
||||
*/
|
||||
function dispatchRenderedEvent(container, detail) {
|
||||
try {
|
||||
container.dispatchEvent(new CustomEvent('aksrt:posts:rendered', {
|
||||
bubbles: true,
|
||||
detail: detail
|
||||
}));
|
||||
} catch (e) { /* */ }
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* Skeleton, lazyload, and hydration
|
||||
* ============================================================ */
|
||||
|
||||
function buildSkeleton(count) {
|
||||
count = count || 3;
|
||||
var wrapper = document.createElement('div');
|
||||
wrapper.className = 'aksrt-homepage__tab-skeleton';
|
||||
for (var i = 0; i < count; i++) {
|
||||
var item = document.createElement('div');
|
||||
item.className = 'aksrt-homepage__tab-skeleton-item';
|
||||
item.innerHTML =
|
||||
'<div class="aksrt-homepage__tab-skeleton-thumb"></div>' +
|
||||
'<div class="aksrt-homepage__tab-skeleton-body">' +
|
||||
'<div class="aksrt-homepage__tab-skeleton-line"></div>' +
|
||||
'<div class="aksrt-homepage__tab-skeleton-line"></div>' +
|
||||
'<div class="aksrt-homepage__tab-skeleton-line"></div>' +
|
||||
'</div>';
|
||||
wrapper.appendChild(item);
|
||||
}
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hydrate a panel after AJAX content injection.
|
||||
* Sets data-view, re-binds lazy images, and dispatches events.
|
||||
*/
|
||||
function notifyPostsRendered(panel, viewMode) {
|
||||
var postsContainer = panel.matches('.aksrt-homepage__posts, .posts-row')
|
||||
? panel
|
||||
: panel.querySelector('.aksrt-homepage__posts, .posts-row');
|
||||
if (postsContainer) {
|
||||
postsContainer.setAttribute('data-view', viewMode || getDefaultView());
|
||||
}
|
||||
|
||||
dispatchRenderedEvent(panel, {
|
||||
viewMode: viewMode || getDefaultView(),
|
||||
panel: panel.getAttribute('data-home-tab-panel') || ''
|
||||
});
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* Unified AJAX panel loader
|
||||
* ============================================================ */
|
||||
|
||||
function renderPanelPager(panel, options, hasMore) {
|
||||
var existing = panel.querySelector('.aksrt-homepage__panel-footer');
|
||||
if (existing) existing.remove();
|
||||
if (!hasMore) return;
|
||||
|
||||
var footer = document.createElement('div');
|
||||
footer.className = 'aksrt-homepage__panel-footer';
|
||||
var button = document.createElement('button');
|
||||
button.type = 'button';
|
||||
button.className = 'aksrt-homepage__more';
|
||||
button.textContent = (window.aksrtData && aksrtData.ajaxTrigger) || '加载更多';
|
||||
button.addEventListener('click', function () {
|
||||
button.disabled = true;
|
||||
button.textContent = (window.aksrtData && aksrtData.ajaxLoading) || '正在加载...';
|
||||
requestHomepagePanel(panel, {
|
||||
termId: options.termId,
|
||||
page: options.page + 1,
|
||||
perPage: options.perPage,
|
||||
sort: options.sort,
|
||||
viewMode: options.viewMode,
|
||||
panel: options.panel,
|
||||
tabOrderby: options.tabOrderby,
|
||||
append: true
|
||||
});
|
||||
});
|
||||
footer.appendChild(button);
|
||||
panel.appendChild(footer);
|
||||
}
|
||||
|
||||
function buildErrorState(panel, requestOptions) {
|
||||
var wrapper = document.createElement('div');
|
||||
wrapper.className = 'aksrt-homepage__tab-error';
|
||||
|
||||
var msg = document.createElement('p');
|
||||
msg.textContent = (window.aksrtData && aksrtData.ajaxLoadError) || '加载失败,请重试';
|
||||
wrapper.appendChild(msg);
|
||||
|
||||
var retry = document.createElement('button');
|
||||
retry.type = 'button';
|
||||
retry.className = 'aksrt-homepage__tab-retry';
|
||||
retry.innerHTML = '<i class="fa fas fa-redo"></i> ' +
|
||||
((window.aksrtData && aksrtData.ajaxRetry) || '重试');
|
||||
retry.addEventListener('click', function () {
|
||||
requestHomepagePanel(panel, requestOptions);
|
||||
});
|
||||
wrapper.appendChild(retry);
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Core AJAX loader. Shared by tab switch, sort change, pagination, and widget tabs.
|
||||
*
|
||||
* Dispatches the full legacy-aligned event lifecycle:
|
||||
* 1. post_ajax.before (before fetch)
|
||||
* 2. [inject HTML]
|
||||
* 3. post_ajax.ed (after inject, before hydrate)
|
||||
* 4. aksrt:posts:rendered (after lazyload rebind)
|
||||
*/
|
||||
function requestHomepagePanel(panel, requestOptions) {
|
||||
var options = {
|
||||
termId: requestOptions.termId || 0,
|
||||
page: requestOptions.page || 1,
|
||||
perPage: requestOptions.perPage || getHomepagePerPage(panel),
|
||||
sort: requestOptions.sort || getDefaultSort(),
|
||||
viewMode: requestOptions.viewMode || getDefaultView(),
|
||||
panel: requestOptions.panel || panel.getAttribute('data-home-tab-panel') || 'latest',
|
||||
tabOrderby: requestOptions.tabOrderby || getPanelTabOrderby(panel) || '',
|
||||
append: requestOptions.append === true
|
||||
};
|
||||
|
||||
var restUrl = buildRestUrl(options);
|
||||
var retryCount = 0;
|
||||
var maxRetries = 1;
|
||||
|
||||
// 1. Pre-request event
|
||||
dispatchBeforeEvent(panel, {
|
||||
termId: options.termId,
|
||||
page: options.page,
|
||||
sort: options.sort,
|
||||
viewMode: options.viewMode,
|
||||
panel: options.panel,
|
||||
url: restUrl
|
||||
});
|
||||
|
||||
// Full refreshes replace the panel; append requests keep existing cards.
|
||||
if (!options.append) {
|
||||
panel.innerHTML = '';
|
||||
panel.appendChild(buildSkeleton(options.perPage > 6 ? 4 : 3));
|
||||
}
|
||||
|
||||
function markLoaded() {
|
||||
panel.dataset.loaded = 'true';
|
||||
panel.dataset.loadedPage = String(options.page);
|
||||
panel.dataset.loadedSort = options.tabOrderby || options.sort;
|
||||
panel.dataset.loadedTermId = String(options.termId);
|
||||
}
|
||||
|
||||
function doFetch() {
|
||||
fetch(restUrl, {
|
||||
method: 'GET',
|
||||
headers: { Accept: 'application/json' },
|
||||
credentials: 'same-origin'
|
||||
})
|
||||
.then(function (response) {
|
||||
if (!response.ok) throw new Error('HTTP ' + response.status);
|
||||
return response.json();
|
||||
})
|
||||
.then(function (data) {
|
||||
if (!options.append) panel.innerHTML = '';
|
||||
markLoaded();
|
||||
|
||||
if (data && data.html) {
|
||||
// 2. Inject or append article nodes without nesting a posts-row wrapper.
|
||||
if (options.append) {
|
||||
var oldFooter = panel.querySelector('.aksrt-homepage__panel-footer');
|
||||
if (oldFooter) oldFooter.remove();
|
||||
var fragment = document.createElement('div');
|
||||
fragment.innerHTML = data.html;
|
||||
while (fragment.firstChild) panel.appendChild(fragment.firstChild);
|
||||
} else {
|
||||
panel.innerHTML = data.html;
|
||||
}
|
||||
renderPanelPager(panel, options, !!data.has_more);
|
||||
|
||||
// 3. Post-inject event
|
||||
dispatchAfterEvent(panel, {
|
||||
termId: options.termId,
|
||||
page: options.page,
|
||||
sort: options.sort,
|
||||
viewMode: options.viewMode,
|
||||
panel: options.panel,
|
||||
total: data.total || 0,
|
||||
hasMore: !!data.has_more
|
||||
});
|
||||
|
||||
// 4. Hydrate + rendered event
|
||||
notifyPostsRendered(panel, options.viewMode);
|
||||
|
||||
// 5. legacy 契约:post_ajax.ed 之后调用全局 auto_fun 重扫新内容
|
||||
if (typeof window.auto_fun === 'function') window.auto_fun();
|
||||
return;
|
||||
}
|
||||
|
||||
// Empty response
|
||||
var empty = document.createElement('div');
|
||||
empty.className = 'no-results';
|
||||
empty.innerHTML = '<p>' + ((window.aksrtData && aksrtData.ajaxEmpty) || '暂无文章') + '</p>';
|
||||
panel.appendChild(empty);
|
||||
|
||||
dispatchAfterEvent(panel, {
|
||||
termId: options.termId,
|
||||
page: options.page,
|
||||
sort: options.sort,
|
||||
viewMode: options.viewMode,
|
||||
panel: options.panel,
|
||||
total: 0,
|
||||
hasMore: false
|
||||
});
|
||||
})
|
||||
.catch(function () {
|
||||
if (retryCount < maxRetries) {
|
||||
retryCount++;
|
||||
window.setTimeout(doFetch, 3000);
|
||||
return;
|
||||
}
|
||||
if (!options.append) panel.innerHTML = '';
|
||||
var failedFooter = panel.querySelector('.aksrt-homepage__panel-footer');
|
||||
if (failedFooter) failedFooter.remove();
|
||||
panel.appendChild(buildErrorState(panel, options));
|
||||
});
|
||||
}
|
||||
|
||||
doFetch();
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* Tab Navigation
|
||||
* ============================================================ */
|
||||
|
||||
function initHomeTabs(scope) {
|
||||
var tablists = (scope || document).querySelectorAll('[data-aksrt-home-tabs]');
|
||||
|
||||
tablists.forEach(function (list, listIndex) {
|
||||
var stream = list.closest('.aksrt-homepage__stream');
|
||||
if (!stream) return;
|
||||
|
||||
var buttons = Array.from(list.querySelectorAll('[data-home-tab-target]'));
|
||||
var panels = Array.from(stream.querySelectorAll('[data-home-tab-panel]'));
|
||||
|
||||
if (buttons.length < 2 || !panels.length) return;
|
||||
|
||||
function getPanel(button) {
|
||||
var target = button.getAttribute('data-home-tab-target');
|
||||
return panels.find(function (p) {
|
||||
return p.getAttribute('data-home-tab-panel') === target;
|
||||
});
|
||||
}
|
||||
|
||||
function activate(button) {
|
||||
var target = button.getAttribute('data-home-tab-target');
|
||||
var panel = getPanel(button);
|
||||
var termId = getPanelTermId(panel);
|
||||
var currentSort = getCurrentSort(stream);
|
||||
var viewMode = getStreamViewMode(stream);
|
||||
var tabOrderby = button.getAttribute('data-tab-orderby') || getPanelTabOrderby(panel) || '';
|
||||
|
||||
// Toggle active state on tab buttons
|
||||
buttons.forEach(function (item) {
|
||||
var isActive = item === button;
|
||||
var itemWrap = item.closest('.aksrt-homepage__tab-item');
|
||||
if (itemWrap) itemWrap.classList.toggle('is-active', isActive);
|
||||
item.setAttribute('aria-selected', isActive ? 'true' : 'false');
|
||||
item.tabIndex = isActive ? 0 : -1;
|
||||
});
|
||||
|
||||
// Toggle active state on panels (ajaxpager convention)
|
||||
panels.forEach(function (tabPanel) {
|
||||
var isActive = tabPanel === panel;
|
||||
tabPanel.classList.toggle('is-active', isActive);
|
||||
if (isActive) {
|
||||
tabPanel.removeAttribute('hidden');
|
||||
tabPanel.setAttribute('aria-hidden', 'false');
|
||||
} else {
|
||||
tabPanel.setAttribute('hidden', '');
|
||||
tabPanel.setAttribute('aria-hidden', 'true');
|
||||
}
|
||||
});
|
||||
|
||||
// Load content if needed (lazy AJAX load like legacy)
|
||||
// For tab panels, the "loaded sort" check uses tabOrderby, not main stream sort
|
||||
var effectiveSort = tabOrderby || currentSort;
|
||||
if (panel && (panel.dataset.loaded !== 'true' || panel.dataset.loadedSort !== effectiveSort)) {
|
||||
requestHomepagePanel(panel, {
|
||||
termId: termId,
|
||||
page: 1,
|
||||
perPage: getHomepagePerPage(panel),
|
||||
sort: currentSort,
|
||||
viewMode: viewMode,
|
||||
panel: target,
|
||||
tabOrderby: tabOrderby
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Set up ARIA relationships
|
||||
buttons.forEach(function (button) {
|
||||
var target = button.getAttribute('data-home-tab-target');
|
||||
var panel = getPanel(button);
|
||||
var buttonId = 'aksrt-home-tab-' + listIndex + '-' + target;
|
||||
|
||||
button.id = button.id || buttonId;
|
||||
if (panel) {
|
||||
panel.id = panel.id || buttonId + '-panel';
|
||||
panel.setAttribute('aria-labelledby', button.id);
|
||||
button.setAttribute('aria-controls', panel.id);
|
||||
// Add ajaxpager class for legacy DOM convention
|
||||
panel.classList.add('ajaxpager');
|
||||
}
|
||||
|
||||
button.addEventListener('click', function () { activate(button); });
|
||||
|
||||
button.addEventListener('keydown', function (event) {
|
||||
if (event.key !== 'ArrowRight' && event.key !== 'ArrowLeft') return;
|
||||
event.preventDefault();
|
||||
var direction = event.key === 'ArrowRight' ? 1 : -1;
|
||||
var currentIndex = buttons.indexOf(button);
|
||||
var nextIndex = (currentIndex + direction + buttons.length) % buttons.length;
|
||||
var nextButton = buttons[nextIndex];
|
||||
if (nextButton) {
|
||||
nextButton.focus();
|
||||
activate(nextButton);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Mark server-rendered panels as already loaded. The panel itself owns
|
||||
// the posts-row contract, so checking descendants would miss SSR items.
|
||||
panels.forEach(function (panel) {
|
||||
if (getRenderedPostCount(panel) < 1) return;
|
||||
panel.dataset.loaded = 'true';
|
||||
panel.dataset.loadedPage = '1';
|
||||
panel.dataset.loadedSort = getCurrentSort(stream);
|
||||
panel.dataset.loadedTermId = String(getPanelTermId(panel));
|
||||
});
|
||||
|
||||
// Activate initial tab
|
||||
var initialButton = buttons.find(function (b) {
|
||||
return b.getAttribute('aria-selected') === 'true';
|
||||
}) || buttons[0];
|
||||
activate(initialButton);
|
||||
});
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* Sortbar Dropdown Toggle
|
||||
* ============================================================ */
|
||||
|
||||
function initSortbarDropdown() {
|
||||
document.querySelectorAll('[data-sort-dropdown-trigger]').forEach(function (trigger) {
|
||||
var wrapper = trigger.closest('.aksrt-homepage__sortbar-dropdown');
|
||||
if (!wrapper) return;
|
||||
var menu = wrapper.querySelector('.aksrt-homepage__sortbar-dropdown-menu');
|
||||
if (!menu) return;
|
||||
|
||||
function close() {
|
||||
menu.setAttribute('hidden', '');
|
||||
trigger.setAttribute('aria-expanded', 'false');
|
||||
}
|
||||
|
||||
function toggle() {
|
||||
var isOpen = !menu.hasAttribute('hidden');
|
||||
if (isOpen) {
|
||||
close();
|
||||
} else {
|
||||
menu.removeAttribute('hidden');
|
||||
trigger.setAttribute('aria-expanded', 'true');
|
||||
}
|
||||
}
|
||||
|
||||
trigger.addEventListener('click', function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
toggle();
|
||||
});
|
||||
|
||||
// Close when clicking an item
|
||||
menu.addEventListener('click', function (e) {
|
||||
var item = e.target.closest('.aksrt-homepage__sortbar-dropdown-item');
|
||||
if (!item) return;
|
||||
// Update trigger text
|
||||
trigger.firstChild.textContent = item.textContent;
|
||||
// Update active state
|
||||
menu.querySelectorAll('.aksrt-homepage__sortbar-dropdown-item').forEach(function (el) {
|
||||
el.classList.toggle('is-active', el === item);
|
||||
});
|
||||
close();
|
||||
});
|
||||
|
||||
// Close on outside click
|
||||
document.addEventListener('click', function (e) {
|
||||
if (!wrapper.contains(e.target)) close();
|
||||
});
|
||||
|
||||
// Close on Escape
|
||||
document.addEventListener('keydown', function (e) {
|
||||
if (e.key === 'Escape' && !menu.hasAttribute('hidden')) {
|
||||
close();
|
||||
trigger.focus();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* Sortbar AJAX
|
||||
* ============================================================ */
|
||||
|
||||
function initSortbar() {
|
||||
document.querySelectorAll('.aksrt-homepage__stream').forEach(function (stream) {
|
||||
var sortbar = stream.querySelector('.aksrt-homepage__sortbar');
|
||||
if (!sortbar) return;
|
||||
|
||||
sortbar.addEventListener('click', function (event) {
|
||||
var link = event.target.closest('.aksrt-homepage__sortbar-link, .aksrt-homepage__sortbar-dropdown-item');
|
||||
var activePanel = getActivePanel(stream);
|
||||
var sort = link ? link.getAttribute('data-sort') : '';
|
||||
var termId = getPanelTermId(activePanel);
|
||||
|
||||
if (!link || !activePanel || !sort) return;
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
setActiveSortLink(sortbar, sort);
|
||||
|
||||
requestHomepagePanel(activePanel, {
|
||||
termId: termId,
|
||||
page: 1,
|
||||
perPage: getHomepagePerPage(activePanel),
|
||||
sort: sort,
|
||||
viewMode: getStreamViewMode(stream),
|
||||
panel: activePanel.getAttribute('data-home-tab-panel') || 'latest',
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* Sticky Tabs
|
||||
* ============================================================ */
|
||||
|
||||
function supportsStickyPosition() {
|
||||
if (window.CSS && typeof window.CSS.supports === 'function') {
|
||||
return window.CSS.supports('position', 'sticky') || window.CSS.supports('position', '-webkit-sticky');
|
||||
}
|
||||
var testNode = document.createElement('div');
|
||||
testNode.style.position = 'sticky';
|
||||
return testNode.style.position.indexOf('sticky') !== -1;
|
||||
}
|
||||
|
||||
function getStickyOffset() {
|
||||
var docStyles = window.getComputedStyle(document.documentElement);
|
||||
var offset = parseFloat(docStyles.getPropertyValue('--nav-height') || '60');
|
||||
return isNaN(offset) ? 60 : offset;
|
||||
}
|
||||
|
||||
function initStickyTabs() {
|
||||
if (!isStickyTabsEnabled()) return;
|
||||
|
||||
document.querySelectorAll('.aksrt-homepage__tabs.home-tab-nav-box').forEach(function (tabs) {
|
||||
var parent = tabs.parentNode;
|
||||
var sentinel = tabs.previousElementSibling;
|
||||
var canUseSticky = supportsStickyPosition();
|
||||
var hasObserver = 'IntersectionObserver' in window;
|
||||
var observer = null;
|
||||
|
||||
if (!parent || tabs.getAttribute('data-sticky-tabs') === 'false') return;
|
||||
|
||||
if (!sentinel || !sentinel.classList.contains('aksrt-homepage__tabs-sentinel')) {
|
||||
sentinel = document.createElement('div');
|
||||
sentinel.className = 'aksrt-homepage__tabs-sentinel';
|
||||
parent.insertBefore(sentinel, tabs);
|
||||
}
|
||||
|
||||
function clearAffixBox() {
|
||||
sentinel.style.height = '1px';
|
||||
tabs.style.left = '';
|
||||
tabs.style.width = '';
|
||||
}
|
||||
|
||||
function syncAffixBox() {
|
||||
var rect = sentinel.getBoundingClientRect();
|
||||
sentinel.style.height = tabs.offsetHeight + 'px';
|
||||
tabs.style.left = rect.left + 'px';
|
||||
tabs.style.width = rect.width + 'px';
|
||||
}
|
||||
|
||||
function setStickyState(isStuck) {
|
||||
tabs.classList.toggle('is-stuck', isStuck);
|
||||
if (!canUseSticky) {
|
||||
tabs.classList.toggle('is-affixed', isStuck);
|
||||
if (isStuck) { syncAffixBox(); } else { clearAffixBox(); }
|
||||
return;
|
||||
}
|
||||
tabs.classList.remove('is-affixed');
|
||||
clearAffixBox();
|
||||
}
|
||||
|
||||
function evaluateFallbackState() {
|
||||
setStickyState(sentinel.getBoundingClientRect().top <= getStickyOffset());
|
||||
}
|
||||
|
||||
if (canUseSticky && hasObserver) {
|
||||
var bindObserver = function () {
|
||||
if (observer) observer.disconnect();
|
||||
observer = new IntersectionObserver(function (entries) {
|
||||
setStickyState(!entries[0].isIntersecting);
|
||||
}, { rootMargin: '-' + getStickyOffset() + 'px 0px 0px 0px', threshold: [1] });
|
||||
observer.observe(sentinel);
|
||||
};
|
||||
bindObserver();
|
||||
window.addEventListener('resize', bindObserver);
|
||||
return;
|
||||
}
|
||||
|
||||
window.addEventListener('scroll', evaluateFallbackState, { passive: true });
|
||||
window.addEventListener('resize', evaluateFallbackState);
|
||||
evaluateFallbackState();
|
||||
});
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* Init
|
||||
* ============================================================ */
|
||||
|
||||
function init() {
|
||||
if (document.body.dataset.aksrtHomeFixedInit === '1') return;
|
||||
document.body.dataset.aksrtHomeFixedInit = '1';
|
||||
|
||||
initHomeTabs();
|
||||
initSortbarDropdown();
|
||||
initSortbar();
|
||||
initStickyTabs();
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', init);
|
||||
} else {
|
||||
init();
|
||||
}
|
||||
})();
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
@@ -187,6 +187,11 @@ if (!function_exists('aksrt_archive_render_filter_bar')) :
|
||||
* @param array<string,mixed> $args Filter bar args.
|
||||
*/
|
||||
function aksrt_archive_render_filter_bar(array $args = []): void {
|
||||
// legacy zib_ajax_option_menu:nofilter 请求(首页更多栏目 tab 加载)不输出筛选菜单。
|
||||
if (!empty($_GET['nofilter'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$args = wp_parse_args($args, [
|
||||
'ajax' => false,
|
||||
'ajax_archive' => '',
|
||||
|
||||
@@ -217,16 +217,20 @@ if (!function_exists('aksrt_archive_render_stream')) :
|
||||
|
||||
<?php if ($has_posts) : ?>
|
||||
<?php
|
||||
aksrt_render_post_list(array_merge($render_config, ['wrapper_class' => 'content-stream__list']), $query);
|
||||
// legacy 契约:分页渲染在 .ajaxpager 内部(zib_paging 位置),
|
||||
// 首页更多栏目 tab 的 runtime post_ajax 依赖它提取下一页。
|
||||
ob_start();
|
||||
aksrt_render_pagination($query, [
|
||||
'query_context' => (string) $args['query_context'],
|
||||
'render_config' => $render_config,
|
||||
]);
|
||||
$pagination_html = (string) ob_get_clean();
|
||||
|
||||
aksrt_render_post_list(array_merge($render_config, [
|
||||
'wrapper_class' => 'content-stream__list',
|
||||
'append_inner_html' => $pagination_html,
|
||||
]), $query);
|
||||
?>
|
||||
<div class="content-stream__footer">
|
||||
<?php
|
||||
aksrt_render_pagination($query, [
|
||||
'query_context' => (string) $args['query_context'],
|
||||
'render_config' => $render_config,
|
||||
]);
|
||||
?>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<div class="no-results content-stream__empty">
|
||||
<p><?php echo esc_html((string) $args['empty_text']); ?></p>
|
||||
|
||||
+127
-107
@@ -46,7 +46,7 @@ if (!function_exists('aksrt_homepage_get_post_types')) {
|
||||
}
|
||||
|
||||
|
||||
if (!function_exists('aksrt_homepage_get_tab_terms')) {
|
||||
if (!function_exists('aksrt_homepage_get_tab_configs')) {
|
||||
/**
|
||||
* Homepage category tabs with full config.
|
||||
*
|
||||
@@ -88,52 +88,12 @@ if (!function_exists('aksrt_homepage_get_tab_terms')) {
|
||||
'term' => $term,
|
||||
'term_id' => (int) $tab['term_id'],
|
||||
'title' => $tab['title'] !== '' ? $tab['title'] : $term->name,
|
||||
'orderby' => $tab['orderby'] ?: 'modified',
|
||||
'orderby' => $tab['orderby'] ?: '',
|
||||
];
|
||||
}
|
||||
|
||||
return $configs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Homepage category tabs — returns WP_Term objects for backward compat.
|
||||
*
|
||||
* @param int $limit Unused, reads from settings.
|
||||
* @return WP_Term[]
|
||||
*/
|
||||
function aksrt_homepage_get_tab_terms(int $limit = 4): array {
|
||||
$configs = aksrt_homepage_get_tab_configs();
|
||||
return array_column($configs, 'term');
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_homepage_get_tab_posts_per_page')) {
|
||||
/**
|
||||
* Per-tab homepage post count.
|
||||
*/
|
||||
function aksrt_homepage_get_tab_posts_per_page(): int {
|
||||
if (class_exists('\AKSRT\Settings\Settings')) {
|
||||
$count = \AKSRT\Settings\Settings::homepage_tab_posts_per_page();
|
||||
if ($count > 0) {
|
||||
return max(1, min(20, $count));
|
||||
}
|
||||
}
|
||||
|
||||
return 6;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_homepage_sticky_tabs_enabled')) {
|
||||
/**
|
||||
* Whether homepage tabs should stick below the primary nav.
|
||||
*/
|
||||
function aksrt_homepage_sticky_tabs_enabled(): bool {
|
||||
if (class_exists('\AKSRT\Settings\Settings')) {
|
||||
return \AKSRT\Settings\Settings::homepage_sticky_tabs_enabled();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_homepage_get_sort_mode')) {
|
||||
@@ -156,32 +116,23 @@ if (!function_exists('aksrt_homepage_get_sort_mode')) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_homepage_get_sort_items')) {
|
||||
if (!function_exists('aksrt_homepage_get_request_sort')) {
|
||||
/**
|
||||
* Configured sort bar items for the main stream.
|
||||
* Main-stream sort requested by URL (?orderby=), legacy zib_sift_posts_per_orde.
|
||||
*
|
||||
* @return array<string,string>
|
||||
* 排序菜单(.ajax-option)点击后原位刷新的响应页靠它同序。
|
||||
*/
|
||||
function aksrt_homepage_get_sort_items(): array {
|
||||
$all_labels = class_exists('\AKSRT\Settings\Settings')
|
||||
? \AKSRT\Settings\Settings::homepage_sort_labels()
|
||||
: [
|
||||
'modified' => '更新', 'date' => '发布', 'views' => '浏览',
|
||||
'like' => '点赞', 'comment_count' => '评论', 'favorite' => '收藏', 'rand' => '随机',
|
||||
];
|
||||
|
||||
$enabled_keys = class_exists('\AKSRT\Settings\Settings')
|
||||
? \AKSRT\Settings\Settings::home_list_sort_options()
|
||||
: array_keys($all_labels);
|
||||
|
||||
$items = [];
|
||||
foreach ($enabled_keys as $key) {
|
||||
if (isset($all_labels[$key])) {
|
||||
$items[$key] = $all_labels[$key];
|
||||
}
|
||||
function aksrt_homepage_get_request_sort(): string {
|
||||
$get_sort = isset($_GET['orderby']) ? sanitize_key(wp_unslash((string) $_GET['orderby'])) : '';
|
||||
if ($get_sort === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
return !empty($items) ? $items : ['modified' => '更新', 'date' => '发布'];
|
||||
$allowed = class_exists('\AKSRT\Settings\Settings')
|
||||
? \AKSRT\Settings\Settings::homepage_allowed_sorts()
|
||||
: ['modified', 'date', 'views', 'like', 'comment_count', 'favorite', 'rand'];
|
||||
|
||||
return in_array($get_sort, $allowed, true) ? $get_sort : '';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,55 +220,124 @@ if (!function_exists('aksrt_homepage_apply_named_sort_args')) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_homepage_render_sortbar')) {
|
||||
if (!function_exists('aksrt_homepage_render_ajax_option_menu')) {
|
||||
/**
|
||||
* Render the main-stream sort bar.
|
||||
* 首页排序菜单,1:1 zib_ajax_option_menu('home')。
|
||||
*
|
||||
* 输出 .ajax-option.ajax-replace[win-ajax-replace="filter"],点击 .ajax-next
|
||||
* 排序链接由 runtime post_ajax 原位替换 #index-tab-main 内的列表。
|
||||
*/
|
||||
function aksrt_homepage_render_sortbar(): void {
|
||||
if (class_exists('\AKSRT\Settings\Settings') && !\AKSRT\Settings\Settings::home_list_sort_enabled()) {
|
||||
function aksrt_homepage_render_ajax_option_menu(): void {
|
||||
if (!empty($_GET['nofilter'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$current = aksrt_homepage_get_sort_mode();
|
||||
$is_dropdown = class_exists('\AKSRT\Settings\Settings')
|
||||
? \AKSRT\Settings\Settings::home_list_sort_dropdown()
|
||||
: false;
|
||||
$sort_items = aksrt_homepage_get_sort_items();
|
||||
$all_labels = class_exists('\AKSRT\Settings\Settings')
|
||||
if (!class_exists('\AKSRT\Settings\Settings') || !\AKSRT\Settings\Settings::home_list_sort_enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$con = aksrt_homepage_get_option_orderby_but([
|
||||
'lists' => (array) \AKSRT\Settings\Settings::home_list_sort_options(),
|
||||
'dropdown' => (bool) \AKSRT\Settings\Settings::home_list_sort_dropdown(),
|
||||
]);
|
||||
|
||||
if (!$con) {
|
||||
return;
|
||||
}
|
||||
|
||||
echo '<div class="ajax-option ajax-replace" win-ajax-replace="filter">' . $con . '</div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo '<div></div>'; // 空白内容,解决css奇数偶数行
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_homepage_get_option_orderby_but')) {
|
||||
/**
|
||||
* 排序方式按钮组,1:1 zib_get_option_orderby_but。
|
||||
*
|
||||
* @param array{lists?:string[],dropdown?:bool} $option Sort option config.
|
||||
*/
|
||||
function aksrt_homepage_get_option_orderby_but($option = []): string {
|
||||
$defaults = [
|
||||
'lists' => [],
|
||||
'dropdown' => false,
|
||||
];
|
||||
|
||||
$option = wp_parse_args((array) $option, $defaults);
|
||||
if (!$option['lists'] && !$option['dropdown']) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$labels = class_exists('\AKSRT\Settings\Settings')
|
||||
? \AKSRT\Settings\Settings::homepage_sort_labels()
|
||||
: $sort_items;
|
||||
?>
|
||||
<div class="aksrt-homepage__sortbar" aria-label="<?php esc_attr_e('Homepage Sort', 'aksrt'); ?>">
|
||||
<?php if ($is_dropdown) : ?>
|
||||
<div class="aksrt-homepage__sortbar-dropdown">
|
||||
<button type="button" class="aksrt-homepage__sortbar-current" data-sort-dropdown-trigger>
|
||||
<?php echo esc_html($all_labels[$current] ?? $current); ?>
|
||||
<i class="fa fas fa-caret-down" aria-hidden="true"></i>
|
||||
</button>
|
||||
<div class="aksrt-homepage__sortbar-dropdown-menu" hidden>
|
||||
<?php foreach ($sort_items as $sort_key => $label) : ?>
|
||||
<button type="button"
|
||||
class="aksrt-homepage__sortbar-dropdown-item<?php echo $sort_key === $current ? ' is-active' : ''; ?>"
|
||||
data-sort="<?php echo esc_attr($sort_key); ?>"
|
||||
>
|
||||
<?php echo esc_html($label); ?>
|
||||
</button>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<div class="aksrt-homepage__sortbar-links">
|
||||
<?php foreach ($sort_items as $sort_key => $label) : ?>
|
||||
<button type="button"
|
||||
class="aksrt-homepage__sortbar-link<?php echo $sort_key === $current ? ' is-active' : ''; ?>"
|
||||
data-sort="<?php echo esc_attr($sort_key); ?>"
|
||||
>
|
||||
<?php echo esc_html($label); ?>
|
||||
</button>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php
|
||||
: ['modified' => '更新', 'date' => '发布', 'views' => '浏览', 'like' => '点赞', 'comment_count' => '评论', 'favorite' => '收藏', 'rand' => '随机'];
|
||||
|
||||
$dropdown_but = '';
|
||||
$but = '';
|
||||
$uri = aksrt_homepage_url_del_paged(aksrt_homepage_get_current_url());
|
||||
|
||||
foreach ($option['lists'] as $key) {
|
||||
if (!isset($labels[$key])) {
|
||||
continue;
|
||||
}
|
||||
$_class = 'ajax-next';
|
||||
if (isset($_GET['orderby']) && sanitize_key(wp_unslash((string) $_GET['orderby'])) === $key) {
|
||||
$_class .= ' focus-color';
|
||||
}
|
||||
$href = add_query_arg(['orderby' => $key], $uri);
|
||||
$but .= '<a rel="nofollow" ajax-replace="true" class="' . esc_attr($_class) . '" href="' . esc_url($href) . '">' . esc_html($labels[$key]) . '</a>';
|
||||
}
|
||||
if ($option['dropdown']) {
|
||||
foreach ($labels as $key => $value) {
|
||||
$_class = 'ajax-next';
|
||||
if (isset($_GET['orderby']) && sanitize_key(wp_unslash((string) $_GET['orderby'])) === $key) {
|
||||
$_class .= ' focus-color';
|
||||
}
|
||||
$href = add_query_arg(['orderby' => $key], $uri);
|
||||
$dropdown_but .= '<li><a rel="nofollow" ajax-replace="true" class="' . esc_attr($_class) . '" href="' . esc_url($href) . '">' . esc_html($value) . '</a></li>';
|
||||
}
|
||||
}
|
||||
|
||||
if (!$but && !$dropdown_but) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$is_dropdown = ($option['dropdown'] && $dropdown_but) ? true : false;
|
||||
$d_but = $is_dropdown
|
||||
? '<a href="javascript:;" data-toggle="dropdown"><span name="cat">' . esc_html__('排序', 'aksrt') . '</span><i class="fa fa-fw fa-sort opacity5" aria-hidden="true"></i></a>'
|
||||
: esc_html__('排序', 'aksrt');
|
||||
|
||||
$html = '<div class="flex ac">';
|
||||
$html .= '<div class="option-dropdown splitters-this-r dropdown flex0">';
|
||||
$html .= $d_but;
|
||||
$html .= $is_dropdown ? '<ul class="dropdown-menu">' . $dropdown_but . '</ul>' : '';
|
||||
$html .= '</div>';
|
||||
$html .= '<ul class="list-inline scroll-x mini-scrollbar option-items">' . $but . '</ul>';
|
||||
$html .= '</div>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_homepage_get_current_url')) {
|
||||
/**
|
||||
* 当前页面链接,1:1 zib_get_current_url。
|
||||
*/
|
||||
function aksrt_homepage_get_current_url(): string {
|
||||
$home_url = home_url();
|
||||
$host = preg_replace('/^(http|https)(:\/\/)(?)([^\/]+).*$/im', '$1$2$3', $home_url);
|
||||
|
||||
return $host . add_query_arg(null, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_homepage_url_del_paged')) {
|
||||
/**
|
||||
* 移除分页参数的链接,1:1 zib_url_del_paged。
|
||||
*/
|
||||
function aksrt_homepage_url_del_paged(string $url): string {
|
||||
$url = remove_query_arg(['paged', 'page'], $url);
|
||||
global $wp_rewrite;
|
||||
|
||||
return preg_replace('/\/' . $wp_rewrite->pagination_base . '\/\d*/', '', $url);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,60 +43,15 @@ if (!function_exists('aksrt_homepage_get_latest_query')) {
|
||||
$query_args['category__not_in'] = $exclude_cat_ids;
|
||||
}
|
||||
|
||||
$query = new WP_Query(aksrt_homepage_apply_sort_args($query_args));
|
||||
|
||||
return $query;
|
||||
}
|
||||
}
|
||||
if (!function_exists('aksrt_homepage_get_tab_query')) {
|
||||
/**
|
||||
* Build a category-tab query.
|
||||
*/
|
||||
function aksrt_homepage_get_tab_query(int $term_id, string $orderby = 'date'): WP_Query {
|
||||
static $queries = [];
|
||||
|
||||
$cache_key = $term_id . '_' . $orderby;
|
||||
if (isset($queries[$cache_key]) && $queries[$cache_key] instanceof WP_Query) {
|
||||
return $queries[$cache_key];
|
||||
}
|
||||
|
||||
$term = get_term($term_id);
|
||||
$taxonomy = ($term && !is_wp_error($term)) ? (string) $term->taxonomy : 'category';
|
||||
if ($taxonomy !== 'category') {
|
||||
$taxonomy = 'category';
|
||||
}
|
||||
|
||||
$query_args = [
|
||||
'post_type' => aksrt_homepage_get_post_types(),
|
||||
'post_status' => 'publish',
|
||||
'posts_per_page' => class_exists('\AKSRT\Settings\Settings')
|
||||
? \AKSRT\Settings\Settings::homepage_tab_posts_per_page()
|
||||
: 6,
|
||||
'ignore_sticky_posts' => true,
|
||||
'orderby' => 'date',
|
||||
'order' => 'DESC',
|
||||
'no_found_rows' => true,
|
||||
'tax_query' => [
|
||||
[
|
||||
'taxonomy' => $taxonomy,
|
||||
'field' => 'term_id',
|
||||
'terms' => [$term_id],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$exclude_ids = class_exists('\AKSRT\Settings\Settings')
|
||||
? \AKSRT\Settings\Settings::home_exclude_post_ids()
|
||||
: [];
|
||||
if (!empty($exclude_ids)) {
|
||||
$query_args['post__not_in'] = $exclude_ids;
|
||||
}
|
||||
|
||||
$queries[$cache_key] = new WP_Query(
|
||||
aksrt_homepage_apply_named_sort_args($query_args, $orderby)
|
||||
// legacy zib_sift_posts_per_orde:排序菜单的 ?orderby= 优先于后台默认排序。
|
||||
$request_sort = aksrt_homepage_get_request_sort();
|
||||
$query = new WP_Query(
|
||||
$request_sort !== ''
|
||||
? aksrt_homepage_apply_named_sort_args($query_args, $request_sort)
|
||||
: aksrt_homepage_apply_sort_args($query_args)
|
||||
);
|
||||
|
||||
return $queries[$cache_key];
|
||||
return $query;
|
||||
}
|
||||
}
|
||||
if (!function_exists('aksrt_homepage_has_active_sidebars')) {
|
||||
|
||||
+111
-85
@@ -16,15 +16,7 @@ if (!function_exists('aksrt_homepage_render_layout')) {
|
||||
* → fluid bottom. Hero/header-slider is rendered from header.php, not here.
|
||||
*/
|
||||
function aksrt_homepage_render_layout(): void {
|
||||
$current_page = aksrt_homepage_get_current_page();
|
||||
$show_tabs = $current_page === 1;
|
||||
$tab_configs = $show_tabs ? aksrt_homepage_get_tab_configs() : [];
|
||||
$latest_contract = aksrt_homepage_get_latest_panel_contract();
|
||||
$view_mode = (($latest_contract['render_config_array']['mode'] ?? 'list') === 'card') ? 'card' : 'list';
|
||||
$main_list_enabled = !class_exists('\AKSRT\Settings\Settings') || \AKSRT\Settings\Settings::home_posts_list_enabled();
|
||||
$list_title = class_exists('\AKSRT\Settings\Settings')
|
||||
? \AKSRT\Settings\Settings::home_list_title()
|
||||
: __('最新发布', 'aksrt');
|
||||
|
||||
// Fluid zones live outside <main>, once only (removed from header.php).
|
||||
aksrt_homepage_render_widget_zone(
|
||||
@@ -43,86 +35,19 @@ if (!function_exists('aksrt_homepage_render_layout')) {
|
||||
|
||||
?>
|
||||
|
||||
<?php if ($main_list_enabled) : ?>
|
||||
<section class="aksrt-homepage__stream home-tab-content" aria-label="<?php esc_attr_e('Homepage Content', 'aksrt'); ?>">
|
||||
<?php if ($show_tabs && !empty($tab_configs)) : ?>
|
||||
<div class="index-tab affix-header-sm relative home-tab-nav-box aksrt-homepage__tabs mb10" data-sticky-tabs="<?php echo aksrt_homepage_sticky_tabs_enabled() ? 'true' : 'false'; ?>" offset-top="-8">
|
||||
<ul class="list-inline scroll-x no-scrollbar aksrt-homepage__tab-list" role="tablist" data-aksrt-home-tabs style="width:100%;">
|
||||
<li class="aksrt-homepage__tab-item is-active" role="presentation">
|
||||
<button type="button" class="aksrt-homepage__tab-button" role="tab" aria-selected="true" data-home-tab-target="latest">
|
||||
<?php echo wp_kses_post($list_title !== '' ? $list_title : __('最新发布', 'aksrt')); ?>
|
||||
</button>
|
||||
</li>
|
||||
<?php foreach ($tab_configs as $tab_cfg) : ?>
|
||||
<li class="aksrt-homepage__tab-item" role="presentation">
|
||||
<button
|
||||
type="button"
|
||||
class="aksrt-homepage__tab-button"
|
||||
role="tab"
|
||||
aria-selected="false"
|
||||
data-home-tab-target="term-<?php echo (int) $tab_cfg['term_id']; ?>"
|
||||
data-tab-orderby="<?php echo esc_attr($tab_cfg['orderby']); ?>"
|
||||
>
|
||||
<?php echo wp_kses_post($tab_cfg['title']); ?>
|
||||
</button>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<?php if (function_exists('aksrt_render_admin_quick_link')) { aksrt_render_admin_quick_link('page-display/homepage', __('首页设置', 'aksrt'), 'aksrt-admin-quicklink aksrt-homepage__admin-link'); } ?>
|
||||
</div>
|
||||
<?php elseif ($current_page > 1) : ?>
|
||||
<div class="box-body notop nobottom aksrt-homepage__titlebox">
|
||||
<div class="title-theme">
|
||||
<?php echo wp_kses_post($list_title !== '' ? $list_title : __('最新发布', 'aksrt')); ?>
|
||||
<small class="aksrt-homepage__page-indicator ml10">
|
||||
<?php echo esc_html(sprintf(__('第 %d 页', 'aksrt'), $current_page)); ?>
|
||||
</small>
|
||||
<?php if ($main_list_enabled) :
|
||||
$tab_configs = aksrt_homepage_get_current_page() === 1 ? aksrt_homepage_get_tab_configs() : [];
|
||||
?>
|
||||
<div class="home-tab-content">
|
||||
<?php echo aksrt_homepage_get_tab_header_html($tab_configs); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
<div class="tab-content">
|
||||
<div class="posts-row ajaxpager tab-pane fade in active" id="index-tab-main">
|
||||
<?php aksrt_homepage_render_ajax_option_menu(); ?>
|
||||
<?php aksrt_homepage_render_posts_grid(aksrt_homepage_get_latest_query(), true); ?>
|
||||
</div>
|
||||
<?php echo aksrt_homepage_get_tab_panes_html($tab_configs); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
</div>
|
||||
<?php elseif ($list_title !== '') : ?>
|
||||
<div class="box-body notop nobottom aksrt-homepage__titlebox">
|
||||
<div class="title-theme"><?php echo wp_kses_post($list_title); ?></div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php aksrt_homepage_render_sortbar(); ?>
|
||||
|
||||
<div class="aksrt-homepage__panels tab-content">
|
||||
<div class="aksrt-homepage__panel aksrt-homepage__posts posts-row post-grid post-grid--home ajaxpager tab-pane is-active show" role="tabpanel" data-home-tab-panel="latest" data-view="<?php echo esc_attr($view_mode); ?>" id="index-tab-main">
|
||||
<div
|
||||
class="aksrt-homepage__panel-contract"
|
||||
data-query-context="<?php echo esc_attr($latest_contract['query_context']); ?>"
|
||||
data-query-vars="<?php echo esc_attr($latest_contract['query_vars']); ?>"
|
||||
data-render-config="<?php echo esc_attr($latest_contract['render_config']); ?>"
|
||||
data-page="1"
|
||||
data-tab="latest"
|
||||
></div>
|
||||
<?php aksrt_homepage_render_posts_grid(aksrt_homepage_get_latest_query(), true); ?>
|
||||
</div>
|
||||
|
||||
<?php if ($show_tabs && !empty($tab_configs)) : ?>
|
||||
<?php foreach ($tab_configs as $tab_cfg) : ?>
|
||||
<div
|
||||
class="aksrt-homepage__panel aksrt-homepage__posts posts-row post-grid post-grid--home ajaxpager tab-pane"
|
||||
data-view="<?php echo esc_attr($view_mode); ?>"
|
||||
role="tabpanel"
|
||||
data-home-tab-panel="term-<?php echo (int) $tab_cfg['term_id']; ?>"
|
||||
data-tab-orderby="<?php echo esc_attr($tab_cfg['orderby']); ?>"
|
||||
hidden
|
||||
></div>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</section>
|
||||
<?php else : ?>
|
||||
<section class="aksrt-homepage__stream home-tab-content aksrt-homepage__stream--disabled" aria-label="<?php esc_attr_e('Homepage Content', 'aksrt'); ?>">
|
||||
<div class="no-results box-body">
|
||||
<p><?php esc_html_e('首页主列表已关闭。', 'aksrt'); ?></p>
|
||||
<?php if (current_user_can('manage_options') && function_exists('aksrt_render_admin_quick_link')) : ?>
|
||||
<?php aksrt_render_admin_quick_link('page-display/homepage', __('打开首页设置并启用主列表', 'aksrt'), 'aksrt-admin-quicklink'); ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</section>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php
|
||||
@@ -144,6 +69,107 @@ if (!function_exists('aksrt_homepage_render_layout')) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_homepage_get_tab_header_html')) {
|
||||
/**
|
||||
* legacy zib_index_tab_html:tab 导航 / 翻页标题条 / 空占位 三态。
|
||||
*
|
||||
* @param array<int, array<string, mixed>> $tab_configs Configured term tabs.
|
||||
*/
|
||||
function aksrt_homepage_get_tab_header_html(array $tab_configs): string {
|
||||
$list_title = class_exists('\AKSRT\Settings\Settings')
|
||||
? \AKSRT\Settings\Settings::home_list_title()
|
||||
: '';
|
||||
$fallback_title = $list_title !== '' ? $list_title : __('最新发布', 'aksrt');
|
||||
$paged = aksrt_homepage_get_current_page();
|
||||
|
||||
//不是第一页
|
||||
if ($paged > 1) {
|
||||
return '<div class="box-body notop nobottom"><div class="title-theme">' . $fallback_title
|
||||
. '<small class="ml10">' . esc_html(sprintf(__('第%s页', 'aksrt'), $paged)) . '</small></div></div>';
|
||||
}
|
||||
|
||||
$index_tab_nav = '';
|
||||
foreach ($tab_configs as $index => $tab_cfg) {
|
||||
$index_tab_nav .= '<li><a data-toggle="tab" data-ajax="' . esc_url(aksrt_homepage_get_tab_link($tab_cfg))
|
||||
. '" href="#index-tab-' . (int) $index . '">' . wp_kses_post($tab_cfg['title']) . '</a></li>';
|
||||
}
|
||||
|
||||
if (!$index_tab_nav) {
|
||||
return $list_title !== ''
|
||||
? '<div class="box-body notop nobottom"><div class="title-theme">' . wp_kses_post($list_title) . '</div></div>'
|
||||
: '<div></div>';
|
||||
}
|
||||
|
||||
$html = '<li class="active"><a data-toggle="tab" href="#index-tab-main">' . wp_kses_post($fallback_title) . '</a></li>' . $index_tab_nav;
|
||||
|
||||
return '<div class="index-tab affix-header-sm relative home-tab-nav-box mb10" offset-top="-8"><ul style="width:100%;" class="scroll-x no-scrollbar">' . $html . '</ul></div>';
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_homepage_get_tab_panes_html')) {
|
||||
/**
|
||||
* legacy zib_index_tab('content'):每个栏目的原位刷新 pane。
|
||||
*
|
||||
* pane 本身就是 .ajaxpager;post_ajax_trigger 指向栏目页,post_ajax 加载后
|
||||
* 用栏目页自身的列表 DOM 原地替换 loader,不新建区域。
|
||||
*
|
||||
* @param array<int, array<string, mixed>> $tab_configs Configured term tabs.
|
||||
*/
|
||||
function aksrt_homepage_get_tab_panes_html(array $tab_configs): string {
|
||||
if (!$tab_configs) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$is_card = class_exists('\AKSRT\Settings\PostDisplay')
|
||||
&& \AKSRT\Settings\PostDisplay::get_archive_layout() === 'card';
|
||||
$is_mobel = wp_is_mobile();
|
||||
if ($is_card) {
|
||||
$placeholder_type = 'card';
|
||||
$placeholder_num = $is_mobel ? 4 : 12;
|
||||
} else {
|
||||
$placeholder_type = 'list';
|
||||
$placeholder_num = $is_mobel ? 4 : 6;
|
||||
}
|
||||
$placeholder = aksrt_render_placeholder($placeholder_type, $placeholder_num);
|
||||
|
||||
$html = '';
|
||||
foreach ($tab_configs as $index => $tab_cfg) {
|
||||
$html .= '<div class="ajaxpager tab-pane fade" id="index-tab-' . (int) $index . '">';
|
||||
$html .= '<span class="post_ajax_trigger"><a class="ajax_load ajax-next ajax-open" href="' . esc_url(aksrt_homepage_get_tab_link($tab_cfg)) . '"></a></span>';
|
||||
$html .= '<div class="post_ajax_loader">' . $placeholder . '</div>';
|
||||
$html .= '</div>';
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_homepage_get_tab_link')) {
|
||||
/**
|
||||
* 栏目 tab 的加载链接:栏目页 + nofilter(抑制响应页的筛选菜单)。
|
||||
*
|
||||
* @param array<string, mixed> $tab_cfg Tab config with term and orderby.
|
||||
*/
|
||||
function aksrt_homepage_get_tab_link(array $tab_cfg): string {
|
||||
$term = $tab_cfg['term'] ?? null;
|
||||
if (!$term instanceof WP_Term) {
|
||||
return home_url('/');
|
||||
}
|
||||
|
||||
$query_arg = ['nofilter' => 'true'];
|
||||
if (!empty($tab_cfg['orderby'])) {
|
||||
$query_arg['orderby'] = $tab_cfg['orderby'];
|
||||
}
|
||||
|
||||
$link = get_term_link($term);
|
||||
if (is_wp_error($link)) {
|
||||
return home_url('/');
|
||||
}
|
||||
|
||||
return add_query_arg($query_arg, $link);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_render_fixed_homepage')) {
|
||||
/**
|
||||
* Render the new fixed homepage layout.
|
||||
|
||||
@@ -152,6 +152,8 @@ if (!function_exists('aksrt_render_post_list')) {
|
||||
$classes[] = $class;
|
||||
}
|
||||
}
|
||||
// legacy 契约:分页等控件与列表同处一个 .ajaxpager 内,供 runtime post_ajax 提取。
|
||||
$append_inner_html = (string) ($cfg['append_inner_html'] ?? '');
|
||||
$html = empty($cfg['skip_wrapper'])
|
||||
? '<div class="' . esc_attr(implode(' ', array_unique($classes))) . '" data-view="' . esc_attr((string) $cfg['mode']) . '">'
|
||||
: '';
|
||||
@@ -168,6 +170,7 @@ if (!function_exists('aksrt_render_post_list')) {
|
||||
$html .= aksrt_render_post($cfg);
|
||||
}
|
||||
}
|
||||
$html .= $append_inner_html;
|
||||
if (empty($cfg['skip_wrapper'])) {
|
||||
$html .= '</div>';
|
||||
}
|
||||
|
||||
@@ -98,21 +98,6 @@ class GlobalController extends ControllerBase {
|
||||
'permission_callback' => [$this, 'check_permission'],
|
||||
]);
|
||||
|
||||
// Homepage tab posts (public)
|
||||
register_rest_route(self::API_NAMESPACE, '/homepage/tab-posts', [
|
||||
'methods' => 'GET',
|
||||
'callback' => [$this, 'rest_homepage_tab_posts'],
|
||||
'permission_callback' => '__return_true',
|
||||
'args' => [
|
||||
'term_id' => ['type' => 'integer', 'required' => true, 'sanitize_callback' => 'absint'],
|
||||
'page' => ['type' => 'integer', 'default' => 1, 'sanitize_callback' => 'absint'],
|
||||
'per_page' => ['type' => 'integer', 'default' => 10, 'sanitize_callback' => 'absint'],
|
||||
'sort' => ['type' => 'string', 'default' => 'modified', 'sanitize_callback' => 'sanitize_text_field'],
|
||||
'panel' => ['type' => 'string', 'default' => 'latest', 'sanitize_callback' => 'sanitize_key'],
|
||||
'tab_orderby' => ['type' => 'string', 'default' => '', 'sanitize_callback' => 'sanitize_key'],
|
||||
],
|
||||
]);
|
||||
|
||||
// Archive AJAX filter (public) — §2.5/§2.6/§2.7
|
||||
register_rest_route(self::API_NAMESPACE, '/archive/posts', [
|
||||
'methods' => 'GET',
|
||||
@@ -183,81 +168,7 @@ class GlobalController extends ControllerBase {
|
||||
return $this->success(['message' => '测试邮件已发送']);
|
||||
}
|
||||
|
||||
public function rest_homepage_tab_posts(\WP_REST_Request $request): \WP_REST_Response {
|
||||
$term_id = (int) $request->get_param('term_id');
|
||||
$page = max(1, (int) $request->get_param('page'));
|
||||
$per_page = min(50, max(1, (int) $request->get_param('per_page')));
|
||||
$sort = sanitize_key($request->get_param('sort') ?: 'modified');
|
||||
$tab_orderby = sanitize_key($request->get_param('tab_orderby') ?: '');
|
||||
$panel = sanitize_key($request->get_param('panel') ?: 'latest');
|
||||
|
||||
$post_types = function_exists('aksrt_homepage_get_post_types')
|
||||
? aksrt_homepage_get_post_types()
|
||||
: ['post'];
|
||||
|
||||
$args = [
|
||||
'post_type' => $post_types,
|
||||
'post_status' => 'publish',
|
||||
'posts_per_page' => $per_page,
|
||||
'paged' => $page,
|
||||
'ignore_sticky_posts' => $term_id > 0,
|
||||
];
|
||||
|
||||
if ($term_id > 0) {
|
||||
$term = get_term($term_id);
|
||||
$taxonomy = ($term && !is_wp_error($term)) ? (string) $term->taxonomy : 'category';
|
||||
if ($taxonomy !== 'category') {
|
||||
$taxonomy = 'category';
|
||||
}
|
||||
$args['tax_query'] = [[
|
||||
'taxonomy' => $taxonomy,
|
||||
'field' => 'term_id',
|
||||
'terms' => [$term_id],
|
||||
]];
|
||||
}
|
||||
|
||||
$exclude_ids = class_exists('\AKSRT\Settings\Settings')
|
||||
? \AKSRT\Settings\Settings::home_exclude_post_ids()
|
||||
: [];
|
||||
if (!empty($exclude_ids)) {
|
||||
$args['post__not_in'] = $exclude_ids;
|
||||
}
|
||||
|
||||
if ($panel === 'latest' || $term_id <= 0) {
|
||||
$exclude_cat_ids = class_exists('\AKSRT\Settings\Settings')
|
||||
? \AKSRT\Settings\Settings::home_exclude_category_ids()
|
||||
: [];
|
||||
if (!empty($exclude_cat_ids)) {
|
||||
$args['category__not_in'] = $exclude_cat_ids;
|
||||
}
|
||||
}
|
||||
|
||||
$effective_sort = $tab_orderby !== '' ? $tab_orderby : $sort;
|
||||
if (function_exists('aksrt_homepage_apply_named_sort_args')) {
|
||||
$args = aksrt_homepage_apply_named_sort_args($args, $effective_sort);
|
||||
} else {
|
||||
$args['orderby'] = 'date';
|
||||
$args['order'] = 'DESC';
|
||||
}
|
||||
|
||||
$query = new \WP_Query($args);
|
||||
|
||||
$render_config = aksrt_resolve_post_list_render_config([
|
||||
'context' => 'home',
|
||||
]);
|
||||
$render_config['skip_wrapper'] = true;
|
||||
$html = aksrt_render_post_list($render_config, $query, false);
|
||||
|
||||
$has_more = $page < (int) $query->max_num_pages;
|
||||
|
||||
return $this->success([
|
||||
'html' => $html,
|
||||
'total' => (int) $query->found_posts,
|
||||
'has_more' => $has_more,
|
||||
]);
|
||||
}
|
||||
|
||||
public function rest_archive_posts(\WP_REST_Request $request): \WP_REST_Response {
|
||||
public function rest_archive_posts(\WP_REST_Request $request): \WP_REST_Response {
|
||||
$archive_type = sanitize_key((string) ($request->get_param('archive_type') ?: 'category'));
|
||||
$archive_type = in_array($archive_type, ['category', 'tag'], true) ? $archive_type : 'category';
|
||||
$term_id = absint($request->get_param('term_id'));
|
||||
|
||||
@@ -367,18 +367,6 @@ trait ScriptsPart1c {
|
||||
);
|
||||
}
|
||||
|
||||
if ($is_fixed_homepage) {
|
||||
$homepage_js_path = get_template_directory() . '/assets/js/homepage-fixed.js';
|
||||
wp_enqueue_script(
|
||||
'aksrt-homepage-fixed',
|
||||
$base_uri . '/assets/js/homepage-fixed.js',
|
||||
['loader_js'],
|
||||
file_exists($homepage_js_path) ? (string) filemtime($homepage_js_path) : $version,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// Comment toolbar (code/image/link shortcodes) — post form.
|
||||
$load_comment_tools = !empty($singular_assets['needs_comment_tools']);
|
||||
if ($load_comment_tools) {
|
||||
@@ -476,12 +464,6 @@ trait ScriptsPart1c {
|
||||
'debugLog' => defined('WP_DEBUG') && WP_DEBUG && defined('WP_DEBUG_LOG') && WP_DEBUG_LOG,
|
||||
'postPaginationMode' => class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_post_pagination_mode() : 'load_more',
|
||||
'commentPaginationMode' => class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_comment_pagination_mode() : 'numbered',
|
||||
'homepagePostsPerPage' => function_exists('aksrt_homepage_get_tab_posts_per_page') ? aksrt_homepage_get_tab_posts_per_page() : (int) get_option('posts_per_page'),
|
||||
'homepageDefaultSort' => class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::homepage_default_sort() : 'modified',
|
||||
'homepageStickyTabs' => class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::homepage_sticky_tabs_enabled() : true,
|
||||
'homePostsListEnabled' => !class_exists('\AKSRT\Settings\Settings') || \AKSRT\Settings\Settings::home_posts_list_enabled(),
|
||||
'homeListSortEnabled' => !class_exists('\AKSRT\Settings\Settings') || \AKSRT\Settings\Settings::home_list_sort_enabled(),
|
||||
'homeListSortDropdown' => class_exists('\AKSRT\Settings\Settings') && \AKSRT\Settings\Settings::home_list_sort_dropdown(),
|
||||
// AJAX 翻页文案
|
||||
'ajaxTrigger' => (class_exists('\AKSRT\Settings\Settings') && ($t = \AKSRT\Settings\Settings::get_post_list_style_settings()['ajax_trigger'] ?? '') !== '') ? $t : '<i class="fa fas fa-angle-right"></i>加载更多',
|
||||
'ajaxNomore' => (class_exists('\AKSRT\Settings\Settings') && ($n = \AKSRT\Settings\Settings::get_post_list_style_settings()['ajax_nomore'] ?? '') !== '') ? $n : __('没有更多内容了', 'aksrt'),
|
||||
|
||||
@@ -175,10 +175,6 @@ class HomeCms {
|
||||
return $settings['home_list1_orderby_option']['lists'][0] ?? 'modified';
|
||||
}
|
||||
|
||||
public static function homepage_sticky_tabs_enabled(): bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function home_posts_list_enabled(): bool {
|
||||
$settings = self::get_homepage_fixed_settings();
|
||||
return !empty($settings['home_posts_list_s']);
|
||||
@@ -214,10 +210,6 @@ class HomeCms {
|
||||
return $settings['home_exclude_cats'];
|
||||
}
|
||||
|
||||
public static function homepage_tab_posts_per_page(): int {
|
||||
return 6;
|
||||
}
|
||||
|
||||
public static function get_paid_content_settings(): array {
|
||||
return PaymentRuntime::get_paid_content_settings();
|
||||
}
|
||||
@@ -299,9 +291,9 @@ class HomeCms {
|
||||
continue;
|
||||
}
|
||||
|
||||
$orderby = sanitize_key($tab['orderby'] ?? 'modified');
|
||||
if (!in_array($orderby, $allowed_orderby, true)) {
|
||||
$orderby = 'modified';
|
||||
$orderby = sanitize_key((string) ($tab['orderby'] ?? ''));
|
||||
if ($orderby !== '' && !in_array($orderby, $allowed_orderby, true)) {
|
||||
$orderby = '';
|
||||
}
|
||||
|
||||
$tabs[] = [
|
||||
|
||||
@@ -68,13 +68,6 @@ trait HomepageReader {
|
||||
return HomeCms::homepage_default_sort();
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the homepage tabs should use sticky/affix behaviour.
|
||||
*/
|
||||
public static function homepage_sticky_tabs_enabled(): bool {
|
||||
return HomeCms::homepage_sticky_tabs_enabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the main "latest posts" list is enabled on the homepage.
|
||||
*/
|
||||
@@ -130,13 +123,6 @@ trait HomepageReader {
|
||||
return HomeCms::home_exclude_category_ids();
|
||||
}
|
||||
|
||||
/**
|
||||
* Posts per page for each category tab.
|
||||
*/
|
||||
public static function homepage_tab_posts_per_page(): int {
|
||||
return HomeCms::homepage_tab_posts_per_page();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取页脚配色配置
|
||||
*/
|
||||
|
||||
@@ -112,15 +112,50 @@ test('user center navigation initializes once across auto_fun rescans', () => {
|
||||
assert.doesNotMatch(source, /name === 'vip' && !forceLoad\) forceLoad = true/);
|
||||
});
|
||||
|
||||
test('homepage sort refreshes one DOM panel without URL state', () => {
|
||||
const source = read('assets/js/homepage-fixed.js')
|
||||
test('homepage tabs refresh the original pane DOM through the runtime post_ajax pipeline', () => {
|
||||
const layout = read('inc/helpers/homepage/layout.php')
|
||||
const homepage = read('inc/helpers/aksrt-homepage.php')
|
||||
const controller = read('src/Admin/GlobalController.php')
|
||||
assert.match(source, /event\.preventDefault\(\)/)
|
||||
assert.match(source, /requestHomepagePanel\(activePanel, \{/)
|
||||
assert.doesNotMatch(source, /home_sort|replaceState|location\.search|data-sort-ajax|homepageSortAjax/)
|
||||
assert.doesNotMatch(homepage, /home_sort|data-sort-ajax|add_query_arg\(['"]home_sort['"]|homepage_sort_ajax_enabled/)
|
||||
assert.doesNotMatch(controller, /'page_url'\s*=>|'source'\s*=>/)
|
||||
|
||||
// legacy zib_index_tab_html 契约:data-toggle="tab" + data-ajax 栏目链接。
|
||||
assert.match(layout, /<a data-toggle="tab" data-ajax="/)
|
||||
assert.match(layout, /href="#index-tab-main"/)
|
||||
assert.match(layout, /class="index-tab affix-header-sm relative home-tab-nav-box mb10" offset-top="-8"/)
|
||||
// pane 本身是原位刷新容器:zib_index_tab('content') 契约。
|
||||
assert.match(layout, /class="posts-row ajaxpager tab-pane fade in active" id="index-tab-main"/)
|
||||
assert.match(layout, /class="ajaxpager tab-pane fade" id="index-tab-/)
|
||||
assert.match(layout, /<span class="post_ajax_trigger"><a class="ajax_load ajax-next ajax-open" href="/)
|
||||
assert.match(layout, /<div class="post_ajax_loader">/)
|
||||
// nofilter:栏目页响应不再输出筛选菜单,避免 win-ajax-replace 串页。
|
||||
assert.match(layout, /'nofilter' => 'true'/)
|
||||
// 不再有旁路刷新:REST 面板、骨架屏、面板 footer 全部移除。
|
||||
assert.equal(fs.existsSync(path.join(root, 'assets/js/homepage-fixed.js')), false)
|
||||
assert.doesNotMatch(layout, /data-home-tab-panel|aksrt-homepage__panel|aksrt-homepage__tab|requestHomepagePanel|data-sticky-tabs/)
|
||||
assert.doesNotMatch(controller, /homepage\/tab-posts|rest_homepage_tab_posts/)
|
||||
|
||||
// 排序菜单 = zib_ajax_option_menu('home') 契约:win-ajax-replace="filter" + ajax-next 链接。
|
||||
assert.match(homepage, /function aksrt_homepage_render_ajax_option_menu/)
|
||||
assert.match(homepage, /win-ajax-replace="filter"/)
|
||||
assert.match(homepage, /ajax-replace="true" class="' \. esc_attr\(\$_class\)/)
|
||||
assert.match(homepage, /!empty\(\$_GET\['nofilter'\]\)/)
|
||||
// 主查询吃 ?orderby=(legacy zib_sift_posts_per_orde),排序原位刷新才有效。
|
||||
assert.match(homepage, /function aksrt_homepage_get_request_sort/)
|
||||
assert.match(read('inc/helpers/homepage/content.php'), /aksrt_homepage_get_request_sort\(\)/)
|
||||
|
||||
// runtime 是 tab/排序的唯一引擎。
|
||||
const runtime = read('assets/js/runtime/main.js')
|
||||
assert.match(runtime, /_win\.bd\.on\('show\.bs\.tab', 'a\[data-ajax\]'/)
|
||||
assert.match(runtime, /function post_ajax\(/)
|
||||
// ajax-list.js 让出 runtime 管辖的控件,避免双请求。
|
||||
assert.match(read('assets/js/core/ajax-list.js'), /link\.closest\("\.ajax-option, \.post_ajax_trigger"\)/)
|
||||
})
|
||||
|
||||
test('archive streams nest pagination inside the ajaxpager for tab extraction', () => {
|
||||
const archive = read('inc/helpers/aksrt-archive.php')
|
||||
assert.match(archive, /append_inner_html/)
|
||||
assert.doesNotMatch(archive, /content-stream__footer/)
|
||||
assert.match(read('inc/helpers/posts-renderer/markup.php'), /append_inner_html/)
|
||||
assert.doesNotMatch(read('assets/js/core/pagination.js'), /data-home-tab-panel|content-stream__footer/)
|
||||
})
|
||||
test('HTML fragment injection announces post_ajax before auto_fun', () => {
|
||||
for (const file of ['assets/js/core/pagination.js', 'assets/js/author.js', 'assets/js/credits.js', 'assets/js/routes/user-center.js']) {
|
||||
|
||||
@@ -43,8 +43,6 @@ const cssBundles = {
|
||||
'assets/css/frontend/sidebar.css',
|
||||
'assets/css/frontend/breadcrumb.css',
|
||||
'assets/css/frontend/homepage-fixed/base.css',
|
||||
'assets/css/frontend/homepage-fixed/ajax-tab-skeleton-placeholder.css',
|
||||
'assets/css/frontend/homepage-fixed/ajax-tab-error-state.css',
|
||||
],
|
||||
'single.css': [
|
||||
'assets/css/frontend/legacy-utilities.css',
|
||||
|
||||
Reference in New Issue
Block a user