mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-17 18:16:15 +08:00
feat: improve admin build (#14485)
#### PR Dependency Tree * **PR #14485** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Chores** * Admin static assets now served under /admin for self-hosted installs * CLI is directly executable from the command line * Build tooling supports a configurable self-hosted public path * Updated admin package script for adding UI components * Added a PostCSS dependency and plugin to the build toolchain for admin builds * **Style** * Switched queue module to a local queuedash stylesheet, added queuedash Tailwind layer, and scoped queuedash styles for the admin UI * **Bug Fixes** * Improved error propagation in the Electron renderer * Migration compatibility to repair a legacy checksum during native storage upgrades * **Tests** * Added tests covering the migration repair flow <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -1,19 +1,98 @@
|
||||
import '@queuedash/ui/dist/styles.css';
|
||||
import './queue.css';
|
||||
import './queuedash.css';
|
||||
|
||||
import { QueueDashApp } from '@queuedash/ui';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { Header } from '../header';
|
||||
|
||||
const QUEUEDASH_SCOPE_CLASS = 'affine-queuedash';
|
||||
const PORTAL_CONTENT_SELECTOR =
|
||||
'.react-aria-ModalOverlay, .react-aria-Menu, [data-rac][data-placement][data-trigger]';
|
||||
|
||||
export function QueuePage() {
|
||||
useEffect(() => {
|
||||
const marked = new Set<HTMLElement>();
|
||||
|
||||
const markScopeRoot = (el: Element) => {
|
||||
if (!(el instanceof HTMLElement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (el.classList.contains(QUEUEDASH_SCOPE_CLASS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
el.classList.add(QUEUEDASH_SCOPE_CLASS);
|
||||
marked.add(el);
|
||||
};
|
||||
|
||||
const isPortalContent = (el: Element) => {
|
||||
return (
|
||||
el.matches(PORTAL_CONTENT_SELECTOR) ||
|
||||
!!el.querySelector(PORTAL_CONTENT_SELECTOR)
|
||||
);
|
||||
};
|
||||
|
||||
const markIfPortalRoot = (el: Element) => {
|
||||
if (!isPortalContent(el)) {
|
||||
return;
|
||||
}
|
||||
markScopeRoot(el);
|
||||
};
|
||||
|
||||
const getBodyChildRoot = (el: Element) => {
|
||||
let current: Element | null = el;
|
||||
while (
|
||||
current?.parentElement &&
|
||||
current.parentElement !== document.body
|
||||
) {
|
||||
current = current.parentElement;
|
||||
}
|
||||
return current?.parentElement === document.body ? current : null;
|
||||
};
|
||||
|
||||
Array.from(document.body.children).forEach(child => {
|
||||
if (child.id === 'app') {
|
||||
return;
|
||||
}
|
||||
markIfPortalRoot(child);
|
||||
});
|
||||
|
||||
const observer = new MutationObserver(mutations => {
|
||||
const appRoot = document.getElementById('app');
|
||||
for (const mutation of mutations) {
|
||||
for (const node of mutation.addedNodes) {
|
||||
if (!(node instanceof Element)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const root = getBodyChildRoot(node) ?? node;
|
||||
if (appRoot && root === appRoot) {
|
||||
continue;
|
||||
}
|
||||
markIfPortalRoot(root);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
observer.observe(document.body, { childList: true, subtree: true });
|
||||
|
||||
return () => {
|
||||
observer.disconnect();
|
||||
marked.forEach(el => el.classList.remove(QUEUEDASH_SCOPE_CLASS));
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="h-dvh flex-1 flex-col flex overflow-hidden">
|
||||
<Header title="Queue" />
|
||||
<div className="flex-1 overflow-hidden">
|
||||
<QueueDashApp
|
||||
apiUrl={`${environment.subPath}/api/queue/trpc`}
|
||||
basename="/admin/queue"
|
||||
/>
|
||||
<div className={`${QUEUEDASH_SCOPE_CLASS} h-full`}>
|
||||
<QueueDashApp
|
||||
apiUrl={`${environment.subPath}/api/queue/trpc`}
|
||||
basename="/admin/queue"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
/* Scoped queuedash modal alignment */
|
||||
|
||||
.react-aria-ModalOverlay section[role='dialog'] {
|
||||
transform: unset;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
@import '@queuedash/ui/dist/styles.css' layer(queuedash);
|
||||
|
||||
/*
|
||||
* QueueDash UI is built with Tailwind v3 (translate via `transform`), while AFFiNE Admin
|
||||
* uses Tailwind v4 (translate via the individual `translate` property). When QueueDash
|
||||
* overlays are portaled to `document.body`, both utility sets can apply at once and
|
||||
* result in double transforms (mis-centered dialogs, etc). Reset individual transform
|
||||
* properties within the queuedash scope so Tailwind v3 styles win.
|
||||
*/
|
||||
:where(.affine-queuedash) * {
|
||||
translate: none;
|
||||
rotate: none;
|
||||
scale: none;
|
||||
}
|
||||
Reference in New Issue
Block a user