fix(ux): surface hidden notices, bound report waits, add root boundaries
Framework-level UX fixes found while auditing staging (BUG-216..220).
- chat: route 44 previously discarded composer notices to sonner with
dedupe, so recovery, cancel and archive feedback is actually visible
(BUG-216)
- chat: anchor stream auto-scroll to bottom proximity and add a
jump-to-latest control, so reading history is no longer interrupted
on every token (BUG-218)
- reports: replace the silent 120s poll cutoff with an explicit
timed-out state, an 8m budget, stepped backoff and an elapsed
counter (BUG-217)
- reports: pause polling while the tab is hidden, via a shared hook
- app: add root error, global-error and not-found boundaries (BUG-219)
- admin: add antd SSR style extraction and the React 19 render adapter,
and move admin-only css out of the global stylesheet (BUG-220)
- membership: run bootstrap fetches concurrently and pause payment
polling while hidden
- build: configure optimizePackageImports
Verified on top of 2d370f2e: tsc, eslint, next build, and the related
frontend contract suites.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
.admin-app-shell {
|
||||
min-height: 100dvh;
|
||||
background: #f3f2ee;
|
||||
color: #1d1d1f;
|
||||
font-family: var(--font-body);
|
||||
}
|
||||
.admin-app-shell .ant-layout { background: #f3f2ee; }
|
||||
.admin-app-shell .ant-layout-sider { border-right: 1px solid #d8d6cf; box-shadow: none !important; }
|
||||
.admin-app-shell .ant-layout-header { border-bottom: 1px solid #d8d6cf; box-shadow: none !important; }
|
||||
.admin-app-shell .ant-layout-content { padding: 22px; }
|
||||
.admin-app-shell .ant-menu { border-inline-end: 0 !important; background: transparent !important; }
|
||||
.admin-app-shell .ant-menu-item, .admin-app-shell .ant-menu-submenu-title { margin-inline: 8px; width: calc(100% - 16px); }
|
||||
.admin-app-shell .ant-card { border-color: #d8d6cf; box-shadow: none !important; }
|
||||
.admin-app-shell .ant-card-head { border-bottom-color: #d8d6cf; }
|
||||
.admin-app-shell .ant-card .ant-card { border-radius: 0; }
|
||||
.admin-app-shell .ant-card .ant-card:not(:last-child) { border-bottom: 0; }
|
||||
.admin-app-shell .ant-list-bordered { border-color: #d8d6cf; border-radius: 6px; }
|
||||
.admin-app-shell .ant-table-wrapper .ant-table { background: #fbfaf7; }
|
||||
.admin-app-shell .ant-table-wrapper .ant-table-container { border-radius: 6px; }
|
||||
.admin-app-shell .ant-table-wrapper .ant-table-thead > tr > th { font-size: 12px; font-weight: 650; }
|
||||
.admin-app-shell .ant-table-wrapper .ant-table-cell { line-height: 1.45; }
|
||||
.admin-app-shell .ant-tag { margin-inline-end: 4px; border-radius: 4px; font-weight: 550; }
|
||||
.admin-app-shell .ant-alert { border-radius: 6px; box-shadow: none; }
|
||||
.admin-app-shell .ant-statistic-title { color: #5f5f59; font-size: 12px; }
|
||||
.admin-app-shell .ant-statistic-content { font-size: 22px; font-weight: 650; }
|
||||
.admin-app-shell .ant-typography h1, .admin-app-shell h1.ant-typography { font-family: var(--font-body); font-size: 26px; font-weight: 680; letter-spacing: -.025em; }
|
||||
.admin-app-shell .ant-typography h2, .admin-app-shell h2.ant-typography { font-family: var(--font-body); font-size: 21px; font-weight: 650; letter-spacing: -.015em; }
|
||||
.admin-app-shell .ant-typography h3, .admin-app-shell h3.ant-typography { font-family: var(--font-body); font-size: 17px; font-weight: 650; }
|
||||
.admin-app-shell code { font-family: var(--font-mono); }
|
||||
.admin-text-list { max-width: 680px; color: #5f5f59; line-height: 1.65; white-space: normal; overflow-wrap: anywhere; }
|
||||
.admin-loading { min-height: 100dvh; display: grid; place-content: center; justify-items: center; gap: 12px; background: #f3f2ee; color: #5f5f59; }
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.admin-app-shell .ant-layout-content { padding: 14px; }
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
import "@refinedev/antd/dist/reset.css";
|
||||
import "antd/dist/reset.css";
|
||||
import "./admin.css";
|
||||
import type { ReactNode } from "react";
|
||||
import { forbidden, redirect } from "next/navigation";
|
||||
|
||||
import { AdminAntdRegistry } from "@/components/admin/admin-antd-registry";
|
||||
import { AdminApp } from "@/components/admin/admin-app";
|
||||
import { AdminAuthorizationError, requireAdminSession } from "@/lib/admin/auth";
|
||||
import { resolveAdminPageAccessFailure } from "@/lib/admin/page-access";
|
||||
@@ -21,5 +22,9 @@ export default async function AdminLayout({ children }: { children: ReactNode })
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
return <AdminApp>{children}</AdminApp>;
|
||||
return (
|
||||
<AdminAntdRegistry>
|
||||
<AdminApp>{children}</AdminApp>
|
||||
</AdminAntdRegistry>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user