Fix page workspace controls and glass overlays
This commit is contained in:
parent
2777b69eb3
commit
7be6104b6b
|
|
@ -6,8 +6,9 @@
|
|||
|
||||
- База: светлая Apple-like система, много воздуха, мягкие панели, скругления и спокойный серый фон.
|
||||
- Главный акцент: тёмный neutral active `#202124 -> #111113`, как у активного этапа и основных submit/action-кнопок.
|
||||
- Вторичный слой: white glass surfaces/controls через `--nodedc-glass-*`, без отдельных цветных акцентов.
|
||||
- Вторичный слой: white glass surfaces/controls через `--nodedc-glass-*`, без отдельных цветных акцентов. Glass-панели должны оставаться прозрачными: материал строится на низкой alpha-подложке, `backdrop-filter` и outline-gradient, а не на глухой белой заливке.
|
||||
- Избегаем случайной зелени/оранжевого/голубого/фиолета, если это не специально введённый статус.
|
||||
- Точки ошибок в preview-сайте: розовый marker `#ff4fb8`, активный `#d81b7d`.
|
||||
|
||||
## Кнопки
|
||||
|
||||
|
|
|
|||
|
|
@ -1059,7 +1059,7 @@ type WorkspaceTarget = {
|
|||
};
|
||||
|
||||
type WorkspacePreviewMode = "desktop" | "mobile";
|
||||
type WorkspaceDrawerPanel = "fields" | "issues" | "scope";
|
||||
type WorkspaceDrawerPanel = "fields" | "issues";
|
||||
|
||||
const WORKSPACE_PREVIEW_MODES: Array<{ id: WorkspacePreviewMode; label: string }> = [
|
||||
{ id: "desktop", label: "Desktop" },
|
||||
|
|
@ -3522,7 +3522,11 @@ export function App() {
|
|||
null;
|
||||
const activeWorkspaceMarkers = activeWorkspaceKey ? (workspacePreviewMarkers[activeWorkspaceKey] ?? []) : [];
|
||||
const activeWorkspacePreviewMode = activeWorkspaceKey ? (workspacePreviewModes[activeWorkspaceKey] ?? "desktop") : "desktop";
|
||||
const activeWorkspaceDrawers = activeWorkspaceKey ? (workspaceDrawers[activeWorkspaceKey] ?? []) : [];
|
||||
const activeWorkspaceDrawers = activeWorkspaceKey
|
||||
? (workspaceDrawers[activeWorkspaceKey] ?? []).filter(
|
||||
(drawer): drawer is WorkspaceDrawerPanel => drawer === "fields" || drawer === "issues"
|
||||
)
|
||||
: [];
|
||||
const isWorkspacePageMenuOpen = activeWorkspaceKey ? Boolean(workspacePageMenus[activeWorkspaceKey]) : false;
|
||||
const previewWorkspaceScopeId = workspacePreviewScopeIds[project.id] ?? activeWorkspaceScopeItem?.scopeId ?? null;
|
||||
const previewWorkspaceScopeItem =
|
||||
|
|
@ -4775,7 +4779,7 @@ export function App() {
|
|||
<div className="workspace-current-page">
|
||||
<div>
|
||||
<span>
|
||||
Активная зона {activeWorkspacePageIndex + 1}/{selectedWorkspaceScopeItems.length} · выбранный scope
|
||||
Активная страница {activeWorkspacePageIndex + 1}/{selectedWorkspaceScopeItems.length}
|
||||
</span>
|
||||
<strong>{activeWorkspaceScopeItem.title}</strong>
|
||||
<small>{activeWorkspaceScopeItem.pathLabel}</small>
|
||||
|
|
@ -4785,7 +4789,7 @@ export function App() {
|
|||
<div className="workspace-cockpit-toolbar">
|
||||
<div className="workspace-preview-status">
|
||||
<span>Замечаний на активной странице: {activeWorkspaceIssues.length}</span>
|
||||
<span>В выбранном scope: {selectedCoverageIssueCount}</span>
|
||||
<span>В выбранных страницах: {selectedCoverageIssueCount}</span>
|
||||
<span>Warning: {activeWorkspaceIssueCounts.warnings} · Info: {activeWorkspaceIssueCounts.info}</span>
|
||||
</div>
|
||||
<div className="workspace-current-page-actions">
|
||||
|
|
@ -4807,7 +4811,7 @@ export function App() {
|
|||
{isWorkspacePageMenuOpen ? (
|
||||
<div className="workspace-page-menu" role="menu">
|
||||
<div className="workspace-page-menu-head">
|
||||
<strong>Страницы и секции scope</strong>
|
||||
<strong>Страницы и секции</strong>
|
||||
<small>Переключает preview, ошибки и поля рабочей зоны.</small>
|
||||
</div>
|
||||
{selectedWorkspaceScopeItems.length > 0 ? (
|
||||
|
|
@ -4826,7 +4830,8 @@ export function App() {
|
|||
onClick={() => {
|
||||
setWorkspacePageMenus((currentMenus) => ({
|
||||
...currentMenus,
|
||||
[activeWorkspaceKey]: false
|
||||
[activeWorkspaceKey]: false,
|
||||
[pageWorkspaceKey]: true
|
||||
}));
|
||||
void handleOpenPageWorkspace(project, scopeItem, { silent: true });
|
||||
}}
|
||||
|
|
@ -4843,21 +4848,12 @@ export function App() {
|
|||
</div>
|
||||
) : (
|
||||
<small className="workspace-page-menu-empty">
|
||||
В выбранном scope пока нет рабочих страниц или секций.
|
||||
В выбранном наборе пока нет рабочих страниц или секций.
|
||||
</small>
|
||||
)}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
<button
|
||||
className={activeWorkspaceDrawers.includes("scope") ? "active" : undefined}
|
||||
onClick={() => toggleWorkspaceDrawer(activeWorkspaceKey, "scope")}
|
||||
type="button"
|
||||
>
|
||||
<FileText size={14} />
|
||||
Scope
|
||||
<em>{selectedWorkspaceScopeItems.length}</em>
|
||||
</button>
|
||||
<button
|
||||
className={activeWorkspaceDrawers.includes("issues") ? "active" : undefined}
|
||||
onClick={() => toggleWorkspaceDrawer(activeWorkspaceKey, "issues")}
|
||||
|
|
@ -4958,25 +4954,17 @@ export function App() {
|
|||
<div className="workspace-drawer-header">
|
||||
<div>
|
||||
<span>
|
||||
{activeWorkspaceDrawer === "scope"
|
||||
? "Выбранный scope"
|
||||
: activeWorkspaceDrawer === "fields"
|
||||
? "Поля для правки"
|
||||
: "Аудит страницы"}
|
||||
{activeWorkspaceDrawer === "fields" ? "Поля для правки" : "Аудит страницы"}
|
||||
</span>
|
||||
<strong>
|
||||
{activeWorkspaceDrawer === "scope"
|
||||
? `${selectedWorkspaceScopeItems.length} в scope`
|
||||
: activeWorkspaceDrawer === "fields"
|
||||
? `${activeWorkspaceTargets.length} полей`
|
||||
: `${activeWorkspaceIssues.length} замечаний`}
|
||||
{activeWorkspaceDrawer === "fields"
|
||||
? `${activeWorkspaceTargets.length} полей`
|
||||
: `${activeWorkspaceIssues.length} замечаний`}
|
||||
</strong>
|
||||
<small>
|
||||
{activeWorkspaceDrawer === "scope"
|
||||
? "Дальше анализируются только выбранные страницы и секции."
|
||||
: activeWorkspaceDrawer === "fields"
|
||||
? "Клик по точке или карточке открывает связанное поле."
|
||||
: "Список относится к активной странице, не ко всему сайту."}
|
||||
{activeWorkspaceDrawer === "fields"
|
||||
? "Клик по точке или карточке открывает связанное поле."
|
||||
: "Список относится к активной странице, не ко всему сайту."}
|
||||
</small>
|
||||
</div>
|
||||
<button
|
||||
|
|
@ -4988,31 +4976,7 @@ export function App() {
|
|||
<X size={16} />
|
||||
</button>
|
||||
</div>
|
||||
{activeWorkspaceDrawer === "scope" ? (
|
||||
<div className="workspace-scope-list">
|
||||
{selectedWorkspaceScopeItems.map((scopeItem, pageIndex) => {
|
||||
const pageWorkspaceKey = getWorkspaceKey(project.id, scopeItem.scopeId);
|
||||
const isOpening = busyWorkspaceKey === pageWorkspaceKey;
|
||||
const isActivePage = activeWorkspaceScopeItem?.scopeId === scopeItem.scopeId;
|
||||
const pageIssues = getPageIssues(scanSummary, scopeItem.pageId);
|
||||
|
||||
return (
|
||||
<button
|
||||
className={isActivePage ? "active" : undefined}
|
||||
disabled={isOpening}
|
||||
key={`workspace-scope-${scopeItem.scopeId}`}
|
||||
onClick={() => void handleOpenPageWorkspace(project, scopeItem)}
|
||||
type="button"
|
||||
>
|
||||
<span>{pageIndex + 1}</span>
|
||||
<strong>{scopeItem.title}</strong>
|
||||
<small>{scopeItem.pathLabel}</small>
|
||||
<em>{pageIssues.length} замечаний</em>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
) : activeWorkspaceDrawer === "fields" ? (
|
||||
{activeWorkspaceDrawer === "fields" ? (
|
||||
<div className="workspace-fields-drawer">
|
||||
{activeWorkspaceTargets.length > 0 ? (
|
||||
activeWorkspaceTargets.map((target) => {
|
||||
|
|
|
|||
|
|
@ -15,25 +15,25 @@
|
|||
--accent-soft: rgba(0, 0, 0, 0.08);
|
||||
--warning-bg: #e8e8e8;
|
||||
--danger-bg: #d8d8d8;
|
||||
--nodedc-glass-panel-bg: rgba(255, 255, 255, 0.76);
|
||||
--nodedc-glass-panel-bg-strong: rgba(255, 255, 255, 0.9);
|
||||
--nodedc-glass-panel-bg-soft: rgba(255, 255, 255, 0.6);
|
||||
--nodedc-glass-panel-surface: linear-gradient(180deg, rgba(255, 255, 255, 0.76) 0%, rgba(255, 255, 255, 0.44) 100%), var(--nodedc-glass-panel-bg);
|
||||
--nodedc-glass-panel-surface-strong: linear-gradient(180deg, rgba(255, 255, 255, 0.86) 0%, rgba(255, 255, 255, 0.52) 100%), var(--nodedc-glass-panel-bg-strong);
|
||||
--nodedc-glass-section-bg: linear-gradient(180deg, rgba(255, 255, 255, 0.58) 0%, rgba(255, 255, 255, 0.28) 100%), rgba(244, 244, 246, 0.62);
|
||||
--nodedc-glass-control-bg: linear-gradient(180deg, rgba(255, 255, 255, 0.68) 0%, rgba(255, 255, 255, 0.36) 100%), rgba(244, 244, 246, 0.74);
|
||||
--nodedc-glass-control-hover: linear-gradient(180deg, rgba(255, 255, 255, 0.78) 0%, rgba(255, 255, 255, 0.44) 100%), rgba(232, 232, 235, 0.82);
|
||||
--nodedc-glass-panel-bg: rgba(255, 255, 255, 0.18);
|
||||
--nodedc-glass-panel-bg-strong: rgba(255, 255, 255, 0.26);
|
||||
--nodedc-glass-panel-bg-soft: rgba(255, 255, 255, 0.12);
|
||||
--nodedc-glass-panel-surface: linear-gradient(180deg, rgba(255, 255, 255, 0.3) 0%, rgba(255, 255, 255, 0.1) 100%), var(--nodedc-glass-panel-bg);
|
||||
--nodedc-glass-panel-surface-strong: linear-gradient(180deg, rgba(255, 255, 255, 0.38) 0%, rgba(255, 255, 255, 0.14) 100%), var(--nodedc-glass-panel-bg-strong);
|
||||
--nodedc-glass-section-bg: linear-gradient(180deg, rgba(255, 255, 255, 0.22) 0%, rgba(255, 255, 255, 0.08) 100%), rgba(255, 255, 255, 0.12);
|
||||
--nodedc-glass-control-bg: linear-gradient(180deg, rgba(255, 255, 255, 0.24) 0%, rgba(255, 255, 255, 0.08) 100%), rgba(255, 255, 255, 0.12);
|
||||
--nodedc-glass-control-hover: linear-gradient(180deg, rgba(255, 255, 255, 0.34) 0%, rgba(255, 255, 255, 0.12) 100%), rgba(255, 255, 255, 0.2);
|
||||
--nodedc-glass-control-active: linear-gradient(180deg, rgba(32, 32, 34, 0.98), rgba(20, 20, 22, 0.96));
|
||||
--nodedc-glass-outline: rgba(24, 32, 29, 0.1);
|
||||
--nodedc-glass-outline-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.86), rgba(24, 32, 29, 0.08));
|
||||
--nodedc-glass-panel-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.75), 0 22px 72px rgba(24, 32, 29, 0.16);
|
||||
--nodedc-glass-control-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.7);
|
||||
--nodedc-glass-blur: blur(44px) saturate(1.12);
|
||||
--nodedc-glass-panel-blur: blur(64px) saturate(1.24) brightness(1.02);
|
||||
--nodedc-glass-outline-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.8) 0%, rgba(255, 255, 255, 0.34) 28%, rgba(24, 32, 29, 0.1) 100%);
|
||||
--nodedc-glass-panel-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.42), 0 18px 60px rgba(24, 32, 29, 0.14);
|
||||
--nodedc-glass-control-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.34);
|
||||
--nodedc-glass-blur: blur(24px) saturate(128%) brightness(1.05);
|
||||
--nodedc-glass-panel-blur: blur(64px) saturate(150%) brightness(1.08);
|
||||
--nodedc-header-dropdown-bg: var(--nodedc-glass-panel-surface-strong);
|
||||
--nodedc-header-dropdown-item-bg: var(--nodedc-glass-control-bg);
|
||||
--nodedc-header-dropdown-item-hover-bg: var(--nodedc-glass-control-hover);
|
||||
--nodedc-header-dropdown-item-active-bg: rgba(24, 32, 29, 0.09);
|
||||
--nodedc-header-dropdown-item-active-bg: rgba(255, 255, 255, 0.24);
|
||||
--nodedc-header-dropdown-item-active-color: var(--ink);
|
||||
font-family: "Aptos", "Segoe UI", sans-serif;
|
||||
font-synthesis: none;
|
||||
|
|
@ -1362,10 +1362,10 @@ input {
|
|||
place-items: center;
|
||||
padding: 0;
|
||||
color: #fff;
|
||||
background: var(--accent);
|
||||
background: #ff4fb8;
|
||||
border: 2px solid rgba(255, 255, 255, 0.92);
|
||||
border-radius: 999px;
|
||||
box-shadow: 0 8px 18px rgba(242, 122, 26, 0.24);
|
||||
box-shadow: 0 8px 18px rgba(255, 79, 184, 0.3);
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
font-weight: 750;
|
||||
|
|
@ -1374,8 +1374,8 @@ input {
|
|||
}
|
||||
|
||||
.workspace-preview-markers button.active {
|
||||
background: var(--ink);
|
||||
box-shadow: 0 0 0 4px rgba(242, 122, 26, 0.18);
|
||||
background: #d81b7d;
|
||||
box-shadow: 0 0 0 4px rgba(255, 79, 184, 0.18);
|
||||
}
|
||||
|
||||
.workspace-subheading {
|
||||
|
|
@ -7440,12 +7440,14 @@ input[type="checkbox"] {
|
|||
}
|
||||
|
||||
.stage-3 .workspace-preview-markers button {
|
||||
background: var(--accent) !important;
|
||||
background: #ff4fb8 !important;
|
||||
box-shadow: 0 8px 18px rgba(255, 79, 184, 0.3) !important;
|
||||
transform: none !important;
|
||||
}
|
||||
|
||||
.stage-3 .workspace-preview-markers button.active {
|
||||
background: var(--ink) !important;
|
||||
background: #d81b7d !important;
|
||||
box-shadow: 0 0 0 4px rgba(255, 79, 184, 0.18) !important;
|
||||
}
|
||||
|
||||
.stage-6 .project-setup,
|
||||
|
|
@ -7566,6 +7568,89 @@ input[type="checkbox"] {
|
|||
box-shadow: var(--nodedc-glass-panel-shadow) !important;
|
||||
backdrop-filter: var(--nodedc-glass-panel-blur) !important;
|
||||
-webkit-backdrop-filter: var(--nodedc-glass-panel-blur) !important;
|
||||
isolation: isolate;
|
||||
}
|
||||
|
||||
.workspace-page-menu,
|
||||
.workspace-drawer,
|
||||
.semantic-panel,
|
||||
.semantic-page-plan-panel,
|
||||
.semantic-brief-panel,
|
||||
.semantic-landing-panel,
|
||||
.semantic-verdict-panel,
|
||||
.semantic-warning-list,
|
||||
.semantic-gap-panel,
|
||||
.semantic-seeds,
|
||||
.semantic-ai-contract,
|
||||
.semantic-style-panel,
|
||||
.semantic-action-list,
|
||||
.semantic-cluster-detail,
|
||||
.market-panel,
|
||||
.market-heading,
|
||||
.market-state-card,
|
||||
.market-wordstat-card,
|
||||
.market-provider,
|
||||
.market-columns section,
|
||||
.market-next-actions {
|
||||
overflow: hidden !important;
|
||||
}
|
||||
|
||||
.semantic-panel,
|
||||
.semantic-page-plan-panel,
|
||||
.semantic-brief-panel,
|
||||
.semantic-landing-panel,
|
||||
.semantic-verdict-panel,
|
||||
.semantic-warning-list,
|
||||
.semantic-gap-panel,
|
||||
.semantic-seeds,
|
||||
.semantic-ai-contract,
|
||||
.semantic-style-panel,
|
||||
.semantic-action-list,
|
||||
.semantic-cluster-detail,
|
||||
.market-panel,
|
||||
.market-heading,
|
||||
.market-state-card,
|
||||
.market-wordstat-card,
|
||||
.market-provider,
|
||||
.market-columns section,
|
||||
.market-next-actions {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.workspace-page-menu::after,
|
||||
.workspace-drawer::after,
|
||||
.semantic-panel::after,
|
||||
.semantic-page-plan-panel::after,
|
||||
.semantic-brief-panel::after,
|
||||
.semantic-landing-panel::after,
|
||||
.semantic-verdict-panel::after,
|
||||
.semantic-warning-list::after,
|
||||
.semantic-gap-panel::after,
|
||||
.semantic-seeds::after,
|
||||
.semantic-ai-contract::after,
|
||||
.semantic-style-panel::after,
|
||||
.semantic-action-list::after,
|
||||
.semantic-cluster-detail::after,
|
||||
.market-panel::after,
|
||||
.market-heading::after,
|
||||
.market-state-card::after,
|
||||
.market-wordstat-card::after,
|
||||
.market-provider::after,
|
||||
.market-columns section::after,
|
||||
.market-next-actions::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 2;
|
||||
padding: 1px;
|
||||
pointer-events: none;
|
||||
border-radius: inherit;
|
||||
background: var(--nodedc-glass-outline-gradient);
|
||||
-webkit-mask:
|
||||
linear-gradient(#000 0 0) content-box,
|
||||
linear-gradient(#000 0 0);
|
||||
-webkit-mask-composite: xor;
|
||||
mask-composite: exclude;
|
||||
}
|
||||
|
||||
.workspace-drawer-header,
|
||||
|
|
|
|||
|
|
@ -523,10 +523,10 @@ function buildPreviewBridgeScript() {
|
|||
marker.style.placeItems = "center";
|
||||
marker.style.padding = "0";
|
||||
marker.style.color = "#fff";
|
||||
marker.style.background = "#202124";
|
||||
marker.style.background = "#ff4fb8";
|
||||
marker.style.border = "2px solid rgba(255,255,255,.95)";
|
||||
marker.style.borderRadius = "999px";
|
||||
marker.style.boxShadow = "0 6px 16px rgba(24,32,29,.24)";
|
||||
marker.style.boxShadow = "0 6px 16px rgba(255,79,184,.32)";
|
||||
marker.style.cursor = "pointer";
|
||||
marker.style.font = "700 12px/1 Inter, Arial, sans-serif";
|
||||
marker.style.pointerEvents = "auto";
|
||||
|
|
|
|||
Loading…
Reference in New Issue