Polish SEO workspace controls
This commit is contained in:
parent
08894288bc
commit
5ec8e7e691
|
|
@ -1756,7 +1756,16 @@ export function App() {
|
||||||
function handlePreviewMessage(event: MessageEvent) {
|
function handlePreviewMessage(event: MessageEvent) {
|
||||||
const data = event.data;
|
const data = event.data;
|
||||||
|
|
||||||
if (!data || typeof data !== "object" || data.type !== "seo-mode:preview-markers") {
|
if (!data || typeof data !== "object") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.type === "seo-mode:preview-pointerdown") {
|
||||||
|
closeWorkspacePageMenus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.type !== "seo-mode:preview-markers") {
|
||||||
if (data?.type === "seo-mode:active-scope-page") {
|
if (data?.type === "seo-mode:active-scope-page") {
|
||||||
const sourceWorkspaceKey = typeof data.workspaceKey === "string" ? data.workspaceKey : "";
|
const sourceWorkspaceKey = typeof data.workspaceKey === "string" ? data.workspaceKey : "";
|
||||||
const pageId = typeof data.pageId === "string" ? data.pageId : "";
|
const pageId = typeof data.pageId === "string" ? data.pageId : "";
|
||||||
|
|
@ -2597,6 +2606,42 @@ export function App() {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function closeWorkspacePageMenus() {
|
||||||
|
setWorkspacePageMenus((currentMenus) => {
|
||||||
|
let hasOpenMenu = false;
|
||||||
|
const nextMenus = { ...currentMenus };
|
||||||
|
|
||||||
|
Object.keys(nextMenus).forEach((workspaceKey) => {
|
||||||
|
if (nextMenus[workspaceKey]) {
|
||||||
|
nextMenus[workspaceKey] = false;
|
||||||
|
hasOpenMenu = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return hasOpenMenu ? nextMenus : currentMenus;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!Object.values(workspacePageMenus).some(Boolean)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDocumentPointerDown(event: PointerEvent) {
|
||||||
|
if (event.target instanceof Element && event.target.closest(".workspace-page-control")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
closeWorkspacePageMenus();
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener("pointerdown", handleDocumentPointerDown, true);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener("pointerdown", handleDocumentPointerDown, true);
|
||||||
|
};
|
||||||
|
}, [workspacePageMenus]);
|
||||||
|
|
||||||
function updateWorkspacePreviewMarkers(
|
function updateWorkspacePreviewMarkers(
|
||||||
workspaceKey: string,
|
workspaceKey: string,
|
||||||
targets: WorkspaceTarget[],
|
targets: WorkspaceTarget[],
|
||||||
|
|
|
||||||
|
|
@ -1301,16 +1301,19 @@ export default function ProjectScopeFlow({
|
||||||
return (
|
return (
|
||||||
<section className="project-scope-flow-panel">
|
<section className="project-scope-flow-panel">
|
||||||
<div className="project-scope-flow-head">
|
<div className="project-scope-flow-head">
|
||||||
<div>
|
<strong>Конфигурация проекта</strong>
|
||||||
<strong>Конфигурация проекта</strong>
|
</div>
|
||||||
<small>
|
<div className="project-scope-flow-controls">
|
||||||
Выбрано рабочих зон {stats.selectedWorkspaceItems}: посадочных {stats.selectedIndexable}/{stats.indexable},
|
<div className="project-scope-flow-legend">
|
||||||
секций {stats.selectedSections}/{stats.enabledSections}, админка {stats.selectedAdmin}/{stats.admin},
|
{groups.map((group) => (
|
||||||
техслой {stats.selectedTechnical}/{stats.technical}.
|
<span className={`scope-legend-item ${group.scope}`} key={group.scope}>
|
||||||
</small>
|
<FileText size={13} />
|
||||||
|
{scopeGroupNames[group.scope]} · {group.selected}/{group.count}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div className="project-scope-flow-actions">
|
<div className="project-scope-flow-actions">
|
||||||
<button disabled={isBusy} onClick={onApplyRecommendedScope} type="button">
|
<button className="active" disabled={isBusy} onClick={onApplyRecommendedScope} type="button">
|
||||||
SEO scope
|
SEO scope
|
||||||
</button>
|
</button>
|
||||||
<button disabled={isBusy || stats.selectedWorkspaceItems === 0} onClick={onClearSelection} type="button">
|
<button disabled={isBusy || stats.selectedWorkspaceItems === 0} onClick={onClearSelection} type="button">
|
||||||
|
|
@ -1318,14 +1321,6 @@ export default function ProjectScopeFlow({
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="project-scope-flow-legend">
|
|
||||||
{groups.map((group) => (
|
|
||||||
<span className={`scope-legend-item ${group.scope}`} key={group.scope}>
|
|
||||||
<FileText size={13} />
|
|
||||||
{scopeGroupNames[group.scope]} · {group.selected}/{group.count}
|
|
||||||
</span>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
<div className="project-scope-flow-canvas">
|
<div className="project-scope-flow-canvas">
|
||||||
<ReactFlowProvider>
|
<ReactFlowProvider>
|
||||||
<ReactFlow
|
<ReactFlow
|
||||||
|
|
|
||||||
|
|
@ -4543,16 +4543,8 @@ input[type="checkbox"] {
|
||||||
}
|
}
|
||||||
|
|
||||||
.project-scope-flow-head {
|
.project-scope-flow-head {
|
||||||
display: flex;
|
display: block;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
|
||||||
gap: 14px;
|
|
||||||
min-width: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.project-scope-flow-head > div:first-child {
|
|
||||||
display: grid;
|
|
||||||
gap: 4px;
|
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4562,10 +4554,12 @@ input[type="checkbox"] {
|
||||||
font-weight: 780;
|
font-weight: 780;
|
||||||
}
|
}
|
||||||
|
|
||||||
.project-scope-flow-head small {
|
.project-scope-flow-controls {
|
||||||
color: var(--muted);
|
display: flex;
|
||||||
font-size: 13px;
|
flex-wrap: wrap;
|
||||||
line-height: 1.35;
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.project-scope-flow-actions {
|
.project-scope-flow-actions {
|
||||||
|
|
@ -4576,26 +4570,39 @@ input[type="checkbox"] {
|
||||||
}
|
}
|
||||||
|
|
||||||
.project-scope-flow-actions button {
|
.project-scope-flow-actions button {
|
||||||
min-height: 32px;
|
display: inline-flex;
|
||||||
padding: 0 12px;
|
align-items: center;
|
||||||
color: #202522;
|
justify-content: center;
|
||||||
|
gap: 8px;
|
||||||
|
min-height: 38px;
|
||||||
|
padding: 0 13px;
|
||||||
|
color: var(--ink);
|
||||||
background: #ffffff;
|
background: #ffffff;
|
||||||
border: 1px solid rgba(0, 0, 0, 0.14);
|
border: 1px solid var(--line);
|
||||||
border-radius: 8px;
|
border-radius: 999px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
font-weight: 780;
|
font-weight: 700;
|
||||||
|
line-height: 1;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.project-scope-flow-actions button:first-child {
|
.project-scope-flow-actions button:hover:not(:disabled) {
|
||||||
|
border-color: rgba(24, 32, 29, 0.2);
|
||||||
|
background: #fafafa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-scope-flow-actions button.active {
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
background: #202522;
|
background: var(--ink);
|
||||||
border-color: #202522;
|
border-color: var(--ink);
|
||||||
}
|
}
|
||||||
|
|
||||||
.project-scope-flow-actions button:disabled {
|
.project-scope-flow-actions button:disabled {
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
opacity: 0.48;
|
color: var(--muted);
|
||||||
|
background: #f6f6f7;
|
||||||
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.project-scope-flow-legend {
|
.project-scope-flow-legend {
|
||||||
|
|
@ -4607,20 +4614,23 @@ input[type="checkbox"] {
|
||||||
.scope-legend-item {
|
.scope-legend-item {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 6px;
|
justify-content: center;
|
||||||
min-height: 28px;
|
gap: 8px;
|
||||||
padding: 0 9px;
|
min-height: 38px;
|
||||||
color: #4d5753;
|
padding: 0 13px;
|
||||||
background: #ffffff;
|
color: var(--muted);
|
||||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
background: #f6f6f7;
|
||||||
border-radius: 8px;
|
border: 1px solid var(--line);
|
||||||
font-size: 12px;
|
border-radius: 999px;
|
||||||
font-weight: 720;
|
font-size: 13px;
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 1;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.scope-legend-item.indexable_page {
|
.scope-legend-item.indexable_page {
|
||||||
color: #63300d;
|
color: var(--muted);
|
||||||
border-color: rgba(242, 122, 26, 0.28);
|
border-color: var(--line);
|
||||||
}
|
}
|
||||||
|
|
||||||
.project-scope-flow-canvas {
|
.project-scope-flow-canvas {
|
||||||
|
|
@ -5268,15 +5278,18 @@ input[type="checkbox"] {
|
||||||
.page-audit-summary span {
|
.page-audit-summary span {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 6px;
|
justify-content: center;
|
||||||
min-height: 30px;
|
gap: 8px;
|
||||||
padding: 0 10px;
|
min-height: 38px;
|
||||||
color: var(--ink);
|
padding: 0 13px;
|
||||||
background: rgba(255, 255, 255, 0.72);
|
color: var(--muted);
|
||||||
|
background: #f6f6f7;
|
||||||
border: 1px solid var(--line);
|
border: 1px solid var(--line);
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
font-weight: 600;
|
font-weight: 700;
|
||||||
|
line-height: 1;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-audit-list {
|
.page-audit-list {
|
||||||
|
|
@ -6493,14 +6506,13 @@ input[type="checkbox"] {
|
||||||
right: 0;
|
right: 0;
|
||||||
z-index: 30;
|
z-index: 30;
|
||||||
display: grid;
|
display: grid;
|
||||||
|
grid-template-rows: auto minmax(0, 1fr);
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
width: min(380px, calc(100vw - 48px));
|
width: min(380px, calc(100vw - 48px));
|
||||||
max-height: min(420px, calc(100vh - 240px));
|
max-height: min(480px, calc(100vh - 180px));
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background:
|
background: rgba(255, 255, 255, 0.97);
|
||||||
linear-gradient(180deg, rgba(255, 255, 255, 0.88), rgba(255, 255, 255, 0.72)),
|
|
||||||
rgba(255, 255, 255, 0.94);
|
|
||||||
border: 1px solid rgba(24, 32, 29, 0.1);
|
border: 1px solid rgba(24, 32, 29, 0.1);
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
box-shadow: 0 22px 70px rgba(24, 32, 29, 0.16);
|
box-shadow: 0 22px 70px rgba(24, 32, 29, 0.16);
|
||||||
|
|
@ -6533,8 +6545,12 @@ input[type="checkbox"] {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 7px;
|
gap: 7px;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
overflow: auto;
|
max-height: min(360px, calc(100vh - 260px));
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
overscroll-behavior: contain;
|
||||||
padding-right: 2px;
|
padding-right: 2px;
|
||||||
|
scrollbar-gutter: stable;
|
||||||
}
|
}
|
||||||
|
|
||||||
.workspace-page-menu-list button {
|
.workspace-page-menu-list button {
|
||||||
|
|
@ -6552,8 +6568,14 @@ input[type="checkbox"] {
|
||||||
|
|
||||||
.workspace-page-menu-list button:hover,
|
.workspace-page-menu-list button:hover,
|
||||||
.workspace-page-menu-list button.active {
|
.workspace-page-menu-list button.active {
|
||||||
background: #fffaf5;
|
background: #f6f6f7;
|
||||||
border-color: rgba(242, 122, 26, 0.32);
|
border-color: rgba(24, 32, 29, 0.16);
|
||||||
|
}
|
||||||
|
|
||||||
|
.workspace-page-menu-list button.active {
|
||||||
|
color: #ffffff;
|
||||||
|
background: var(--ink);
|
||||||
|
border-color: var(--ink);
|
||||||
}
|
}
|
||||||
|
|
||||||
.workspace-page-menu-list button span {
|
.workspace-page-menu-list button span {
|
||||||
|
|
@ -6562,8 +6584,8 @@ input[type="checkbox"] {
|
||||||
height: 26px;
|
height: 26px;
|
||||||
display: grid;
|
display: grid;
|
||||||
place-items: center;
|
place-items: center;
|
||||||
color: #fff;
|
color: #ffffff;
|
||||||
background: var(--accent);
|
background: var(--ink);
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: 850;
|
font-weight: 850;
|
||||||
|
|
@ -6605,6 +6627,21 @@ input[type="checkbox"] {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.workspace-page-menu-list button.active span {
|
||||||
|
color: var(--ink);
|
||||||
|
background: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.workspace-page-menu-list button.active strong,
|
||||||
|
.workspace-page-menu-list button.active small {
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.workspace-page-menu-list button.active em {
|
||||||
|
color: #ffffff;
|
||||||
|
background: rgba(255, 255, 255, 0.16);
|
||||||
|
}
|
||||||
|
|
||||||
.workspace-current-page-actions .workspace-preview-mode-switch {
|
.workspace-current-page-actions .workspace-preview-mode-switch {
|
||||||
min-height: 38px;
|
min-height: 38px;
|
||||||
background: #fff !important;
|
background: #fff !important;
|
||||||
|
|
|
||||||
|
|
@ -596,6 +596,17 @@ function buildPreviewBridgeScript() {
|
||||||
}, "*");
|
}, "*");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function reportPreviewPointerDown() {
|
||||||
|
if (!state.workspaceKey) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.parent?.postMessage({
|
||||||
|
type: "seo-mode:preview-pointerdown",
|
||||||
|
workspaceKey: state.workspaceKey
|
||||||
|
}, "*");
|
||||||
|
}
|
||||||
|
|
||||||
function measure() {
|
function measure() {
|
||||||
const layer = ensureLayer();
|
const layer = ensureLayer();
|
||||||
const root = document.documentElement;
|
const root = document.documentElement;
|
||||||
|
|
@ -702,6 +713,7 @@ function buildPreviewBridgeScript() {
|
||||||
window.addEventListener("resize", scheduleMeasure);
|
window.addEventListener("resize", scheduleMeasure);
|
||||||
window.addEventListener("scroll", scheduleMeasure, { passive: true });
|
window.addEventListener("scroll", scheduleMeasure, { passive: true });
|
||||||
document.addEventListener("scroll", scheduleMeasure, { capture: true, passive: true });
|
document.addEventListener("scroll", scheduleMeasure, { capture: true, passive: true });
|
||||||
|
document.addEventListener("pointerdown", reportPreviewPointerDown, { capture: true, passive: true });
|
||||||
window.addEventListener("load", () => {
|
window.addEventListener("load", () => {
|
||||||
window.setTimeout(scheduleMeasure, 50);
|
window.setTimeout(scheduleMeasure, 50);
|
||||||
window.setTimeout(scheduleMeasure, 500);
|
window.setTimeout(scheduleMeasure, 500);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue