The top-bar theme switch was bound twice — core/theme.js attached a click
handler to #theme-toggle-desktop while runtime/main.js delegated click on
.toggle-theme, and both ship in main.min.js, so one press toggled twice and
the button looked dead.
Also realign the control with the reference:
- Drop the far modifier from fa-toggle-theme so the sun/moon glyphs resolve
against the Solid face at the reference weight instead of Regular.
- Restore .toggle-radius .fa/.icon to the reference form (left/right 0 +
auto margin only). The extra position/top/transform/size/flex block and
the > i selector were overriding the shared abs-* centering rule.
- Replace the per-ID bindings with one delegated listener so the floating
rail, which carries no id, keeps working.
- Remove dead theme.js queries for selectors no markup or stylesheet ships
(#theme-toggle, #dropdown-theme-toggle, .theme-icon-moon/.theme-icon-sun,
[data-action='toggle-theme'], .is-dark).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The theme was renamed Zibll/子比 → AKSRT → Jio, but upstream branding
survived the sweeps in CSS classes, the SVG sprite prefix, a persisted
widget field ID, JS events, admin Vue class names, test infrastructure
and docblocks.
Renames:
- zib-widget / zib-widget-wrap / zib-slider → jio-widget-box /
jio-widget-box-wrap / jio-slider-box (jio-widget is taken by the modern
widget shell, jio-box-* by the card primitives)
- zib-partners-scroll + zps-* → jio-partners-scroll + jps-*
- zib-combo-info-card + zci-* → jio-combo-info-card + jci-*
- zibsvg- → jiosvg-, including the exported picker helpers and the
fa-zibsvg- family-prefix guard
- zibpay_type → pay_type; the dual-read fallback in PostQuery collapses
to a single key
- [zibajax="submit"] dropped (no PHP emitter); zib_ajax.success →
jio_ajax.success
- aks-* admin Vue classes → jio-*
- zib_palette() → palette()
User-facing vendor traces are gone: the floating "more" button default no
longer ships a zibll.com link or 子比主题 marketing copy, the notice
widget ships no preset promo entries, and the four 官网教程 links are
removed from the post-list admin schema.
Test infrastructure renamed to neutral names (docker-compose.reference.yml,
Caddyfile, article-baseline.json, modern-widgets-contract.test.cjs) with
their DB/volume/env/slug identifiers following.
Kept intentionally, documented in tests/fixtures/README.md: the golden
fixture reference fingerprint (a SHA-256 record of an external directory,
read by validate-widget-golden / generate-widget-golden-fixture /
audit-widget-system), the doesNotMatch guards that prove the old tokens are
gone, and the reference theme's own meta key in the visual fixtures.
No backward-compat or data migration: saved widget configs holding old
icon keys or the old field ID silently lose them, per the project's
rewrite-over-compatibility rule.
Verified: 132/132 node contract tests, php tests/widget-system/run.php
(146 assertions), audit-admin-contracts, audit-psr4-paths and
validate-widget-golden all green; tracked bundles regenerated and in sync.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The mechanical rename turned AKSRT-theme into Jio-theme, but the
directory itself is Jio. Fix the three places that name the folder
(README install steps and tree, wp-cli-visual-fixtures usage comment,
DocsPage docs deep-link) and rebuild the SPA bundle.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
user_medal_args was declared as type=json without sanitize_type, so
sanitize_field_value() fell through to sanitize_text_field((string) $value)
and stored the literal string "Array". validate() has no json shape check,
so the save reported success.
Consequence: parse_medal_catalog() json_decoded "Array" into an empty
catalog, the dictionary came back empty, and user_context() dropped every
owned badge — the front end showed "获取徽章" and the grant modal listed
nothing, hiding both the newly added and the pre-existing badges.
Add the missing sanitize_type to match its sibling level/integral fields,
and guard sanitize_field_value() so structured container types can never
reach the scalar fallback again. Mirrors the declaration in the Vue schema.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
AksImageSelectField pinned every preview to a 60x60 box with
object-fit:cover, but these are wide layout strips: header layouts are
597x57 (10.47:1), the footer template is 800x190 (4.21:1) and the slide
align set is 200x101. A 10:1 strip inside a square crop keeps ~6% of its
width, so the layout it is supposed to illustrate is unrecognisable.
Constrain the width instead and let the height follow, which is what the
reference theme's CSF image_select does (max-width:100%; height:auto).
Each field now declares the width that suits its images, and an option
may still override it: header 200, footer 240, slide align 160, mobile
header 120.
Only presentation changed. No image files and no stored values moved,
so existing settings are unaffected.
generate-fa5-icons.php read fa-{brands,regular,solid}.svg from
webfonts/, but only woff/woff2 ship with the theme, so the generator
died on file_get_contents() and the committed fa5-icons.php could not
be regenerated from what the theme actually distributes.
Decode the style split from each shipped woff's cmap table instead.
The split has to come from the font: FA5 assigns different drawings to
the same codepoint per style, so fas/far/fab membership is unanswerable
from the CSS alone. Output is byte-identical to the committed catalog
(1001/151/456), so the picker is unaffected.
all.min.css also declared eot / eot?#iefix / ttf / svg fallbacks for all
three families while webfonts/ holds only woff2 + woff, so a browser
that stops at woff requested six files that do not exist. Add
tools/strip-fa5-legacy-fonts.mjs to keep the src: list to what ships;
it is idempotent and touches nothing but the @font-face blocks.
assets/admin/public/images/header-layout duplicated
assets/images/header-layout byte for byte (all five PNGs, matching
md5). The directory only existed because assets/admin/public is Vite's
default publicDir, so every build copied it into build/images.
Nothing referenced it: SchemaPageDisplay builds its preview URLs from
assets/images/header-layout via self::asset(), and a repo-wide search
finds no reference to public/images anywhere. Remove the source and let
build/images stop being regenerated.
- Overview page: realtime today vs. same time yesterday, 6 KPI cards with
period-over-period deltas, trend (paid / net / refund curves + order count
line), category curves, payment method donut, top 10 paid content,
conversion / close / refund rates, todos and shortcuts
- Date presets, custom range and category filter via
GET aksrt/v1/admin/pay-overview (manage_options + wp_rest nonce)
- Metrics: paid amount by paid date including later-refunded orders, refunds
by refund date, net = paid - refund; CNY only, points and recharge excluded,
foreign-currency orders listed separately; integer cents internally
- Daily records cached per month in transients (today/yesterday live),
invalidated on order status change and on purge
- ECharts 6.1.0 subset bundled to assets/js/runtime/libs/echarts-pay.min.js
(npm run build:pay-charts), loaded only on the overview page
- Split payment-attempt methods out of OrderRepositoryCore into
OrderRepositoryAttempts; remove dead get_stats(), cash_decimal(),
Order::get_stats() and the old .aksrt-native-links styles
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Split PayWithdrawals into shell + PayWithdrawalsList flat sibling trait
- Add process/policy callout, open/paid/fee stats, status views with counts
- Filter by source and payout method; reset keeps the status view
- Show net payout with gross/fee breakdown, copyable payee, note column
- Replace inline select form with per-row actions and a confirm dialog;
reject requires a reason; double-submit guard; retry reuses the
idempotency key; redirect back preserving filters and paging
- Withdrawal: add get_status_counts() and method filter; get_stats() now
returns open_gross / paid_net / paid_fee
- Remove unused REST routes (/payment/withdrawals, /transition),
admin_withdrawals(), update_status(), has_open_withdrawal(),
count_open(), resolve_gross_amount()
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Always render the checkbox column and bulk bar; disable with a reason
instead of hiding when settlement is off or the page has no pending rows
- Replace the batch-settle button with a bulk action select (settle / delete)
plus apply, matching the charge cards and invite codes pages
- Add per-row delete for pending records and Revenue::delete_pending(),
guarded by status = 'pending' so settled ledger-backed rows are never removed
- Report done / failed counts for bulk settle and delete
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Add shared .aksrt-native-bulk row that locks select and button to the
same height, font size and line height
- Apply it to the charge cards and invite codes bulk action rows
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Move "新建优惠码" / "批量生成" into header-launched <dialog>s
- Extract forms into PayCouponsForms trait with shared rule fields,
hints, validation and currency/percent unit switching
- Generated codes card gets a copy-all button; list codes copy on click
- Drop old inline forms, render_generated_dump and the unread
aksrt_coupon_generated redirect arg
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Rebuild aksrt_pay_products as list + in-page quick settings dialog
(pay type, limit, cash/points prices, sales float, coupon, order expiry, copy)
- Query by _aksrt_pay_type with real pagination; drop order-summary fallback
and the duplicate "Meta 销量" column
- Centralize pay meta writes in DomainModel::persist_pay_meta(); stop writing
unread _aksrt_pay_modo / _aksrt_pay_limit keys
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Keep ticket info at its natural height and let the internal notes card fill
the remaining sidebar height, so only the notes list scrolls.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Share one --aksrt-ticket-pane-height between the conversation panel and
the sidebar cap so both columns line up, and drop the sidebar sticky
offset that no longer matches the pane height.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Put the reply composer at the bottom of the conversation card so the
timeline and composer form one viewport-height panel; the send button is
visible on load and Ctrl/Cmd+Enter submits. Internal notes now open in a
dialog instead of expanding inline, so the sidebar no longer grows.
Remove the shared ticket_composer helper and the inline note expansion CSS;
both dialogs share ticket_dialog_head.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Move "代客提交工单" back into a native <dialog> on the ticket list while
the ticket workspace stays a full page. Closing asks before discarding
input, ignores backdrop clicks, resets the form and returns focus; an
uncertain create result keeps the form locked behind "重新加载".
Remove the ?view=new create page route and its styles.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ticket handling on users.php?page=aksrt_tickets no longer uses dialogs.
The list, the workspace (?id=N) and the assisted create form (?view=new)
are server-rendered page views that carry the list filters and page
for going back. Writes still go through the ticket REST routes; on
success the page reloads with a native notice, and unsent drafts in
other forms survive the reload via sessionStorage. Uncertain or
conflicting writes lock every form and only offer a reload.
Remove dead code: UsersMenusTicketsDialogs, the aksrt_ticket_view AJAX
read and its nonce, dialog CSS/JS (backdrop, scroll lock, focus return,
read races) and the dialog runtime test. Fix the create link carrying
an unclamped page number on out-of-range list pages.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replace the type/method tab rows with status views backed by one GROUP BY
count, move filters into a single toolbar card, show gateway names, keep
list context across detail and actions, and split the detail page into a
summary/timeline column and an actions/buyer/note sidebar. Confirmations
move to admin-orders.js; PayOrders splits into flat List/Detail traits.
Remove dead code: unused Order AJAX endpoints and init(), get_orders_count(),
shipping flash codes, and the legacy raw-note fallback.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Show only the latest three notes and fold older ones into a details
toggle, collapse the note composer to one line until focused, and cap
the sidebar height to the dialog body so its controls stay reachable.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Render the original question and replies as one chat-style timeline,
merge editor and toolbar into a shared composer for replies and notes,
and refresh sidebar cards. Remove superseded renderers and selectors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Edit status, department and assignee directly in ticket information, remove the redundant handling card and its layout rules, and cover editable and closed-ticket rendering.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Keep the ticket number and status in the sidebar only, remove the unused header description payload and bindings, and update dialog regression coverage.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Move on-behalf ticket creation into a header dialog and load ticket handling on demand. Reuse the admin REST write path, preserve drafts and filters, and cover dialog and server boundaries with regression tests.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Store readable category snapshots separately from details and evidence, validate report categories, and preserve context in admin displays and moderation actions. Widen report categories to TEXT and bump the schema to 3.2.0 without legacy data conversion.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Use highlight-only reason choices, show the associated target on one line, and replace inline submission progress with shared toast feedback.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replace inline identity review forms with focused detail and review dialogs, improve list filters and caching, and align evidence permissions and deletion feedback. Add contract and runtime regression coverage.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Unify status filters, search, bulk actions and pagination in one invite list card. Remove the standalone filter summary and preserve usable search widths on small screens, with structural regression coverage.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replace standalone add and export views with accessible dialogs, refine list interactions, and remove obsolete paths and unused counts. Fix filtered totals and reject oversized imports without truncation, with regression coverage.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Center the operations heading and row buttons, with 20px padding on both
sides of the cell. Add a regression contract for alignment and spacing.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add a dedicated operations column for viewing, marking read and deleting
messages. Keep the message cell focused on its title, excerpt and ID;
adjust column widths and empty-state colspan with regression coverage.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add message details, per-row actions, selection-aware bulk controls and
confirmation dialogs. Merge filters into the list card and link overview
statistics to the matching views with site-timezone today filtering.
Improve the compose dialog with Unicode character counters, recipient mode
segments, role counts and explicit broadcast confirmation verified against
the resolved role and recipient count on submission. Split rendering into
focused sibling traits and cover rendering, handlers and UI interactions.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replace the inline <details> compose card on users.php?page=aksrt_messages
with a primary header button that opens a native <dialog>. NativeUi::header()
gains dialog-type actions via NativeUi::button_dialog(). The dialog reopens
automatically after a failed send.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Replace per-row inline <details> forms and the separate bulk form with a
single <dialog> shared by single-user and bulk adjustments
- Add stats row, styled tabs, date range filter with reset, sortable expiry
- Show fallback tier, remaining time, and disable unavailable operations
- History tab: labelled operation/status badges, avatars, local time,
batch marker and error message
- Move inline script/onclick to assets/js/admin-vip.js; add vip.css
- Surface the service error message when every user fails
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add NativeUi helper + native-ui.css (tokens mirror the SPA Naive UI theme)
and move the pay center, orders, products, coupons, charge cards, income,
withdrawals, tickets, invite codes, VIP, verify, messages and report/ban
pages onto shared header, stat cards, cards, filters, badges and empty
states. Remove inline styles and dead helpers; split PayChargeCards into
sibling traits to stay under the file size limit.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Replace transfer modal/admin-post flow with reference-style AJAX
export/import/template dialogs (admin-transfer.js, TransferController)
- Customizer "移出模块" action, reference lazy form loading with t-notice
- Common fields use reference labels, dependencies, compact/inline rows,
top/bottom-only extra spacing; form header with description/reminder
- Remove placement hint, template preview and legacy transfer code
- Fix widget audit (current_datetime stub, honor catalog common flags)
and regenerate stale golden fixtures for posts_toc, quote, posts
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>