feat(widgets): replicate 12 reference widgets for full Zibll parity

- rewrite schemas for posts, tab_posts, oneline_posts, hot_posts,
  term_cards, term_aggregation, media_cards, combo_info, partners,
  recent_comments, posts_toc and slider_media_combo to mirror the
  modern reference modules field by field (options, defaults,
  dependencies, min/max/step, subheadings)
- port reference renderers: hot ranking with TOP badges, category
  aggregation card, graphic cover cards, partners CSS marquee,
  combo info cards with auto band palette, recent comment list
- rename 分类与标签聚合卡片 to 分类聚合卡片 and restrict it to
  categories (no tags/topics branch in this project)
- drop topics filter fields and the topics query branch; align
  orderby value domain with supported post meta
- add searchable sortable terms admin field type and spinner unit
  suffix rendering
- unify widget pagination and lazy loading on the REST client with
  the runtime-owned ias reveal trigger; remove the legacy
  post_ajax_trigger dual path
- align section-navs TOC with the reference contract (wznav ids,
  3-heading minimum, zib-widget box)
This commit is contained in:
2026-09-05 11:28:00 +08:00
parent 9dc278bd83
commit b639d57c5b
25 changed files with 1388 additions and 446 deletions
+12 -3
View File
@@ -14,7 +14,7 @@ final class FieldSchema {
return [
'text', 'textarea', 'number', 'spinner', 'slider', 'switcher', 'radio',
'button_set', 'select', 'checkbox', 'color', 'palette', 'image_select', 'icon', 'upload',
'link', 'spacing', 'background', 'group', 'fieldset', 'accordion',
'link', 'spacing', 'background', 'group', 'fieldset', 'accordion', 'terms',
'content', 'subheading', 'submessage',
];
}
@@ -63,6 +63,8 @@ final class FieldSchema {
return self::choice($field, $value);
case 'checkbox':
return self::checkbox($field, $value);
case 'terms':
return self::terms($value);
case 'link':
return self::link($value);
case 'spacing':
@@ -103,7 +105,7 @@ final class FieldSchema {
if ($type === 'switcher') {
return false;
}
if (in_array($type, ['group', 'checkbox'], true)) {
if (in_array($type, ['group', 'checkbox', 'terms'], true)) {
return [];
}
if (in_array($type, ['link', 'spacing', 'background', 'fieldset', 'accordion'], true)) {
@@ -121,7 +123,9 @@ final class FieldSchema {
$number = min((float) $field['max'], $number);
}
$step = (float) ($field['step'] ?? 1);
return $step >= 1 ? (int) round($number) : $number;
// Whole values stay int so JSON round trips keep normalize identity
// even for fractional-step fields (e.g. partners speed 0.1–10s).
return $step >= 1 || fmod($number, 1.0) === 0.0 ? (int) round($number) : $number;
}
private static function choice(array $field, $value) {
@@ -143,6 +147,11 @@ final class FieldSchema {
return array_values(array_filter(array_map('strval', $values), static fn($item) => array_key_exists($item, $options)));
}
private static function terms($value): array {
$values = is_array($value) ? $value : (preg_split('/[,,\s]+/', (string) $value) ?: []);
return array_values(array_unique(array_filter(array_map('absint', $values))));
}
private static function link($value): array {
$value = is_array($value) ? $value : [];
return [