From 39047d7fa15c94d18902bbb4f1984f1b39cc7eba Mon Sep 17 00:00:00 2001 From: Michael Gasperini <163041857+TheStreamCode@users.noreply.github.com> Date: Thu, 22 Oct 2026 12:24:07 +0200 Subject: [PATCH 1/4] feat(admin): unify TeamVault admin screens with a shared design system --- admin/views/file-manager-page.php | 9 +- admin/views/settings-page.php | 2 +- assets/css/admin.css | 1486 ++++++++++++++++++++++++++++- assets/js/admin-app-core.js | 4 + assets/js/admin-app-governance.js | 2 +- includes/class-mstv-assets.php | 34 +- includes/class-mstv-i18n.php | 4 + tests/PDMAdminAppTest.php | 67 ++ tests/PDMAdminHandlersTest.php | 1 + tests/PDMAssetsTest.php | 19 + tests/bootstrap.php | 8 + 11 files changed, 1599 insertions(+), 37 deletions(-) diff --git a/admin/views/file-manager-page.php b/admin/views/file-manager-page.php index 49bf738..8625272 100644 --- a/admin/views/file-manager-page.php +++ b/admin/views/file-manager-page.php @@ -7,6 +7,7 @@ $mstv_logo_src = MSTV_PLUGIN_URL . 'assets/logo-teamvault.svg'; ?>
+

@@ -57,21 +58,23 @@
-
-
- diff --git a/admin/views/settings-page.php b/admin/views/settings-page.php index 6d55cfa..b05e0c2 100644 --- a/admin/views/settings-page.php +++ b/admin/views/settings-page.php @@ -299,7 +299,7 @@ class="pdm-input"
- +
diff --git a/assets/css/admin.css b/assets/css/admin.css index db61dea..cb0b551 100644 --- a/assets/css/admin.css +++ b/assets/css/admin.css @@ -2,6 +2,7 @@ --pdm-color-primary: #2563eb; --pdm-color-primary-hover: #1d4ed8; --pdm-color-primary-light: #dbeafe; + --pdm-color-primary-soft: #eff6ff; --pdm-color-secondary: #64748b; --pdm-color-success: #22c55e; --pdm-color-success-light: #dcfce7; @@ -9,32 +10,46 @@ --pdm-color-danger-light: #fee2e2; --pdm-color-warning: #f59e0b; --pdm-color-warning-light: #fef3c7; - --pdm-color-bg: #f8fafc; + /* Accessible text variants for chips on tinted backgrounds. */ + --pdm-color-success-text: #15803d; + --pdm-color-danger-text: #b91c1c; + --pdm-color-warning-text: #b45309; + --pdm-color-bg: #f6f8fb; --pdm-color-bg-secondary: #ffffff; - --pdm-color-border: #e2e8f0; - --pdm-color-text: #1e293b; - --pdm-color-text-secondary: #64748b; - /* Darkened from #94a3b8 to meet WCAG AA (>=4.5:1) for informational text. */ - --pdm-color-text-muted: #6b7280; - --pdm-shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05); - --pdm-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); - --pdm-shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); - --pdm-shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); - --pdm-radius-sm: 4px; + --pdm-color-border: #e3e8ef; + --pdm-color-border-strong: #cbd5e1; + --pdm-color-text: #0f172a; + --pdm-color-text-secondary: #475569; + /* WCAG AA (>=4.5:1) for informational text on white and on --pdm-color-bg. */ + --pdm-color-text-muted: #5b6575; + --pdm-shadow-sm: 0 1px 1px 0 rgb(15 23 42 / 0.04), 0 1px 2px 0 rgb(15 23 42 / 0.05); + --pdm-shadow: 0 1px 2px 0 rgb(15 23 42 / 0.05), 0 2px 6px -1px rgb(15 23 42 / 0.08); + --pdm-shadow-md: 0 4px 10px -2px rgb(15 23 42 / 0.1), 0 2px 4px -2px rgb(15 23 42 / 0.06); + --pdm-shadow-lg: 0 18px 40px -12px rgb(15 23 42 / 0.2); + --pdm-radius-sm: 6px; --pdm-radius: 8px; --pdm-radius-lg: 12px; --pdm-radius-xl: 16px; --pdm-transition: all 0.15s ease; --pdm-font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; + --pdm-font-mono: ui-monospace, SFMono-Regular, "SF Mono", Consolas, "Liberation Mono", monospace; --pdm-sidebar-width: 260px; --pdm-details-width: 320px; --pdm-toolbar-height: 60px; --pdm-admin-bar-offset: 32px; + /* Core admin content padding; the plugin screens bleed over it edge to edge. */ + --pdm-admin-content-pad: 20px; + --pdm-page-pad-y: 28px; + --pdm-page-pad-x: 32px; + --pdm-content-max: 780px; } @media (max-width: 782px) { :root { --pdm-admin-bar-offset: 46px; + --pdm-admin-content-pad: 10px; + --pdm-page-pad-y: 22px; + --pdm-page-pad-x: 20px; } } @@ -62,6 +77,37 @@ overflow-y: auto; } +/* + * TeamVault owns its admin screens: drop the WordPress chrome bands (the footer row + * and the gray gaps it leaves above and below the plugin panels) from every page. + * The File Manager goes one step further and fills the whole viewport below the admin + * bar, so its storage panel sits on the bottom edge. + */ +body.mstv-admin-page #wpfooter { + display: none; +} + +body.mstv-admin-page #wpbody-content { + padding-bottom: 0; +} + +body.mstv-admin-page .pdm-wrapper { + margin: 0 0 0 -20px; +} + +body.toplevel_page_mikesoft-teamvault .pdm-wrapper { + height: calc(100vh - var(--pdm-admin-bar-offset)); +} + +body.toplevel_page_mikesoft-teamvault .pdm-app { + height: 100%; + min-height: 0; +} + +body.toplevel_page_mikesoft-teamvault .pdm-sidebar { + max-height: none; +} + .pdm-sidebar-header { display: flex; align-items: center; @@ -879,7 +925,7 @@ color: var(--pdm-color-text); resize: vertical; min-height: 80px; - font-agomily: inherit; + font-family: inherit; transition: var(--pdm-transition); } @@ -1615,18 +1661,6 @@ outline: 2px solid var(--pdm-color-primary, #2271b1); outline-offset: 1px; } - - .pdm-btn-primary { - order: 1; - } - - .pdm-view-toggle { - order: 0; - } - - .pdm-btn-secondary { - order: 2; - } } @media (min-width: 769px) { @@ -1637,9 +1671,9 @@ } @media (max-width: 600px) { - /* Keep secondary toolbar actions compact (file-manager app only; must not affect - the governance pages or the shared modal, which live outside .pdm-app). */ - .pdm-app .pdm-btn-secondary:not(.pdm-sidebar-toggle):not(#pdm-export-btn) { + /* Keep secondary toolbar actions compact (file manager only; never hide the + details-panel actions or the shared modal controls). */ + .pdm-app .pdm-toolbar .pdm-btn-secondary:not(.pdm-sidebar-toggle):not(#pdm-export-btn) { display: none; } @@ -1927,7 +1961,7 @@ .pdm-log-context { font-size: 12px; - font-agomily: monospace; + font-family: var(--pdm-font-mono); background: var(--pdm-color-bg); padding: 4px 8px; border-radius: 4px; @@ -2429,7 +2463,7 @@ body.pdm-no-scroll { padding: 12px; } - .pdmm-checkbox-label input[type="checkbox"] { + .pdm-checkbox-label input[type="checkbox"] { width: 22px; height: 22px; } @@ -2816,3 +2850,1397 @@ input[type="date"]::-webkit-calendar-picker-indicator { font-size: 12px; color: var(--pdm-color-text-secondary); } + +/* ============================================================ + DESIGN SYSTEM · unified style for every TeamVault screen + Single shared layer for the page canvas, headers, typography, + controls, tables, panels and empty states. It normalises the + earlier component rules and is the place to tune the visual + language for File Manager, Settings, Activity Log and the + governance screens at once. + ============================================================ */ + +/* ---- Page canvas -------------------------------------------- */ + +body.mstv-admin-page { + background: var(--pdm-color-bg); + color: var(--pdm-color-text); +} + +body.mstv-admin-page .pdm-settings-wrapper, +body.mstv-admin-page .pdm-logs-wrapper, +body.mstv-admin-page .pdm-governance-wrap { + box-sizing: border-box; + margin: 0 0 0 calc(-1 * var(--pdm-admin-content-pad)); + padding: var(--pdm-page-pad-y) var(--pdm-page-pad-x) calc(var(--pdm-page-pad-y) + 24px); + background: var(--pdm-color-bg-secondary); + min-height: calc(100vh - var(--pdm-admin-bar-offset)); +} + +body.mstv-admin-page .pdm-wrapper { + margin-left: calc(-1 * var(--pdm-admin-content-pad)); +} + +body.mstv-admin-page .pdm-settings-wrapper { + max-width: none; +} + +/* Readable single column for the settings form. */ +body.mstv-admin-page .pdm-settings-wrapper > * { + max-width: var(--pdm-content-max); + margin-left: auto; + margin-right: auto; +} + +body.mstv-admin-page .pdm-governance-wrap > * { + max-width: 1120px; +} + +/* ---- Shared page headers ------------------------------------ */ + +body.mstv-admin-page .mstv-governance-header { + display: flex; + align-items: flex-start; + justify-content: space-between; + flex-wrap: wrap; + gap: 16px; + margin: 0 0 24px; + padding: 0 0 20px; + border-bottom: 1px solid var(--pdm-color-border); +} + +body.mstv-admin-page .mstv-governance-header > div { + flex: 1 1 auto; + min-width: 0; +} + +body.mstv-admin-page .mstv-governance-header .pdm-btn { + flex-shrink: 0; +} + +body.mstv-admin-page .pdm-settings-header, +body.mstv-admin-page .pdm-logs-header { + margin-top: 0; + margin-bottom: 26px; + padding: 0 0 20px; + border-bottom: 1px solid var(--pdm-color-border); +} + +body.mstv-admin-page .mstv-governance-title, +body.mstv-admin-page .pdm-settings-title, +body.mstv-admin-page .pdm-logs-title { + margin: 0 0 6px; + font-size: 24px; + line-height: 1.25; + font-weight: 600; + letter-spacing: -0.012em; + color: var(--pdm-color-text); +} + +body.mstv-admin-page .mstv-governance-subtitle, +body.mstv-admin-page .pdm-settings-desc, +body.mstv-admin-page .pdm-logs-desc { + margin: 0; + max-width: 680px; + font-size: 14px; + line-height: 1.55; + color: var(--pdm-color-text-secondary); +} + +/* ---- Buttons ------------------------------------------------ */ + +body.mstv-admin-page .pdm-btn { + min-height: 36px; + padding: 8px 14px; + border: 1px solid transparent; + border-radius: var(--pdm-radius); + font-size: 13px; + font-weight: 500; + line-height: 1.2; + gap: 7px; + box-shadow: none; + text-shadow: none; + transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease; +} + +body.mstv-admin-page .pdm-btn svg { + flex-shrink: 0; +} + +body.mstv-admin-page .pdm-btn-primary { + background: var(--pdm-color-primary); + border-color: var(--pdm-color-primary); + color: #ffffff; +} + +body.mstv-admin-page .pdm-btn-primary:hover:not(:disabled) { + background: var(--pdm-color-primary-hover); + border-color: var(--pdm-color-primary-hover); +} + +body.mstv-admin-page .pdm-btn-secondary { + background: var(--pdm-color-bg-secondary); + border-color: var(--pdm-color-border); + color: var(--pdm-color-text); +} + +body.mstv-admin-page .pdm-btn-secondary:hover:not(:disabled) { + background: var(--pdm-color-bg); + border-color: var(--pdm-color-border-strong); +} + +body.mstv-admin-page .pdm-btn-ghost { + color: var(--pdm-color-text-secondary); +} + +body.mstv-admin-page .pdm-btn-ghost:hover:not(:disabled) { + background: #eef2f7; + color: var(--pdm-color-text); +} + +body.mstv-admin-page .pdm-btn-danger { + background: var(--pdm-color-danger); + border-color: var(--pdm-color-danger); + color: #ffffff; +} + +body.mstv-admin-page .pdm-btn-danger:hover:not(:disabled) { + background: #dc2626; + border-color: #dc2626; +} + +body.mstv-admin-page .pdm-btn-icon { + width: 36px; + height: 36px; + min-height: 36px; + padding: 0; +} + +body.mstv-admin-page .pdm-btn-sm { + min-height: 30px; + padding: 5px 10px; + font-size: 12px; +} + +body.mstv-admin-page .pdm-btn:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +/* ---- Form controls ------------------------------------------ */ + +body.mstv-admin-page .pdm-input, +body.mstv-admin-page .pdm-select, +body.mstv-admin-page .pdm-textarea { + min-height: 36px; + padding: 8px 12px; + border: 1px solid var(--pdm-color-border); + border-radius: var(--pdm-radius); + background: var(--pdm-color-bg-secondary); + color: var(--pdm-color-text); + font-family: var(--pdm-font-sans); + font-size: 13px; + line-height: 1.4; + box-shadow: none; +} + +body.mstv-admin-page .pdm-input:hover, +body.mstv-admin-page .pdm-select:hover, +body.mstv-admin-page .pdm-textarea:hover { + border-color: var(--pdm-color-border-strong); +} + +body.mstv-admin-page .pdm-input:focus, +body.mstv-admin-page .pdm-select:focus, +body.mstv-admin-page .pdm-textarea:focus { + outline: none; + border-color: var(--pdm-color-primary); + box-shadow: 0 0 0 3px var(--pdm-color-primary-light); +} + +body.mstv-admin-page .pdm-select { + padding-right: 30px; +} + +body.mstv-admin-page .pdm-textarea { + min-height: 90px; +} + +body.mstv-admin-page .pdm-field { + margin-bottom: 22px; +} + +body.mstv-admin-page .pdm-field-label { + margin-bottom: 6px; + font-size: 13px; + font-weight: 600; +} + +body.mstv-admin-page .pdm-field-desc { + margin: 6px 0 10px; + font-size: 12.5px; + line-height: 1.55; + color: var(--pdm-color-text-secondary); +} + +body.mstv-admin-page .pdm-checkbox-label { + gap: 10px; + font-size: 13px; + font-weight: 500; +} + +body.mstv-admin-page .pdm-checkbox-label input[type="checkbox"] { + width: 17px; + height: 17px; + margin: 0; + accent-color: var(--pdm-color-primary); +} + +body.mstv-admin-page .pdm-checkbox-label--danger input[type="checkbox"] { + accent-color: var(--pdm-color-danger); +} + +body.mstv-admin-page .pdm-section-title { + margin: 0 0 14px; + font-size: 15px; + font-weight: 600; + letter-spacing: 0; + color: var(--pdm-color-text); +} + +/* ---- File Manager shell ------------------------------------- */ + +body.mstv-admin-page .pdm-sidebar-header { + padding: 17px 16px 13px; +} + +body.mstv-admin-page .pdm-sidebar-logo { + height: 34px; +} + +body.mstv-admin-page .pdm-sidebar-search { + padding: 12px 14px; +} + +body.mstv-admin-page .pdm-sidebar-search .pdm-input { + height: 36px; +} + +body.mstv-admin-page .pdm-folder-tree { + padding: 6px 10px 12px; +} + +body.mstv-admin-page .pdm-folder-item { + min-height: 34px; + padding: 7px 10px; + border-radius: var(--pdm-radius); + gap: 8px; + font-size: 13px; + color: var(--pdm-color-text-secondary); +} + +body.mstv-admin-page .pdm-folder-item:hover { + background: #f1f5f9; + color: var(--pdm-color-text); +} + +body.mstv-admin-page .pdm-folder-item.active { + background: var(--pdm-color-primary-soft); + color: var(--pdm-color-primary); + font-weight: 500; +} + +body.mstv-admin-page .pdm-folder-item svg { + flex-shrink: 0; +} + +body.mstv-admin-page .pdm-storage-indicator { + padding: 16px; + background: linear-gradient(180deg, #ffffff 0%, #f8fafc 100%); +} + +body.mstv-admin-page .pdm-storage-title { + margin-bottom: 10px; + font-size: 10.5px; + letter-spacing: 0.08em; + color: var(--pdm-color-text-muted); +} + +body.mstv-admin-page .pdm-storage-stat-value { + font-size: 15px; +} + +body.mstv-admin-page .pdm-storage-stat-label { + font-size: 11px; + color: var(--pdm-color-text-muted); +} + +body.mstv-admin-page .pdm-toolbar { + padding: 10px 20px; + gap: 12px; +} + +body.mstv-admin-page .pdm-breadcrumb { + font-size: 13px; + color: var(--pdm-color-text-secondary); +} + +body.mstv-admin-page .pdm-breadcrumb-item { + padding: 5px 8px; +} + +body.mstv-admin-page .pdm-toolbar-label { + font-size: 12px; + color: var(--pdm-color-text-secondary); +} + +body.mstv-admin-page .pdm-view-toggle { + padding: 3px; + gap: 2px; + background: #eef2f7; + border-radius: var(--pdm-radius); +} + +body.mstv-admin-page .pdm-view-toggle .pdm-btn { + width: 34px; + height: 30px; + min-height: 30px; + padding: 0; + border-radius: 6px; + color: var(--pdm-color-text-secondary); +} + +body.mstv-admin-page .pdm-view-toggle .pdm-btn:hover:not(.active) { + background: rgba(255, 255, 255, 0.7); + color: var(--pdm-color-text); +} + +body.mstv-admin-page .pdm-view-toggle .pdm-btn.active { + background: var(--pdm-color-bg-secondary); + color: var(--pdm-color-primary); + box-shadow: var(--pdm-shadow-sm); +} + +body.mstv-admin-page .pdm-content { + padding: 20px 20px 24px; +} + +body.mstv-admin-page .pdm-content-grid { + gap: 14px; + grid-template-columns: repeat(auto-fill, minmax(168px, 1fr)); +} + +body.mstv-admin-page .pdm-item { + padding: 16px 12px 14px; + border-radius: 10px; +} + +body.mstv-admin-page .pdm-item:hover { + border-color: var(--pdm-color-border-strong); + box-shadow: var(--pdm-shadow); +} + +body.mstv-admin-page .pdm-item.selected { + background: var(--pdm-color-primary-soft); + border-color: var(--pdm-color-primary); + box-shadow: 0 0 0 1px var(--pdm-color-primary); +} + +body.mstv-admin-page .pdm-item-icon { + margin-bottom: 10px; +} + +body.mstv-admin-page .pdm-item-name { + font-size: 13px; + font-weight: 500; + line-height: 1.4; +} + +body.mstv-admin-page .pdm-item-meta { + margin-top: 3px; + font-size: 11.5px; +} + +body.mstv-admin-page .pdm-list-item { + padding: 10px 14px; + border-radius: var(--pdm-radius); + gap: 12px; +} + +body.mstv-admin-page .pdm-list-item:hover { + border-color: var(--pdm-color-border-strong); + background: var(--pdm-color-bg-secondary); +} + +body.mstv-admin-page .pdm-list-item.selected { + background: var(--pdm-color-primary-soft); + border-color: var(--pdm-color-primary); +} + +body.mstv-admin-page .pdm-list-item-name { + font-size: 13px; + font-weight: 500; +} + +body.mstv-admin-page .pdm-list-item-meta { + font-size: 12px; +} + +body.mstv-admin-page .pdm-pagination { + margin-top: 22px; + padding-top: 16px; +} + +body.mstv-admin-page .pdm-pagination-summary, +body.mstv-admin-page .pdm-pagination-status { + font-size: 12.5px; +} + +body.mstv-admin-page .pdm-pagination-btn { + min-height: 32px; +} + +body.mstv-admin-page .pdm-loading { + font-size: 13px; + color: var(--pdm-color-text-muted); +} + +/* ---- File details panel ------------------------------------- */ + +body.mstv-admin-page .pdm-details-header { + padding: 18px 20px; +} + +body.mstv-admin-page .pdm-details-name { + font-size: 15px; + line-height: 1.35; +} + +body.mstv-admin-page .pdm-details-preview { + background: var(--pdm-color-bg); + border: 1px solid var(--pdm-color-border); + border-radius: 10px; +} + +body.mstv-admin-page .pdm-details-body { + padding: 18px 20px; +} + +body.mstv-admin-page .pdm-details-section-title { + margin-bottom: 8px; + font-size: 10.5px; + letter-spacing: 0.08em; + color: var(--pdm-color-text-muted); +} + +body.mstv-admin-page .pdm-details-row { + padding: 7px 0; + font-size: 13px; +} + +body.mstv-admin-page .pdm-details-row-label { + color: var(--pdm-color-text-muted); +} + +body.mstv-admin-page .pdm-details-actions { + padding: 16px 20px; + gap: 8px; + background: #fbfcfe; + flex-shrink: 0; +} + +body.mstv-admin-page .pdm-details-empty { + color: var(--pdm-color-text-muted); +} + +body.mstv-admin-page .pdm-details-empty p { + max-width: 220px; + font-size: 13px; + line-height: 1.5; +} + +/* ---- Empty states, modals, toasts --------------------------- */ + +body.mstv-admin-page .pdm-empty-state { + padding: 60px 24px; + color: var(--pdm-color-text-muted); +} + +body.mstv-admin-page .pdm-empty-state > svg { + width: 56px; + height: 56px; + margin-bottom: 18px; + padding: 15px; + box-sizing: content-box; + border-radius: 50%; + background: #eef2f7; + color: var(--pdm-color-text-secondary); + opacity: 1; +} + +body.mstv-admin-page .pdm-empty-state h3 { + margin-bottom: 6px; + font-size: 17px; +} + +body.mstv-admin-page .pdm-empty-state p { + max-width: 460px; + font-size: 13.5px; + line-height: 1.55; +} + +body.mstv-admin-page .pdm-empty-state--dropzone { + margin: 20px; + background: #fbfcfe; + border-color: var(--pdm-color-border-strong); + border-radius: 14px; +} + +body.mstv-admin-page .pdm-empty-actions { + margin-top: 20px; +} + +body.mstv-admin-page .pdm-modal-content { + border: 1px solid var(--pdm-color-border); + border-radius: 14px; +} + +body.mstv-admin-page .pdm-modal-header { + padding: 16px 20px; +} + +body.mstv-admin-page .pdm-modal-title { + font-size: 16px; + letter-spacing: -0.01em; +} + +body.mstv-admin-page .pdm-modal-body { + padding: 20px; +} + +body.mstv-admin-page .pdm-modal-footer { + padding: 14px 20px; + background: #fbfcfe; +} + +body.mstv-admin-page .pdm-upload-overlay { + background: rgb(15 23 42 / 0.55); +} + +body.mstv-admin-page .pdm-upload-dropzone { + max-width: min(560px, calc(100vw - 32px)); + padding: 46px 48px; + border-radius: 16px; + box-shadow: var(--pdm-shadow-lg); +} + +body.mstv-admin-page .pdm-upload-text { + font-size: 17px; + font-weight: 600; +} + +body.mstv-admin-page .pdm-toast { + padding: 12px 16px; + border: 1px solid var(--pdm-color-border); + border-left: 3px solid var(--pdm-color-primary); + border-radius: 10px; +} + +body.mstv-admin-page .pdm-toast-message { + font-size: 13px; +} + +body.mstv-admin-page .pdm-toast-icon--success { + color: var(--pdm-color-success-text); +} + +body.mstv-admin-page .pdm-toast-icon--error { + color: var(--pdm-color-danger-text); +} + +body.mstv-admin-page .pdm-toast-icon--warning { + color: var(--pdm-color-warning-text); +} + +body.mstv-admin-page .context-menu { + padding: 5px; + border-radius: 10px; +} + +body.mstv-admin-page .context-menu-item { + padding: 8px 10px; + border-radius: 6px; +} + +body.mstv-admin-page .pdm-user-result { + padding: 9px 10px; + border-radius: 6px; +} + +body.mstv-admin-page .pdm-user-tag { + padding: 5px 10px; + background: var(--pdm-color-primary-soft); + border: 1px solid var(--pdm-color-primary-light); + border-radius: 999px; +} + +/* ---- Notices ------------------------------------------------ */ + +body.mstv-admin-page .pdm-notice { + padding: 11px 14px; + border: 1px solid transparent; + border-left-width: 4px; + border-radius: var(--pdm-radius); + font-size: 13px; + line-height: 1.5; +} + +body.mstv-admin-page .pdm-notice-success { + background: var(--pdm-color-success-light); + border-color: #bbf7d0; + border-left-color: var(--pdm-color-success); + color: var(--pdm-color-success-text); +} + +body.mstv-admin-page .pdm-notice-error { + background: var(--pdm-color-danger-light); + border-color: #fecaca; + border-left-color: var(--pdm-color-danger); + color: var(--pdm-color-danger-text); +} + +/* ---- Tables and status chips -------------------------------- */ + +body.mstv-admin-page .pdm-table { + font-size: 13px; +} + +body.mstv-admin-page .pdm-table th { + padding: 11px 16px; + font-size: 11px; + font-weight: 600; + letter-spacing: 0.05em; + text-transform: uppercase; + color: var(--pdm-color-text-muted); + background: var(--pdm-color-bg); + border-bottom: 1px solid var(--pdm-color-border); +} + +body.mstv-admin-page .pdm-table td { + padding: 13px 16px; + vertical-align: middle; +} + +body.mstv-admin-page .pdm-table td:first-child { + white-space: nowrap; +} + +body.mstv-admin-page .pdm-table tbody tr:hover td { + background: #fbfcfe; +} + +body.mstv-admin-page .pdm-table-responsive { + overflow-x: auto; + background: var(--pdm-color-bg-secondary); + border: 1px solid var(--pdm-color-border); + border-radius: 10px; +} + +body.mstv-admin-page .pdm-table-responsive .pdm-table { + min-width: 720px; +} + +body.mstv-admin-page .pdm-log-action { + padding: 3px 9px; + border-radius: 999px; + font-size: 10.5px; + font-weight: 600; + letter-spacing: 0.05em; + text-transform: uppercase; +} + +body.mstv-admin-page .pdm-log-action--upload, +body.mstv-admin-page .pdm-log-action--create { + background: var(--pdm-color-success-light); + color: var(--pdm-color-success-text); +} + +body.mstv-admin-page .pdm-log-action--download { + background: var(--pdm-color-primary-light); + color: var(--pdm-color-primary); +} + +body.mstv-admin-page .pdm-log-action--delete { + background: var(--pdm-color-danger-light); + color: var(--pdm-color-danger-text); +} + +body.mstv-admin-page .pdm-log-action--rename, +body.mstv-admin-page .pdm-log-action--move { + background: var(--pdm-color-warning-light); + color: var(--pdm-color-warning-text); +} + +body.mstv-admin-page .pdm-log-context { + max-width: 260px; + padding: 3px 8px; + background: var(--pdm-color-bg); + border: 1px solid var(--pdm-color-border); + border-radius: 6px; +} + +body.mstv-admin-page .pdm-logs-toolbar { + flex-wrap: wrap; + gap: 12px; + margin-bottom: 16px; +} + +body.mstv-admin-page .pdm-inline-form .pdm-select { + min-width: 78px; +} + +/* ---- Governance screens ------------------------------------- */ + +body.mstv-admin-page .pdm-governance-wrap .pdm-section-title { + margin: 26px 0 12px; + font-size: 15px; +} + +body.mstv-admin-page .pdm-governance-wrap .pdm-section-title:first-child { + margin-top: 0; +} + +body.mstv-admin-page .mstv-notif-events, +body.mstv-admin-page .mstv-notif-groups { + gap: 6px; +} + +body.mstv-admin-page .mstv-notifications-body .pdm-field-label { + margin-top: 18px; +} + +body.mstv-admin-page .mstv-quotas-enable { + display: inline-flex; + margin: 0 0 20px; + padding: 10px 14px; + background: var(--pdm-color-bg); + border: 1px solid var(--pdm-color-border); + border-radius: 10px; +} + +body.mstv-admin-page .mstv-groups-list { + gap: 16px; + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); +} + +body.mstv-admin-page .mstv-group-card { + gap: 14px; + padding: 18px; + border-radius: 10px; + transition: border-color 0.15s ease, box-shadow 0.15s ease; +} + +body.mstv-admin-page .mstv-group-card:hover { + border-color: var(--pdm-color-border-strong); + box-shadow: var(--pdm-shadow); +} + +body.mstv-admin-page .mstv-group-name { + font-size: 15px; + line-height: 1.35; +} + +body.mstv-admin-page .mstv-group-meta { + font-size: 12px; +} + +body.mstv-admin-page .mstv-groups-list > .pdm-perm-empty { + grid-column: 1 / -1; + margin: 0; + padding: 52px 24px; + background: #fbfcfe; + border: 1px dashed var(--pdm-color-border-strong); + border-radius: 12px; + font-size: 13px; +} + +body.mstv-admin-page .mstv-reports-body > .pdm-perm-empty { + margin: 0; + padding: 56px 24px; + background: #fbfcfe; + border: 1px dashed var(--pdm-color-border-strong); + border-radius: 12px; + color: var(--pdm-color-text-muted); + font-size: 13px; +} + +body.mstv-admin-page .mstv-groups-list > .pdm-perm-empty, +body.mstv-admin-page .mstv-reports-body > .pdm-perm-empty { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 10px; + box-sizing: border-box; + width: 100%; + max-width: 100%; + margin-left: auto; + margin-right: auto; + text-align: center; +} + +body.mstv-admin-page .mstv-groups-list > .pdm-perm-empty::before, +body.mstv-admin-page .mstv-reports-body > .pdm-perm-empty::before { + content: ""; + width: 40px; + height: 40px; + background-color: var(--pdm-color-border-strong); + -webkit-mask-position: center; + mask-position: center; + -webkit-mask-repeat: no-repeat; + mask-repeat: no-repeat; + -webkit-mask-size: 40px 40px; + mask-size: 40px 40px; +} + +body.mstv-admin-page .mstv-groups-list > .pdm-perm-empty::before { + -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2'/%3E%3Ccircle cx='9' cy='7' r='4'/%3E%3Cpath d='M23 21v-2a4 4 0 0 0-3-3.87'/%3E%3Cpath d='M16 3.13a4 4 0 0 1 0 7.75'/%3E%3C/svg%3E"); + mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2'/%3E%3Ccircle cx='9' cy='7' r='4'/%3E%3Cpath d='M23 21v-2a4 4 0 0 0-3-3.87'/%3E%3Cpath d='M16 3.13a4 4 0 0 1 0 7.75'/%3E%3C/svg%3E"); +} + +body.mstv-admin-page .mstv-reports-body > .pdm-perm-empty::before { + -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='20' x2='18' y2='10'/%3E%3Cline x1='12' y1='20' x2='12' y2='4'/%3E%3Cline x1='6' y1='20' x2='6' y2='14'/%3E%3C/svg%3E"); + mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='20' x2='18' y2='10'/%3E%3Cline x1='12' y1='20' x2='12' y2='4'/%3E%3Cline x1='6' y1='20' x2='6' y2='14'/%3E%3C/svg%3E"); +} + +body.mstv-admin-page .mstv-reports-filters { + align-items: flex-end; + gap: 14px; + margin: 0 0 24px; + padding: 16px; + background: var(--pdm-color-bg); + border: 1px solid var(--pdm-color-border); + border-radius: 10px; +} + +body.mstv-admin-page .mstv-filter { + gap: 6px; + font-size: 11px; + font-weight: 600; + letter-spacing: 0.04em; + text-transform: uppercase; + color: var(--pdm-color-text-muted); +} + +body.mstv-admin-page .mstv-filter .pdm-select, +body.mstv-admin-page .mstv-filter .pdm-input { + min-width: 170px; +} + +body.mstv-admin-page .pdm-perm-table-wrap { + margin: 0 0 16px; + background: var(--pdm-color-bg-secondary); + border: 1px solid var(--pdm-color-border); + border-radius: 10px; +} + +body.mstv-admin-page .pdm-perm-table { + min-width: 520px; +} + +body.mstv-admin-page .pdm-perm-table th { + padding: 10px 12px; + background: var(--pdm-color-bg); + border-bottom: 1px solid var(--pdm-color-border); + font-size: 11px; + font-weight: 600; + letter-spacing: 0.05em; + text-transform: uppercase; + color: var(--pdm-color-text-muted); +} + +body.mstv-admin-page .pdm-perm-table td { + padding: 10px 12px; + vertical-align: middle; +} + +body.mstv-admin-page .pdm-perm-table tbody tr:hover td { + background: #fbfcfe; +} + +body.mstv-admin-page .pdm-perm-table td.pdm-perm-empty { + padding: 34px 20px; + color: var(--pdm-color-text-muted); + font-size: 13px; +} + +body.mstv-admin-page .pdm-perm-add { + gap: 10px; + margin-top: 0; + padding: 14px; + background: var(--pdm-color-bg); + border: 1px solid var(--pdm-color-border); + border-radius: 10px; +} + +body.mstv-admin-page .pdm-perm-add-user, +body.mstv-admin-page .pdm-perm-add-group { + flex: 1 1 240px; +} + +body.mstv-admin-page .mstv-quota-mb { + width: 96px; +} + +body.mstv-admin-page .mstv-governance-footer { + position: sticky; + bottom: 0; + z-index: 5; + display: flex; + justify-content: flex-end; + gap: 8px; + margin-top: 24px; + padding: 14px 0 max(14px, env(safe-area-inset-bottom)); + background: var(--pdm-color-bg-secondary); + border-top: 1px solid var(--pdm-color-border); +} + +body.mstv-admin-page .mstv-chip { + background: var(--pdm-color-bg); + border: 1px solid var(--pdm-color-border); + font-size: 12px; +} + +/* ---- Settings and Activity Log ------------------------------ */ + +body.mstv-admin-page .pdm-settings-section { + margin-bottom: 30px; + padding-bottom: 30px; +} + +body.mstv-admin-page .pdm-settings-section--danger { + margin: 0; + padding: 20px; + background: #fef2f2; + border: 1px solid #fecaca; + border-radius: 12px; +} + +body.mstv-admin-page .pdm-settings-section--danger .pdm-section-title { + color: #991b1b; +} + +body.mstv-admin-page .pdm-settings-section--danger .pdm-field-desc { + color: #7f1d1d; +} + +body.mstv-admin-page .pdm-settings-actions { + position: sticky; + bottom: 0; + z-index: 5; + display: flex; + justify-content: flex-end; + margin: 8px 0 0; + padding: 14px 0 max(14px, env(safe-area-inset-bottom)); + background: var(--pdm-color-bg-secondary); + border-top: 1px solid var(--pdm-color-border); +} + +body.mstv-admin-page .pdm-settings-actions input[type="submit"] { + min-height: 38px; + padding: 8px 16px; + background: var(--pdm-color-primary); + border: 1px solid var(--pdm-color-primary); + border-radius: var(--pdm-radius); + color: #ffffff; + font-size: 13px; + font-weight: 500; + line-height: 1.2; + text-shadow: none; + box-shadow: none; + cursor: pointer; +} + +body.mstv-admin-page .pdm-settings-actions input[type="submit"]:hover { + background: var(--pdm-color-primary-hover); + border-color: var(--pdm-color-primary-hover); +} + +body.mstv-admin-page .pdm-settings-info { + margin-top: 36px; + padding: 20px; + background: var(--pdm-color-bg); + border: 1px solid var(--pdm-color-border); + border-radius: 12px; +} + +body.mstv-admin-page .pdm-settings-info li { + padding: 5px 0; + line-height: 1.55; + word-break: break-word; +} + +body.mstv-admin-page .pdm-settings-info code { + padding: 1px 5px; + background: var(--pdm-color-bg-secondary); + border: 1px solid var(--pdm-color-border); + border-radius: 4px; +} + +/* ---- Keyboard focus ----------------------------------------- */ + +body.mstv-admin-page :is(.pdm-wrapper, .pdm-modal, .pdm-upload-overlay, .pdm-preview-modal, .pdm-toast-container, .pdm-governance-wrap) :is(button, a[href], select, input[type="checkbox"], input[type="radio"], input[type="date"], [tabindex]):focus-visible { + outline: 2px solid var(--pdm-color-primary); + outline-offset: 2px; +} + +/* Overlays own the whole viewport, including the WordPress admin chrome. */ +body.mstv-admin-page .pdm-modal, +body.mstv-admin-page .pdm-upload-overlay, +body.mstv-admin-page .pdm-preview-modal { + z-index: 100000; +} + +body.mstv-admin-page .context-menu { + z-index: 100001; +} + +body.mstv-admin-page .pdm-toast-container { + z-index: 100002; +} + +/* ---- Responsive: compact toolbar on narrower desktops ------- */ + +@media (min-width: 769px) and (max-width: 1460px) { + body.mstv-admin-page .pdm-toolbar { + padding: 10px 16px; + gap: 8px; + } + + body.mstv-admin-page .pdm-toolbar-right { + gap: 6px; + } + + /* Sort and page size stay reachable through the filter popover; the + breadcrumb remains visible wherever it fits. */ + body.mstv-admin-page .pdm-sort-dropdown { + display: none; + } + + body.mstv-admin-page .pdm-toolbar-filters { + display: flex; + } + + body.mstv-admin-page .pdm-filters-toggle { + display: inline-flex !important; + } + + /* Keep the per-page control visually compact without dropping its label for + assistive technologies. */ + body.mstv-admin-page .pdm-page-size-control .pdm-toolbar-label { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + overflow: hidden; + clip: rect(0 0 0 0); + white-space: nowrap; + border: 0; + } +} + +/* From this width the toolbar has room for the visible per-page label again. */ +@media (min-width: 1024px) and (max-width: 1460px) { + body.mstv-admin-page .pdm-page-size-control .pdm-toolbar-label { + position: static; + width: auto; + height: auto; + margin: 0; + padding: 0; + overflow: visible; + clip: auto; + white-space: nowrap; + border: 0; + } +} + +/* ---- Responsive: mobile toolbar ----------------------------- */ + +@media (max-width: 768px) { + body.mstv-admin-page .pdm-toolbar { + position: relative; + flex-wrap: wrap; + overflow: visible; + padding: 10px 12px; + gap: 8px; + } + + body.mstv-admin-page .pdm-toolbar-left { + min-width: 0; + } + + body.mstv-admin-page .pdm-toolbar-right { + flex: 1 1 auto; + flex-wrap: wrap; + justify-content: flex-end; + gap: 6px; + min-width: 0; + } + + body.mstv-admin-page .pdm-page-size-control, + body.mstv-admin-page .pdm-sort-dropdown { + display: none; + } + + /* Keep the filter dropdown available as a real popover instead of an + always-open row that used to clip the Export and Upload actions. */ + body.mstv-admin-page .pdm-filters-toggle { + display: inline-flex !important; + } + + body.mstv-admin-page .pdm-toolbar-filters { + position: static; + } + + body.mstv-admin-page .pdm-toolbar-filters-dropdown { + position: absolute; + top: calc(100% + 8px); + right: 12px; + left: 12px; + display: none !important; + flex-direction: column; + gap: 10px; + width: auto; + min-width: 0; + margin: 0; + padding: 12px; + background: var(--pdm-color-bg-secondary); + border: 1px solid var(--pdm-color-border); + border-radius: 10px; + box-shadow: var(--pdm-shadow-lg); + z-index: 70; + } + + body.mstv-admin-page .pdm-toolbar-filters-dropdown.active { + display: flex !important; + } + + body.mstv-admin-page .pdm-toolbar-filters-row { + display: flex; + flex-direction: column; + align-items: stretch; + gap: 6px; + margin-bottom: 0; + } + + body.mstv-admin-page .pdm-toolbar-filters-label { + display: block; + } + + body.mstv-admin-page .pdm-toolbar-filters-select, + body.mstv-admin-page .pdm-filters-sort { + width: 100%; + min-height: 38px; + } + + body.mstv-admin-page .pdm-view-toggle .pdm-btn { + width: 38px; + height: 34px; + min-height: 34px; + } + + body.mstv-admin-page .pdm-content { + padding: 14px 12px 20px; + } +} + +@media (max-width: 600px) { + body.mstv-admin-page :is(.mstv-governance-title, .pdm-settings-title, .pdm-logs-title) { + font-size: 21px; + } + + body.mstv-admin-page :is(.mstv-governance-header, .pdm-settings-header, .pdm-logs-header) { + margin-bottom: 20px; + padding-bottom: 16px; + } + + body.mstv-admin-page .mstv-governance-header .pdm-btn { + width: 100%; + } + + /* Icon-only Export keeps the primary actions on one row; the label stays in + the accessibility tree instead of being removed with display: none. */ + body.mstv-admin-page #pdm-export-btn { + width: 36px; + min-width: 36px; + padding: 0; + } + + body.mstv-admin-page #pdm-export-btn span { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + overflow: hidden; + clip: rect(0 0 0 0); + white-space: nowrap; + border: 0; + } + + body.mstv-admin-page .pdm-toolbar { + gap: 6px; + } + + body.mstv-admin-page .mstv-groups-list { + grid-template-columns: 1fr; + } + + body.mstv-admin-page .mstv-reports-filters { + flex-direction: column; + align-items: stretch; + } + + body.mstv-admin-page .mstv-filter .pdm-select, + body.mstv-admin-page .mstv-filter .pdm-input { + min-width: 0; + width: 100%; + } + + body.mstv-admin-page .mstv-reports-filters .pdm-btn { + width: 100%; + } + + body.mstv-admin-page .pdm-perm-add { + flex-direction: column; + } + + /* An empty quota table has no columns worth scrolling for: let the message + wrap inside the card instead of being clipped by the horizontal scroller. */ + body.mstv-admin-page .pdm-perm-table-wrap:has(.pdm-perm-empty) { + overflow-x: hidden; + } + + body.mstv-admin-page .pdm-perm-table-wrap:has(.pdm-perm-empty) .pdm-perm-table { + min-width: 0; + } + + body.mstv-admin-page .pdm-perm-add-user, + body.mstv-admin-page .pdm-perm-add-group { + flex: 1 1 100%; + width: 100%; + } + + body.mstv-admin-page .mstv-governance-footer .pdm-btn { + width: 100%; + } + + body.mstv-admin-page .pdm-settings-actions { + justify-content: stretch; + } + + body.mstv-admin-page .pdm-settings-actions input[type="submit"] { + width: 100%; + } + + body.mstv-admin-page .pdm-logs-toolbar { + flex-direction: column; + align-items: stretch; + gap: 12px; + } + + body.mstv-admin-page .pdm-logs-toolbar .pdm-inline-form { + flex-direction: row; + align-items: center; + flex-wrap: wrap; + gap: 8px; + } + + body.mstv-admin-page .pdm-inline-form .pdm-select { + flex: 1 1 90px; + } + + body.mstv-admin-page .pdm-pagination { + align-items: stretch; + gap: 12px; + } + + body.mstv-admin-page .pdm-pagination-controls { + justify-content: space-between; + } + + body.mstv-admin-page .pdm-upload-dropzone { + padding: 36px 22px; + } + + body.mstv-admin-page .pdm-upload-text { + font-size: 16px; + } + + body.mstv-admin-page .pdm-empty-state { + padding: 44px 18px; + } +} + +@media (max-width: 480px) { + body.mstv-admin-page .pdm-content-grid { + grid-template-columns: repeat(auto-fill, minmax(148px, 1fr)); + gap: 10px; + } + + body.mstv-admin-page .pdm-content { + padding: 12px 10px 18px; + } +} + +@media (max-width: 782px) { + body.mstv-admin-page .pdm-settings-wrapper, + body.mstv-admin-page .pdm-logs-wrapper, + body.mstv-admin-page .pdm-governance-wrap { + min-height: calc(100dvh - var(--pdm-admin-bar-offset)); + } + + body.mstv-admin-page .pdm-settings-wrapper > *, + body.mstv-admin-page .pdm-governance-wrap > * { + max-width: 100%; + } +} + +/* ---- Touch targets ------------------------------------------ */ + +@media (hover: none) and (pointer: coarse) { + body.mstv-admin-page .pdm-btn { + min-height: 44px; + padding: 10px 16px; + } + + body.mstv-admin-page .pdm-btn-icon { + width: 44px; + height: 44px; + min-width: 44px; + min-height: 44px; + padding: 0; + } + + body.mstv-admin-page .pdm-folder-item { + min-height: 44px; + padding: 10px 12px; + } + + body.mstv-admin-page .pdm-input, + body.mstv-admin-page .pdm-select { + min-height: 44px; + } + + body.mstv-admin-page .pdm-toolbar-filters-select { + min-height: 44px; + } + + body.mstv-admin-page .pdm-view-toggle .pdm-btn { + width: 44px; + height: 40px; + min-height: 40px; + } +} + diff --git a/assets/js/admin-app-core.js b/assets/js/admin-app-core.js index 992060b..39db320 100644 --- a/assets/js/admin-app-core.js +++ b/assets/js/admin-app-core.js @@ -174,6 +174,7 @@ if (e.key === 'Escape') { this.closeMobilePanels(); this.elements.filtersDropdown?.classList.remove('active'); + this.elements.filtersToggle?.setAttribute('aria-expanded', 'false'); this.hideContextMenu(); this.hideModal(); this.hidePreview(); @@ -184,6 +185,7 @@ document.addEventListener('click', (e) => { if (!e.target.closest('.pdm-toolbar-filters') && !e.target.closest('.pdm-toolbar-filters-dropdown')) { this.elements.filtersDropdown?.classList.remove('active'); + this.elements.filtersToggle?.setAttribute('aria-expanded', 'false'); } }); @@ -1923,6 +1925,8 @@ this.elements.filtersPerPage.value = String(this.state.pagination.perPage); } } + + this.elements.filtersToggle?.setAttribute('aria-expanded', dropdown.classList.contains('active') ? 'true' : 'false'); }, clearDetails() { diff --git a/assets/js/admin-app-governance.js b/assets/js/admin-app-governance.js index e5ed83a..3ebcbe6 100644 --- a/assets/js/admin-app-governance.js +++ b/assets/js/admin-app-governance.js @@ -297,7 +297,7 @@
- +
diff --git a/includes/class-mstv-assets.php b/includes/class-mstv-assets.php index 536ab82..783d526 100644 --- a/includes/class-mstv-assets.php +++ b/includes/class-mstv-assets.php @@ -10,13 +10,40 @@ public function __construct(MSTV_Settings $settings) { $this->settings = $settings; add_action('admin_enqueue_scripts', [$this, 'enqueue_assets']); + add_filter('admin_body_class', [$this, 'add_admin_body_class']); + } + + /** + * Mark every TeamVault screen so admin.css can drop the WordPress admin chrome + * (the footer band and the wrapper gaps) from all plugin pages, not just the + * full-viewport File Manager. + * + * @param string $classes Space-separated admin body classes. + * @return string + */ + public function add_admin_body_class($classes): string + { + $classes = is_string($classes) ? trim($classes) : ''; + + if (!$this->is_teamvault_screen()) { + return $classes; + } + + return $classes === '' ? 'mstv-admin-page' : $classes . ' mstv-admin-page'; + } + + private function is_teamvault_screen(): bool + { + $screen = function_exists('get_current_screen') ? get_current_screen() : null; + + return $screen !== null + && isset($screen->id) + && strpos((string) $screen->id, 'mikesoft-teamvault') !== false; } public function enqueue_assets(string $hook): void { - $screen = get_current_screen(); - - if (!$screen || strpos($screen->id, 'mikesoft-teamvault') === false) { + if (!$this->is_teamvault_screen()) { return; } @@ -217,6 +244,7 @@ public function enqueue_assets(string $hook): void // Governance: groups. 'groupsEmpty' => __('No groups yet. Create one to organize document access.', 'mikesoft-teamvault'), 'groupsMembers' => __('members', 'mikesoft-teamvault'), + 'groupsMembersLabel' => __('Members', 'mikesoft-teamvault'), 'groupsName' => __('Group name', 'mikesoft-teamvault'), 'groupsDescription' => __('Description', 'mikesoft-teamvault'), 'groupsNew' => __('New group', 'mikesoft-teamvault'), diff --git a/includes/class-mstv-i18n.php b/includes/class-mstv-i18n.php index 50599ed..c7f7298 100644 --- a/includes/class-mstv-i18n.php +++ b/includes/class-mstv-i18n.php @@ -92,6 +92,7 @@ class MSTV_I18n 'You do not have permission to manage this folder.' => 'Non hai i permessi per gestire questa cartella.', 'You do not have permission to perform this action.' => 'Non hai i permessi per eseguire questa azione.', 'members' => 'membri', + 'Members' => 'Membri', 'A folder with this name already exists.' => 'Esiste già una cartella con questo nome.', 'Access denied.' => 'Accesso negato.', 'Action' => 'Azione', @@ -413,6 +414,7 @@ class MSTV_I18n 'You do not have permission to manage this folder.' => 'Vous n\'avez pas l\'autorisation de gérer ce dossier.', 'You do not have permission to perform this action.' => 'Vous n\'avez pas l\'autorisation d\'effectuer cette action.', 'members' => 'membres', + 'Members' => 'Membres', 'A folder with this name already exists.' => 'Un dossier portant ce nom existe déjà.', 'Access denied.' => 'Accès refusé.', 'Action' => 'Action', @@ -734,6 +736,7 @@ class MSTV_I18n 'You do not have permission to manage this folder.' => 'No tienes permiso para gestionar esta carpeta.', 'You do not have permission to perform this action.' => 'No tienes permiso para realizar esta acción.', 'members' => 'miembros', + 'Members' => 'Miembros', 'A folder with this name already exists.' => 'Ya existe una carpeta con este nombre.', 'Access denied.' => 'Acceso denegado.', 'Action' => 'Acción', @@ -1055,6 +1058,7 @@ class MSTV_I18n 'You do not have permission to manage this folder.' => 'Sie haben keine Berechtigung, diesen Ordner zu verwalten.', 'You do not have permission to perform this action.' => 'Sie haben keine Berechtigung, diese Aktion auszuführen.', 'members' => 'Mitglieder', + 'Members' => 'Mitglieder', 'A folder with this name already exists.' => 'Ein Ordner mit diesem Namen existiert bereits.', 'Access denied.' => 'Zugriff verweigert.', 'Action' => 'Aktion', diff --git a/tests/PDMAdminAppTest.php b/tests/PDMAdminAppTest.php index 4c075d1..8aa7e96 100644 --- a/tests/PDMAdminAppTest.php +++ b/tests/PDMAdminAppTest.php @@ -168,6 +168,73 @@ public function testDetailsDrawerCssAccountsForTheAdminMenuAndRespectsAdminBarOf ); } + public function testTeamVaultCssRemovesAdminChromeFromEveryPluginScreen(): void + { + $source = (string) file_get_contents(dirname(__DIR__) . '/assets/css/admin.css'); + + self::assertStringContainsString( + 'body.mstv-admin-page #wpfooter', + $source, + 'Every TeamVault screen must hide the WordPress admin footer band.' + ); + self::assertStringContainsString( + 'body.mstv-admin-page #wpbody-content', + $source, + 'Every TeamVault screen must remove the admin bottom padding under its panels.' + ); + self::assertStringContainsString( + 'body.mstv-admin-page .pdm-wrapper', + $source, + 'Panel wrappers on TeamVault screens must drop the 20px gap above and below the panel.' + ); + self::assertStringContainsString( + 'height: calc(100vh - var(--pdm-admin-bar-offset));', + $source, + 'The File Manager wrapper must fill exactly the viewport below the admin bar.' + ); + self::assertStringContainsString( + 'body.toplevel_page_mikesoft-teamvault .pdm-sidebar', + $source, + 'The File Manager sidebar must stretch to the app height so the storage panel reaches the bottom edge.' + ); + } + + public function testDesignSystemUnifiesEveryPluginScreen(): void + { + $css = (string) file_get_contents(dirname(__DIR__) . '/assets/css/admin.css'); + + self::assertStringContainsString( + 'body.mstv-admin-page .pdm-settings-wrapper,', + $css, + 'Settings, Activity Log and governance screens must share the same page canvas.' + ); + self::assertStringContainsString( + 'body.mstv-admin-page .pdm-logs-wrapper,', + $css, + 'The Activity Log must use the shared page canvas.' + ); + self::assertStringContainsString( + 'body.mstv-admin-page .pdm-governance-wrap > *', + $css, + 'Governance screens must share the constrained content width.' + ); + self::assertStringContainsString( + 'body.mstv-admin-page .mstv-governance-footer', + $css, + 'Governance save bars must share the sticky action pattern.' + ); + self::assertStringContainsString( + 'body.mstv-admin-page .pdm-settings-actions', + $css, + 'Settings must keep its save action visible while scrolling.' + ); + self::assertStringContainsString( + "setAttribute('aria-expanded'", + $this->adminAppSource(), + 'The filter popover toggle must expose its expanded state.' + ); + } + public function testDeleteAndMutationErrorsSurfaceServerMessages(): void { $source = $this->adminAppSource(); diff --git a/tests/PDMAdminHandlersTest.php b/tests/PDMAdminHandlersTest.php index 18552fa..06e3f68 100644 --- a/tests/PDMAdminHandlersTest.php +++ b/tests/PDMAdminHandlersTest.php @@ -81,6 +81,7 @@ public function test_file_manager_page_renders_for_authorized_users(): void self::assertStringContainsString('pdm-app', $html); self::assertStringContainsString('pdm-folder-tree', $html); + self::assertStringContainsString('screen-reader-text', $html); } public function test_handle_save_settings_rejects_unsupported_interface_language(): void diff --git a/tests/PDMAssetsTest.php b/tests/PDMAssetsTest.php index efe7be0..79dbc35 100644 --- a/tests/PDMAssetsTest.php +++ b/tests/PDMAssetsTest.php @@ -6,6 +6,11 @@ final class PDMAssetsTest extends TestCase { + protected function tearDown(): void + { + $GLOBALS['pdm_test_current_screen_id'] = ''; + } + public function test_effective_client_upload_limit_uses_lowest_positive_limit(): void { $assets = new MSTV_Assets(new MSTV_Settings()); @@ -14,4 +19,18 @@ public function test_effective_client_upload_limit_uses_lowest_positive_limit(): self::assertSame(5 * 1024 * 1024, $method->invoke($assets, 50 * 1024 * 1024, '8M', '5M')); } + + public function test_admin_body_class_marks_only_teamvault_screens(): void + { + $assets = new MSTV_Assets(new MSTV_Settings()); + + $GLOBALS['pdm_test_current_screen_id'] = 'teamvault_page_mikesoft-teamvault-settings'; + self::assertSame('wp-admin mstv-admin-page', $assets->add_admin_body_class('wp-admin')); + + $GLOBALS['pdm_test_current_screen_id'] = 'toplevel_page_mikesoft-teamvault'; + self::assertSame('wp-admin mstv-admin-page', $assets->add_admin_body_class('wp-admin')); + + $GLOBALS['pdm_test_current_screen_id'] = 'edit-post'; + self::assertSame('wp-admin', $assets->add_admin_body_class('wp-admin')); + } } diff --git a/tests/bootstrap.php b/tests/bootstrap.php index b95c7cc..68f5d97 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -30,6 +30,7 @@ $GLOBALS['pdm_test_verified_nonce_actions'] = []; $GLOBALS['pdm_test_rest_routes'] = []; $GLOBALS['pdm_test_redirects'] = []; +$GLOBALS['pdm_test_current_screen_id'] = ''; function __($text, $domain = null) { @@ -195,6 +196,13 @@ function apply_filters($hook, $value, ...$args) return $value; } +function get_current_screen() +{ + $id = (string) ($GLOBALS['pdm_test_current_screen_id'] ?? ''); + + return $id === '' ? null : (object) ['id' => $id]; +} + function wp_strip_all_tags($text) { return trim(strip_tags((string) $text)); From 046b9e499c897c2ce25b738e88be15b8be745b0e Mon Sep 17 00:00:00 2001 From: Michael Gasperini <163041857+TheStreamCode@users.noreply.github.com> Date: Thu, 22 Oct 2026 13:19:21 +0200 Subject: [PATCH 2/4] Release 3.5.0: admin design system and storage hardening --- .gitattributes | 1 + CITATION.cff | 4 ++-- changelog.txt | 10 ++++++++++ docs/maintainer/security-review.md | 16 +++++++++++++--- languages/mikesoft-teamvault.pot | 8 ++++++-- mikesoft-teamvault.php | 4 ++-- readme.txt | 14 +++++++++++++- tests/PDMReleaseMetadataTest.php | 4 ++-- 8 files changed, 49 insertions(+), 12 deletions(-) diff --git a/.gitattributes b/.gitattributes index 31544c9..28584ca 100644 --- a/.gitattributes +++ b/.gitattributes @@ -36,6 +36,7 @@ README.fr.md export-ignore README.es.md export-ignore README.de.md export-ignore COPYRIGHT.md export-ignore +CITATION.cff export-ignore SECURITY.md export-ignore SUPPORT.md export-ignore composer.json export-ignore diff --git a/CITATION.cff b/CITATION.cff index 5b30352..63330b0 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -7,8 +7,8 @@ authors: given-names: Michael url: "https://github.com/TheStreamCode/mikesoft-teamvault" repository-code: "https://github.com/TheStreamCode/mikesoft-teamvault" -version: "3.4.0" -date-released: "2026-10-21" +version: "3.5.0" +date-released: "2026-10-22" keywords: - WordPress - document management diff --git a/changelog.txt b/changelog.txt index d1832fc..0fb2c01 100644 --- a/changelog.txt +++ b/changelog.txt @@ -2,6 +2,16 @@ Mikesoft TeamVault Changelog Entries are ordered newest first. Release dates are included where recorded. +## 3.5.0 - 2026-10-22 +- Security: folder and file uniqueness is now enforced in the database through an option-guarded migration that merges existing duplicates before adding the unique keys. The lowest folder id survives; child folders, files, and per-folder rules are re-pointed to it, and duplicate subtrees are rewritten onto the surviving path. Duplicate inserts map to 409 conflicts and duplicate paths are skipped during reindexing. The auto-reindex claim is atomic and released when the scan fails. +- Security: uploads now fail closed when the private storage directory is not writable or when `.htaccess`, `web.config`, or `index.php` cannot be created, and the error names the failing files. The storage warning is persistent and non-dismissible for blocking states and for Nginx, which ignores `.htaccess`; the README documents an out-of-webroot storage path as the recommended deployment. +- Admin UI: every TeamVault screen now shares one design system: unified palette and typography tokens, full-bleed white canvas, page headers, buttons, form controls, tables, badges, empty states, spacing, and radii. +- Admin UI: the File Manager removes the WordPress footer gap and the gray bands above and below the app, fills the viewport below the admin bar, pins the storage panel to the bottom edge, and no longer clips toolbar controls at common desktop widths. The filter control opens a labeled popover, icon-only Export keeps an accessible name, and the filter toggle announces its expanded state. +- Accessibility: the File Manager exposes a screen-reader page heading, custom controls have visible keyboard focus, status badges and muted text meet AA contrast, and touch targets reach 44px on coarse pointers. +- Responsive: settings, governance tables, forms, modals, the upload overlay, and report filters adapt to 360-390px screens without horizontal page overflow; the mobile toolbar keeps Export and Upload reachable, and the detail drawer keeps every file action available. +- Fixed: secondary toolbar actions no longer hide Rename and Move in the mobile file details; the empty quota table is no longer clipped by its horizontal scroller; folder empty states size correctly at 360px; the group editor label reads "Members" and is translated in Italian, French, Spanish, and German. +- Tests: added regression coverage for the shared admin design system, the File Manager screen-reader heading, the admin body-class scope, and the filter popover state, alongside the duplicate-creation, migration-dedupe, reindex-lock, and storage-protection suites merged from the maintenance line. + ## 3.4.0 - 2026-10-21 - Feature: email notifications are folder-aware by default. Selected users and groups receive an upload, download, delete, or access-denied event only when they can view the folder that produced it, so a document name is not disclosed to a group without access. Administrators remain included when the administrator recipient option is enabled. - Feature: a Notifications setting restores the previous global recipient behavior; the `mstv_notification_recipients` filter lets site code refine the final recipient list. diff --git a/docs/maintainer/security-review.md b/docs/maintainer/security-review.md index e27b71c..321a317 100644 --- a/docs/maintainer/security-review.md +++ b/docs/maintainer/security-review.md @@ -1,8 +1,8 @@ -# Security Review — 2026-10-21 +# Security Review — 2026-10-22 ## Scope and Method -This review covers the 3.4.0 working tree: the folder-aware notification path, the permission resolver and governance REST surface, the export/temp-path handling, the validator messages, the admin JavaScript rendering layer, and the test infrastructure. It combines manual source review with the expanded PHPUnit suite, behavioral node tests for the shared helpers, PHP lint on the full tree, Composer validation and audit, JavaScript syntax checks, WordPress Plugin Check on an active local staging installation (no errors), and a WP-CLI functional notification test on that installation. It was not exercised through a browser session or a real mail transport in this cycle; those release checks remain required before publication. +This review covers the 3.5.0 working tree: the shared admin design system across the File Manager and governance screens, the accessibility and responsive changes, the database uniqueness migration and fail-closed storage protection merged from the maintenance line, and the previously reviewed permission, notification, export, and client-rendering surfaces. It combines manual source review with the full PHPUnit suite (223 tests), Composer validation, audit, and CI, PHP lint, JavaScript syntax checks, behavioral node tests, WordPress Plugin Check on a clean runtime payload (no errors), and scripted browser QA on a local WordPress 7.1.3 staging installation covering every admin screen, file upload/rename/move/download/ZIP export/delete, governance settings, maintenance tools, the 3.4.0-to-3.5.0 update path, and mobile viewports. Real mail transport, Nginx-specific storage configuration, multisite, whitelist mode, and uninstall data removal were not exercised end-to-end on the staging install in this cycle; the latter two remain covered by their PHPUnit suites. No critical issue remains open in this cycle. The findings below were fixed in the reviewed tree and carry regression coverage where practical. This document is a point-in-time engineering review, not a guarantee against every vulnerability or a substitute for production configuration testing. @@ -50,9 +50,19 @@ No critical issue remains open in this cycle. The findings below were fixed in t - Resolution: each queued event now carries its `folder_id`; non-administrator recipients are filtered through `MSTV_Permissions::user_can($userId, $folderId, 'view')`, administrators bypass the filter when the administrator recipient option is enabled, and events are grouped by recipient set so one email cannot mix files from folders with different access rules. Download events now include the folder in their hook payload. The behavior is enabled by default and can be disabled with the Notifications setting; the `mstv_notification_recipients` filter is the documented extension point. Regression tests cover group filtering, administrator bypass, direct recipients, downloads, opt-out, and cross-folder batching. - Compatibility note: existing sites begin filtering after the update; the setting restores the previous global behavior. This behavior change is called out in the upgrade notice. +### SEC-010 — Storage: duplicate rows and unprotected storage acceptance + +- Severity: Medium +- Status: Fixed in 3.5.0 +- Location: `includes/class-mstv-activator.php`, `includes/class-mstv-storage.php`, `includes/class-mstv-rest-controller.php`, `includes/class-mstv-repository-folders.php`, `includes/class-mstv-repository-files.php` +- Evidence: folder and file uniqueness was enforced only by application checks, so concurrent or legacy writes could create duplicate names or relative paths and leave ambiguous database and storage state. Separately, uploads could proceed when the private storage directory was not writable or when its protection files could not be created, leaving private documents reachable from the web root. +- Resolution: an option-guarded migration adds `UNIQUE (parent_key, name)` on folders and `UNIQUE (relative_path)` on files after a dedupe pass (lowest folder id survives; children, files, and per-folder rules are re-pointed; duplicate subtrees are rewritten). Duplicate inserts return 409 conflicts and the reindex path skips duplicates; the auto-reindex claim is atomic and released on failure. Uploads now fail closed when storage is not writable or `.htaccess`, `web.config`, and `index.php` cannot be created, reporting the failing files, and the admin notice is persistent and non-dismissible for blocking states and Nginx. Tests cover duplicate creation, migration dedupe, reindex locking, and storage protection. +- Compatibility note: the first update runs the one-time deduplication automatically; it is called out in the upgrade notice. + ## Residual Risks -- Storage protection still depends on server configuration: the generated `.htaccess`/`web.config` cover Apache/IIS, while Nginx requires an equivalent deny rule (surfaced to operators by the settings notice). +- Storage protection still depends on server configuration: the generated `.htaccess`/`web.config` cover Apache/IIS, while Nginx requires an equivalent deny rule (surfaced to operators by the persistent notice; out-of-webroot storage is the documented recommendation). - Header semantics for private streams remain guarded by source-level tests plus live HTTP verification; a CLI unit test cannot observe `header()` output. - The whitelist, quota, and notification surfaces rely on the capability floor plus, where applicable, database advisory locks; they were re-verified through the live governance battery but not fuzzed beyond their regression suites. - The notification filter resolves access per recipient and folder, which adds one cached permission lookup per event recipient; very large selected-recipient sets are bounded by the notification configuration and were not benchmarked at extreme scale. +- The uniqueness migration scans folders and files once during the upgrade; very large libraries pay a one-time upgrade cost that was not benchmarked at extreme scale. diff --git a/languages/mikesoft-teamvault.pot b/languages/mikesoft-teamvault.pot index 028cf72..33d0ceb 100644 --- a/languages/mikesoft-teamvault.pot +++ b/languages/mikesoft-teamvault.pot @@ -1,14 +1,14 @@ # /work/pot-comment.txt msgid "" msgstr "" -"Project-Id-Version: Mikesoft TeamVault 3.3.0\n" +"Project-Id-Version: Mikesoft TeamVault 3.5.0\n" "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/mikesoft-teamvault\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"POT-Creation-Date: 2026-10-11T19:51:51+00:00\n" +"POT-Creation-Date: 2026-10-22T10:45:00+00:00\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "X-Generator: WP-CLI 2.12.0\n" "X-Domain: mikesoft-teamvault\n" @@ -1050,6 +1050,10 @@ msgstr "" msgid "No groups yet. Create one to organize document access." msgstr "" +#: includes/class-mstv-assets.php:247 +msgid "Members" +msgstr "" + #: includes/class-mstv-assets.php:219 msgid "members" msgstr "" diff --git a/mikesoft-teamvault.php b/mikesoft-teamvault.php index bfc8d4d..b0cc5b4 100644 --- a/mikesoft-teamvault.php +++ b/mikesoft-teamvault.php @@ -3,7 +3,7 @@ * Plugin Name: Mikesoft TeamVault * Plugin URI: https://github.com/TheStreamCode/mikesoft-teamvault * Description: Private shared document management separated from the WordPress Media Library with secure access control, preview and drag-and-drop. - * Version: 3.4.0 + * Version: 3.5.0 * Author: Mikesoft * Author URI: https://mikesoft.it * License: GPL-2.0-or-later @@ -16,7 +16,7 @@ defined('ABSPATH') || exit; -define('MSTV_VERSION', '3.4.0'); +define('MSTV_VERSION', '3.5.0'); define('MSTV_PLUGIN_FILE', __FILE__); define('MSTV_PLUGIN_DIR', plugin_dir_path(__FILE__)); define('MSTV_PLUGIN_URL', plugin_dir_url(__FILE__)); diff --git a/readme.txt b/readme.txt index 7e1b8f6..3fc8541 100644 --- a/readme.txt +++ b/readme.txt @@ -5,7 +5,7 @@ Tags: documents, secure, collaboration, privacy, file-manager Requires at least: 6.0 Tested up to: 7.1 Requires PHP: 8.0 -Stable tag: 3.4.0 +Stable tag: 3.5.0 License: GPL-2.0-or-later License URI: https://www.gnu.org/licenses/gpl-2.0.html @@ -167,6 +167,14 @@ For direct contact, email teamvault@mikesoft.it. == Changelog == += 3.5.0 = +* Security: duplicate folder and file records are merged safely in a one-time upgrade migration, and new duplicates are rejected. +* Security: uploads fail closed when the private storage directory cannot be made writable or its protection files cannot be created, and the storage warning is persistent for blocking states and Nginx. +* New: every plugin admin screen now shares one design system, with a full-screen File Manager and consistent settings, groups, quotas, notifications, reports, and activity log layouts. +* Improved: mobile layouts, keyboard focus, touch targets, readable status badges, labeled filter popovers, accessible icon-only actions, and empty states. +* Fixed: mobile file details keep Rename and Move available, the empty quota table no longer clips, the empty folder state fits small screens, and the File Manager toolbar no longer clips controls on common desktop widths. +* Translations: refined labels in Italian, French, Spanish, and German. + = 3.4.0 = * Added: folder-aware email notifications. Selected users and groups receive an upload, download, delete, or access-denied event only when they can view the folder that produced it; administrators remain included when the administrator recipient option is enabled. * Added: a Notifications setting to restore the previous global recipient behavior, and the `mstv_notification_recipients` filter for site-specific routing. @@ -322,6 +330,10 @@ For the full release history, see `changelog.txt` in the plugin package. == Upgrade Notice == += 3.5.0 = + +The admin interface has been refreshed for consistency, mobile use, and accessibility. The first update merges any duplicate folder and file records, then rejects new duplicates, and uploads now fail closed if the private storage protection cannot be enforced. No configuration changes are required. + = 3.4.0 = Email notifications now default to folder-aware delivery: selected users and groups receive an event only if they can view the folder, while administrators remain included when enabled. A Notifications setting restores the previous global behavior. No other configuration changes are required. diff --git a/tests/PDMReleaseMetadataTest.php b/tests/PDMReleaseMetadataTest.php index 7b677bd..578add6 100644 --- a/tests/PDMReleaseMetadataTest.php +++ b/tests/PDMReleaseMetadataTest.php @@ -6,8 +6,8 @@ final class PDMReleaseMetadataTest extends TestCase { - private const RELEASE_VERSION = '3.4.0'; - private const RELEASE_DATE = '2026-10-21'; + private const RELEASE_VERSION = '3.5.0'; + private const RELEASE_DATE = '2026-10-22'; private const TESTED_UP_TO = '7.1'; private const CONTACT_EMAIL = 'teamvault@mikesoft.it'; private const PLUGIN_AUTHOR = 'Mikesoft'; From 2a89ab9328b162ff0054d9a3eddb8a3eef9b96b3 Mon Sep 17 00:00:00 2001 From: Michael Gasperini <163041857+TheStreamCode@users.noreply.github.com> Date: Thu, 22 Oct 2026 13:34:41 +0200 Subject: [PATCH 3/4] fix(admin): align admin CSS prefix and accessibility details --- assets/css/admin.css | 530 ++++++++++++++++----------------- includes/class-mstv-assets.php | 2 +- tests/PDMAdminAppTest.php | 16 +- tests/PDMAssetsTest.php | 4 +- 4 files changed, 275 insertions(+), 277 deletions(-) diff --git a/assets/css/admin.css b/assets/css/admin.css index cb0b551..e7d5d45 100644 --- a/assets/css/admin.css +++ b/assets/css/admin.css @@ -3,6 +3,8 @@ --pdm-color-primary-hover: #1d4ed8; --pdm-color-primary-light: #dbeafe; --pdm-color-primary-soft: #eff6ff; + /* Darker primary for tinted badges where #2563eb falls below AA on #dbeafe. */ + --pdm-color-primary-text: #1e40af; --pdm-color-secondary: #64748b; --pdm-color-success: #22c55e; --pdm-color-success-light: #dcfce7; @@ -83,16 +85,16 @@ * The File Manager goes one step further and fills the whole viewport below the admin * bar, so its storage panel sits on the bottom edge. */ -body.mstv-admin-page #wpfooter { +body.pdm-admin-page #wpfooter { display: none; } -body.mstv-admin-page #wpbody-content { +body.pdm-admin-page #wpbody-content { padding-bottom: 0; } -body.mstv-admin-page .pdm-wrapper { - margin: 0 0 0 -20px; +body.pdm-admin-page .pdm-wrapper { + margin: 0; } body.toplevel_page_mikesoft-teamvault .pdm-wrapper { @@ -1700,10 +1702,6 @@ body.toplevel_page_mikesoft-teamvault .pdm-sidebar { min-width: 36px; } - #pdm-export-btn span { - display: none; - } - #pdm-upload-btn { padding: 6px 9px; } @@ -2862,14 +2860,14 @@ input[type="date"]::-webkit-calendar-picker-indicator { /* ---- Page canvas -------------------------------------------- */ -body.mstv-admin-page { +body.pdm-admin-page { background: var(--pdm-color-bg); color: var(--pdm-color-text); } -body.mstv-admin-page .pdm-settings-wrapper, -body.mstv-admin-page .pdm-logs-wrapper, -body.mstv-admin-page .pdm-governance-wrap { +body.pdm-admin-page .pdm-settings-wrapper, +body.pdm-admin-page .pdm-logs-wrapper, +body.pdm-admin-page .pdm-governance-wrap { box-sizing: border-box; margin: 0 0 0 calc(-1 * var(--pdm-admin-content-pad)); padding: var(--pdm-page-pad-y) var(--pdm-page-pad-x) calc(var(--pdm-page-pad-y) + 24px); @@ -2877,28 +2875,28 @@ body.mstv-admin-page .pdm-governance-wrap { min-height: calc(100vh - var(--pdm-admin-bar-offset)); } -body.mstv-admin-page .pdm-wrapper { +body.pdm-admin-page .pdm-wrapper { margin-left: calc(-1 * var(--pdm-admin-content-pad)); } -body.mstv-admin-page .pdm-settings-wrapper { +body.pdm-admin-page .pdm-settings-wrapper { max-width: none; } /* Readable single column for the settings form. */ -body.mstv-admin-page .pdm-settings-wrapper > * { +body.pdm-admin-page .pdm-settings-wrapper > * { max-width: var(--pdm-content-max); margin-left: auto; margin-right: auto; } -body.mstv-admin-page .pdm-governance-wrap > * { +body.pdm-admin-page .pdm-governance-wrap > * { max-width: 1120px; } /* ---- Shared page headers ------------------------------------ */ -body.mstv-admin-page .mstv-governance-header { +body.pdm-admin-page .mstv-governance-header { display: flex; align-items: flex-start; justify-content: space-between; @@ -2909,26 +2907,26 @@ body.mstv-admin-page .mstv-governance-header { border-bottom: 1px solid var(--pdm-color-border); } -body.mstv-admin-page .mstv-governance-header > div { +body.pdm-admin-page .mstv-governance-header > div { flex: 1 1 auto; min-width: 0; } -body.mstv-admin-page .mstv-governance-header .pdm-btn { +body.pdm-admin-page .mstv-governance-header .pdm-btn { flex-shrink: 0; } -body.mstv-admin-page .pdm-settings-header, -body.mstv-admin-page .pdm-logs-header { +body.pdm-admin-page .pdm-settings-header, +body.pdm-admin-page .pdm-logs-header { margin-top: 0; margin-bottom: 26px; padding: 0 0 20px; border-bottom: 1px solid var(--pdm-color-border); } -body.mstv-admin-page .mstv-governance-title, -body.mstv-admin-page .pdm-settings-title, -body.mstv-admin-page .pdm-logs-title { +body.pdm-admin-page .mstv-governance-title, +body.pdm-admin-page .pdm-settings-title, +body.pdm-admin-page .pdm-logs-title { margin: 0 0 6px; font-size: 24px; line-height: 1.25; @@ -2937,9 +2935,9 @@ body.mstv-admin-page .pdm-logs-title { color: var(--pdm-color-text); } -body.mstv-admin-page .mstv-governance-subtitle, -body.mstv-admin-page .pdm-settings-desc, -body.mstv-admin-page .pdm-logs-desc { +body.pdm-admin-page .mstv-governance-subtitle, +body.pdm-admin-page .pdm-settings-desc, +body.pdm-admin-page .pdm-logs-desc { margin: 0; max-width: 680px; font-size: 14px; @@ -2949,7 +2947,7 @@ body.mstv-admin-page .pdm-logs-desc { /* ---- Buttons ------------------------------------------------ */ -body.mstv-admin-page .pdm-btn { +body.pdm-admin-page .pdm-btn { min-height: 36px; padding: 8px 14px; border: 1px solid transparent; @@ -2963,75 +2961,75 @@ body.mstv-admin-page .pdm-btn { transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease; } -body.mstv-admin-page .pdm-btn svg { +body.pdm-admin-page .pdm-btn svg { flex-shrink: 0; } -body.mstv-admin-page .pdm-btn-primary { +body.pdm-admin-page .pdm-btn-primary { background: var(--pdm-color-primary); border-color: var(--pdm-color-primary); color: #ffffff; } -body.mstv-admin-page .pdm-btn-primary:hover:not(:disabled) { +body.pdm-admin-page .pdm-btn-primary:hover:not(:disabled) { background: var(--pdm-color-primary-hover); border-color: var(--pdm-color-primary-hover); } -body.mstv-admin-page .pdm-btn-secondary { +body.pdm-admin-page .pdm-btn-secondary { background: var(--pdm-color-bg-secondary); border-color: var(--pdm-color-border); color: var(--pdm-color-text); } -body.mstv-admin-page .pdm-btn-secondary:hover:not(:disabled) { +body.pdm-admin-page .pdm-btn-secondary:hover:not(:disabled) { background: var(--pdm-color-bg); border-color: var(--pdm-color-border-strong); } -body.mstv-admin-page .pdm-btn-ghost { +body.pdm-admin-page .pdm-btn-ghost { color: var(--pdm-color-text-secondary); } -body.mstv-admin-page .pdm-btn-ghost:hover:not(:disabled) { +body.pdm-admin-page .pdm-btn-ghost:hover:not(:disabled) { background: #eef2f7; color: var(--pdm-color-text); } -body.mstv-admin-page .pdm-btn-danger { +body.pdm-admin-page .pdm-btn-danger { background: var(--pdm-color-danger); border-color: var(--pdm-color-danger); color: #ffffff; } -body.mstv-admin-page .pdm-btn-danger:hover:not(:disabled) { +body.pdm-admin-page .pdm-btn-danger:hover:not(:disabled) { background: #dc2626; border-color: #dc2626; } -body.mstv-admin-page .pdm-btn-icon { +body.pdm-admin-page .pdm-btn-icon { width: 36px; height: 36px; min-height: 36px; padding: 0; } -body.mstv-admin-page .pdm-btn-sm { +body.pdm-admin-page .pdm-btn-sm { min-height: 30px; padding: 5px 10px; font-size: 12px; } -body.mstv-admin-page .pdm-btn:disabled { +body.pdm-admin-page .pdm-btn:disabled { opacity: 0.5; cursor: not-allowed; } /* ---- Form controls ------------------------------------------ */ -body.mstv-admin-page .pdm-input, -body.mstv-admin-page .pdm-select, -body.mstv-admin-page .pdm-textarea { +body.pdm-admin-page .pdm-input, +body.pdm-admin-page .pdm-select, +body.pdm-admin-page .pdm-textarea { min-height: 36px; padding: 8px 12px; border: 1px solid var(--pdm-color-border); @@ -3044,63 +3042,63 @@ body.mstv-admin-page .pdm-textarea { box-shadow: none; } -body.mstv-admin-page .pdm-input:hover, -body.mstv-admin-page .pdm-select:hover, -body.mstv-admin-page .pdm-textarea:hover { +body.pdm-admin-page .pdm-input:hover, +body.pdm-admin-page .pdm-select:hover, +body.pdm-admin-page .pdm-textarea:hover { border-color: var(--pdm-color-border-strong); } -body.mstv-admin-page .pdm-input:focus, -body.mstv-admin-page .pdm-select:focus, -body.mstv-admin-page .pdm-textarea:focus { +body.pdm-admin-page .pdm-input:focus, +body.pdm-admin-page .pdm-select:focus, +body.pdm-admin-page .pdm-textarea:focus { outline: none; border-color: var(--pdm-color-primary); box-shadow: 0 0 0 3px var(--pdm-color-primary-light); } -body.mstv-admin-page .pdm-select { +body.pdm-admin-page .pdm-select { padding-right: 30px; } -body.mstv-admin-page .pdm-textarea { +body.pdm-admin-page .pdm-textarea { min-height: 90px; } -body.mstv-admin-page .pdm-field { +body.pdm-admin-page .pdm-field { margin-bottom: 22px; } -body.mstv-admin-page .pdm-field-label { +body.pdm-admin-page .pdm-field-label { margin-bottom: 6px; font-size: 13px; font-weight: 600; } -body.mstv-admin-page .pdm-field-desc { +body.pdm-admin-page .pdm-field-desc { margin: 6px 0 10px; font-size: 12.5px; line-height: 1.55; color: var(--pdm-color-text-secondary); } -body.mstv-admin-page .pdm-checkbox-label { +body.pdm-admin-page .pdm-checkbox-label { gap: 10px; font-size: 13px; font-weight: 500; } -body.mstv-admin-page .pdm-checkbox-label input[type="checkbox"] { +body.pdm-admin-page .pdm-checkbox-label input[type="checkbox"] { width: 17px; height: 17px; margin: 0; accent-color: var(--pdm-color-primary); } -body.mstv-admin-page .pdm-checkbox-label--danger input[type="checkbox"] { +body.pdm-admin-page .pdm-checkbox-label--danger input[type="checkbox"] { accent-color: var(--pdm-color-danger); } -body.mstv-admin-page .pdm-section-title { +body.pdm-admin-page .pdm-section-title { margin: 0 0 14px; font-size: 15px; font-weight: 600; @@ -3110,27 +3108,27 @@ body.mstv-admin-page .pdm-section-title { /* ---- File Manager shell ------------------------------------- */ -body.mstv-admin-page .pdm-sidebar-header { +body.pdm-admin-page .pdm-sidebar-header { padding: 17px 16px 13px; } -body.mstv-admin-page .pdm-sidebar-logo { +body.pdm-admin-page .pdm-sidebar-logo { height: 34px; } -body.mstv-admin-page .pdm-sidebar-search { +body.pdm-admin-page .pdm-sidebar-search { padding: 12px 14px; } -body.mstv-admin-page .pdm-sidebar-search .pdm-input { +body.pdm-admin-page .pdm-sidebar-search .pdm-input { height: 36px; } -body.mstv-admin-page .pdm-folder-tree { +body.pdm-admin-page .pdm-folder-tree { padding: 6px 10px 12px; } -body.mstv-admin-page .pdm-folder-item { +body.pdm-admin-page .pdm-folder-item { min-height: 34px; padding: 7px 10px; border-radius: var(--pdm-radius); @@ -3139,69 +3137,69 @@ body.mstv-admin-page .pdm-folder-item { color: var(--pdm-color-text-secondary); } -body.mstv-admin-page .pdm-folder-item:hover { +body.pdm-admin-page .pdm-folder-item:hover { background: #f1f5f9; color: var(--pdm-color-text); } -body.mstv-admin-page .pdm-folder-item.active { +body.pdm-admin-page .pdm-folder-item.active { background: var(--pdm-color-primary-soft); color: var(--pdm-color-primary); font-weight: 500; } -body.mstv-admin-page .pdm-folder-item svg { +body.pdm-admin-page .pdm-folder-item svg { flex-shrink: 0; } -body.mstv-admin-page .pdm-storage-indicator { +body.pdm-admin-page .pdm-storage-indicator { padding: 16px; background: linear-gradient(180deg, #ffffff 0%, #f8fafc 100%); } -body.mstv-admin-page .pdm-storage-title { +body.pdm-admin-page .pdm-storage-title { margin-bottom: 10px; font-size: 10.5px; letter-spacing: 0.08em; color: var(--pdm-color-text-muted); } -body.mstv-admin-page .pdm-storage-stat-value { +body.pdm-admin-page .pdm-storage-stat-value { font-size: 15px; } -body.mstv-admin-page .pdm-storage-stat-label { +body.pdm-admin-page .pdm-storage-stat-label { font-size: 11px; color: var(--pdm-color-text-muted); } -body.mstv-admin-page .pdm-toolbar { +body.pdm-admin-page .pdm-toolbar { padding: 10px 20px; gap: 12px; } -body.mstv-admin-page .pdm-breadcrumb { +body.pdm-admin-page .pdm-breadcrumb { font-size: 13px; color: var(--pdm-color-text-secondary); } -body.mstv-admin-page .pdm-breadcrumb-item { +body.pdm-admin-page .pdm-breadcrumb-item { padding: 5px 8px; } -body.mstv-admin-page .pdm-toolbar-label { +body.pdm-admin-page .pdm-toolbar-label { font-size: 12px; color: var(--pdm-color-text-secondary); } -body.mstv-admin-page .pdm-view-toggle { +body.pdm-admin-page .pdm-view-toggle { padding: 3px; gap: 2px; background: #eef2f7; border-radius: var(--pdm-radius); } -body.mstv-admin-page .pdm-view-toggle .pdm-btn { +body.pdm-admin-page .pdm-view-toggle .pdm-btn { width: 34px; height: 30px; min-height: 30px; @@ -3210,150 +3208,150 @@ body.mstv-admin-page .pdm-view-toggle .pdm-btn { color: var(--pdm-color-text-secondary); } -body.mstv-admin-page .pdm-view-toggle .pdm-btn:hover:not(.active) { +body.pdm-admin-page .pdm-view-toggle .pdm-btn:hover:not(.active) { background: rgba(255, 255, 255, 0.7); color: var(--pdm-color-text); } -body.mstv-admin-page .pdm-view-toggle .pdm-btn.active { +body.pdm-admin-page .pdm-view-toggle .pdm-btn.active { background: var(--pdm-color-bg-secondary); color: var(--pdm-color-primary); box-shadow: var(--pdm-shadow-sm); } -body.mstv-admin-page .pdm-content { +body.pdm-admin-page .pdm-content { padding: 20px 20px 24px; } -body.mstv-admin-page .pdm-content-grid { +body.pdm-admin-page .pdm-content-grid { gap: 14px; grid-template-columns: repeat(auto-fill, minmax(168px, 1fr)); } -body.mstv-admin-page .pdm-item { +body.pdm-admin-page .pdm-item { padding: 16px 12px 14px; border-radius: 10px; } -body.mstv-admin-page .pdm-item:hover { +body.pdm-admin-page .pdm-item:hover { border-color: var(--pdm-color-border-strong); box-shadow: var(--pdm-shadow); } -body.mstv-admin-page .pdm-item.selected { +body.pdm-admin-page .pdm-item.selected { background: var(--pdm-color-primary-soft); border-color: var(--pdm-color-primary); box-shadow: 0 0 0 1px var(--pdm-color-primary); } -body.mstv-admin-page .pdm-item-icon { +body.pdm-admin-page .pdm-item-icon { margin-bottom: 10px; } -body.mstv-admin-page .pdm-item-name { +body.pdm-admin-page .pdm-item-name { font-size: 13px; font-weight: 500; line-height: 1.4; } -body.mstv-admin-page .pdm-item-meta { +body.pdm-admin-page .pdm-item-meta { margin-top: 3px; font-size: 11.5px; } -body.mstv-admin-page .pdm-list-item { +body.pdm-admin-page .pdm-list-item { padding: 10px 14px; border-radius: var(--pdm-radius); gap: 12px; } -body.mstv-admin-page .pdm-list-item:hover { +body.pdm-admin-page .pdm-list-item:hover { border-color: var(--pdm-color-border-strong); background: var(--pdm-color-bg-secondary); } -body.mstv-admin-page .pdm-list-item.selected { +body.pdm-admin-page .pdm-list-item.selected { background: var(--pdm-color-primary-soft); border-color: var(--pdm-color-primary); } -body.mstv-admin-page .pdm-list-item-name { +body.pdm-admin-page .pdm-list-item-name { font-size: 13px; font-weight: 500; } -body.mstv-admin-page .pdm-list-item-meta { +body.pdm-admin-page .pdm-list-item-meta { font-size: 12px; } -body.mstv-admin-page .pdm-pagination { +body.pdm-admin-page .pdm-pagination { margin-top: 22px; padding-top: 16px; } -body.mstv-admin-page .pdm-pagination-summary, -body.mstv-admin-page .pdm-pagination-status { +body.pdm-admin-page .pdm-pagination-summary, +body.pdm-admin-page .pdm-pagination-status { font-size: 12.5px; } -body.mstv-admin-page .pdm-pagination-btn { +body.pdm-admin-page .pdm-pagination-btn { min-height: 32px; } -body.mstv-admin-page .pdm-loading { +body.pdm-admin-page .pdm-loading { font-size: 13px; color: var(--pdm-color-text-muted); } /* ---- File details panel ------------------------------------- */ -body.mstv-admin-page .pdm-details-header { +body.pdm-admin-page .pdm-details-header { padding: 18px 20px; } -body.mstv-admin-page .pdm-details-name { +body.pdm-admin-page .pdm-details-name { font-size: 15px; line-height: 1.35; } -body.mstv-admin-page .pdm-details-preview { +body.pdm-admin-page .pdm-details-preview { background: var(--pdm-color-bg); border: 1px solid var(--pdm-color-border); border-radius: 10px; } -body.mstv-admin-page .pdm-details-body { +body.pdm-admin-page .pdm-details-body { padding: 18px 20px; } -body.mstv-admin-page .pdm-details-section-title { +body.pdm-admin-page .pdm-details-section-title { margin-bottom: 8px; font-size: 10.5px; letter-spacing: 0.08em; color: var(--pdm-color-text-muted); } -body.mstv-admin-page .pdm-details-row { +body.pdm-admin-page .pdm-details-row { padding: 7px 0; font-size: 13px; } -body.mstv-admin-page .pdm-details-row-label { +body.pdm-admin-page .pdm-details-row-label { color: var(--pdm-color-text-muted); } -body.mstv-admin-page .pdm-details-actions { +body.pdm-admin-page .pdm-details-actions { padding: 16px 20px; gap: 8px; background: #fbfcfe; flex-shrink: 0; } -body.mstv-admin-page .pdm-details-empty { +body.pdm-admin-page .pdm-details-empty { color: var(--pdm-color-text-muted); } -body.mstv-admin-page .pdm-details-empty p { +body.pdm-admin-page .pdm-details-empty p { max-width: 220px; font-size: 13px; line-height: 1.5; @@ -3361,12 +3359,12 @@ body.mstv-admin-page .pdm-details-empty p { /* ---- Empty states, modals, toasts --------------------------- */ -body.mstv-admin-page .pdm-empty-state { +body.pdm-admin-page .pdm-empty-state { padding: 60px 24px; color: var(--pdm-color-text-muted); } -body.mstv-admin-page .pdm-empty-state > svg { +body.pdm-admin-page .pdm-empty-state > svg { width: 56px; height: 56px; margin-bottom: 18px; @@ -3378,106 +3376,106 @@ body.mstv-admin-page .pdm-empty-state > svg { opacity: 1; } -body.mstv-admin-page .pdm-empty-state h3 { +body.pdm-admin-page .pdm-empty-state h3 { margin-bottom: 6px; font-size: 17px; } -body.mstv-admin-page .pdm-empty-state p { +body.pdm-admin-page .pdm-empty-state p { max-width: 460px; font-size: 13.5px; line-height: 1.55; } -body.mstv-admin-page .pdm-empty-state--dropzone { +body.pdm-admin-page .pdm-empty-state--dropzone { margin: 20px; background: #fbfcfe; border-color: var(--pdm-color-border-strong); border-radius: 14px; } -body.mstv-admin-page .pdm-empty-actions { +body.pdm-admin-page .pdm-empty-actions { margin-top: 20px; } -body.mstv-admin-page .pdm-modal-content { +body.pdm-admin-page .pdm-modal-content { border: 1px solid var(--pdm-color-border); border-radius: 14px; } -body.mstv-admin-page .pdm-modal-header { +body.pdm-admin-page .pdm-modal-header { padding: 16px 20px; } -body.mstv-admin-page .pdm-modal-title { +body.pdm-admin-page .pdm-modal-title { font-size: 16px; letter-spacing: -0.01em; } -body.mstv-admin-page .pdm-modal-body { +body.pdm-admin-page .pdm-modal-body { padding: 20px; } -body.mstv-admin-page .pdm-modal-footer { +body.pdm-admin-page .pdm-modal-footer { padding: 14px 20px; background: #fbfcfe; } -body.mstv-admin-page .pdm-upload-overlay { +body.pdm-admin-page .pdm-upload-overlay { background: rgb(15 23 42 / 0.55); } -body.mstv-admin-page .pdm-upload-dropzone { +body.pdm-admin-page .pdm-upload-dropzone { max-width: min(560px, calc(100vw - 32px)); padding: 46px 48px; border-radius: 16px; box-shadow: var(--pdm-shadow-lg); } -body.mstv-admin-page .pdm-upload-text { +body.pdm-admin-page .pdm-upload-text { font-size: 17px; font-weight: 600; } -body.mstv-admin-page .pdm-toast { +body.pdm-admin-page .pdm-toast { padding: 12px 16px; border: 1px solid var(--pdm-color-border); border-left: 3px solid var(--pdm-color-primary); border-radius: 10px; } -body.mstv-admin-page .pdm-toast-message { +body.pdm-admin-page .pdm-toast-message { font-size: 13px; } -body.mstv-admin-page .pdm-toast-icon--success { +body.pdm-admin-page .pdm-toast-icon--success { color: var(--pdm-color-success-text); } -body.mstv-admin-page .pdm-toast-icon--error { +body.pdm-admin-page .pdm-toast-icon--error { color: var(--pdm-color-danger-text); } -body.mstv-admin-page .pdm-toast-icon--warning { +body.pdm-admin-page .pdm-toast-icon--warning { color: var(--pdm-color-warning-text); } -body.mstv-admin-page .context-menu { +body.pdm-admin-page .context-menu { padding: 5px; border-radius: 10px; } -body.mstv-admin-page .context-menu-item { +body.pdm-admin-page .context-menu-item { padding: 8px 10px; border-radius: 6px; } -body.mstv-admin-page .pdm-user-result { +body.pdm-admin-page .pdm-user-result { padding: 9px 10px; border-radius: 6px; } -body.mstv-admin-page .pdm-user-tag { +body.pdm-admin-page .pdm-user-tag { padding: 5px 10px; background: var(--pdm-color-primary-soft); border: 1px solid var(--pdm-color-primary-light); @@ -3486,7 +3484,7 @@ body.mstv-admin-page .pdm-user-tag { /* ---- Notices ------------------------------------------------ */ -body.mstv-admin-page .pdm-notice { +body.pdm-admin-page .pdm-notice { padding: 11px 14px; border: 1px solid transparent; border-left-width: 4px; @@ -3495,14 +3493,14 @@ body.mstv-admin-page .pdm-notice { line-height: 1.5; } -body.mstv-admin-page .pdm-notice-success { +body.pdm-admin-page .pdm-notice-success { background: var(--pdm-color-success-light); border-color: #bbf7d0; border-left-color: var(--pdm-color-success); color: var(--pdm-color-success-text); } -body.mstv-admin-page .pdm-notice-error { +body.pdm-admin-page .pdm-notice-error { background: var(--pdm-color-danger-light); border-color: #fecaca; border-left-color: var(--pdm-color-danger); @@ -3511,11 +3509,11 @@ body.mstv-admin-page .pdm-notice-error { /* ---- Tables and status chips -------------------------------- */ -body.mstv-admin-page .pdm-table { +body.pdm-admin-page .pdm-table { font-size: 13px; } -body.mstv-admin-page .pdm-table th { +body.pdm-admin-page .pdm-table th { padding: 11px 16px; font-size: 11px; font-weight: 600; @@ -3526,31 +3524,31 @@ body.mstv-admin-page .pdm-table th { border-bottom: 1px solid var(--pdm-color-border); } -body.mstv-admin-page .pdm-table td { +body.pdm-admin-page .pdm-table td { padding: 13px 16px; vertical-align: middle; } -body.mstv-admin-page .pdm-table td:first-child { +body.pdm-admin-page .pdm-table td:first-child { white-space: nowrap; } -body.mstv-admin-page .pdm-table tbody tr:hover td { +body.pdm-admin-page .pdm-table tbody tr:hover td { background: #fbfcfe; } -body.mstv-admin-page .pdm-table-responsive { +body.pdm-admin-page .pdm-table-responsive { overflow-x: auto; background: var(--pdm-color-bg-secondary); border: 1px solid var(--pdm-color-border); border-radius: 10px; } -body.mstv-admin-page .pdm-table-responsive .pdm-table { +body.pdm-admin-page .pdm-table-responsive .pdm-table { min-width: 720px; } -body.mstv-admin-page .pdm-log-action { +body.pdm-admin-page .pdm-log-action { padding: 3px 9px; border-radius: 999px; font-size: 10.5px; @@ -3559,29 +3557,29 @@ body.mstv-admin-page .pdm-log-action { text-transform: uppercase; } -body.mstv-admin-page .pdm-log-action--upload, -body.mstv-admin-page .pdm-log-action--create { +body.pdm-admin-page .pdm-log-action--upload, +body.pdm-admin-page .pdm-log-action--create { background: var(--pdm-color-success-light); color: var(--pdm-color-success-text); } -body.mstv-admin-page .pdm-log-action--download { +body.pdm-admin-page .pdm-log-action--download { background: var(--pdm-color-primary-light); - color: var(--pdm-color-primary); + color: var(--pdm-color-primary-text); } -body.mstv-admin-page .pdm-log-action--delete { +body.pdm-admin-page .pdm-log-action--delete { background: var(--pdm-color-danger-light); color: var(--pdm-color-danger-text); } -body.mstv-admin-page .pdm-log-action--rename, -body.mstv-admin-page .pdm-log-action--move { +body.pdm-admin-page .pdm-log-action--rename, +body.pdm-admin-page .pdm-log-action--move { background: var(--pdm-color-warning-light); color: var(--pdm-color-warning-text); } -body.mstv-admin-page .pdm-log-context { +body.pdm-admin-page .pdm-log-context { max-width: 260px; padding: 3px 8px; background: var(--pdm-color-bg); @@ -3589,37 +3587,37 @@ body.mstv-admin-page .pdm-log-context { border-radius: 6px; } -body.mstv-admin-page .pdm-logs-toolbar { +body.pdm-admin-page .pdm-logs-toolbar { flex-wrap: wrap; gap: 12px; margin-bottom: 16px; } -body.mstv-admin-page .pdm-inline-form .pdm-select { +body.pdm-admin-page .pdm-inline-form .pdm-select { min-width: 78px; } /* ---- Governance screens ------------------------------------- */ -body.mstv-admin-page .pdm-governance-wrap .pdm-section-title { +body.pdm-admin-page .pdm-governance-wrap .pdm-section-title { margin: 26px 0 12px; font-size: 15px; } -body.mstv-admin-page .pdm-governance-wrap .pdm-section-title:first-child { +body.pdm-admin-page .pdm-governance-wrap .pdm-section-title:first-child { margin-top: 0; } -body.mstv-admin-page .mstv-notif-events, -body.mstv-admin-page .mstv-notif-groups { +body.pdm-admin-page .mstv-notif-events, +body.pdm-admin-page .mstv-notif-groups { gap: 6px; } -body.mstv-admin-page .mstv-notifications-body .pdm-field-label { +body.pdm-admin-page .mstv-notifications-body .pdm-field-label { margin-top: 18px; } -body.mstv-admin-page .mstv-quotas-enable { +body.pdm-admin-page .mstv-quotas-enable { display: inline-flex; margin: 0 0 20px; padding: 10px 14px; @@ -3628,33 +3626,33 @@ body.mstv-admin-page .mstv-quotas-enable { border-radius: 10px; } -body.mstv-admin-page .mstv-groups-list { +body.pdm-admin-page .mstv-groups-list { gap: 16px; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); } -body.mstv-admin-page .mstv-group-card { +body.pdm-admin-page .mstv-group-card { gap: 14px; padding: 18px; border-radius: 10px; transition: border-color 0.15s ease, box-shadow 0.15s ease; } -body.mstv-admin-page .mstv-group-card:hover { +body.pdm-admin-page .mstv-group-card:hover { border-color: var(--pdm-color-border-strong); box-shadow: var(--pdm-shadow); } -body.mstv-admin-page .mstv-group-name { +body.pdm-admin-page .mstv-group-name { font-size: 15px; line-height: 1.35; } -body.mstv-admin-page .mstv-group-meta { +body.pdm-admin-page .mstv-group-meta { font-size: 12px; } -body.mstv-admin-page .mstv-groups-list > .pdm-perm-empty { +body.pdm-admin-page .mstv-groups-list > .pdm-perm-empty { grid-column: 1 / -1; margin: 0; padding: 52px 24px; @@ -3664,7 +3662,7 @@ body.mstv-admin-page .mstv-groups-list > .pdm-perm-empty { font-size: 13px; } -body.mstv-admin-page .mstv-reports-body > .pdm-perm-empty { +body.pdm-admin-page .mstv-reports-body > .pdm-perm-empty { margin: 0; padding: 56px 24px; background: #fbfcfe; @@ -3674,8 +3672,8 @@ body.mstv-admin-page .mstv-reports-body > .pdm-perm-empty { font-size: 13px; } -body.mstv-admin-page .mstv-groups-list > .pdm-perm-empty, -body.mstv-admin-page .mstv-reports-body > .pdm-perm-empty { +body.pdm-admin-page .mstv-groups-list > .pdm-perm-empty, +body.pdm-admin-page .mstv-reports-body > .pdm-perm-empty { display: flex; flex-direction: column; align-items: center; @@ -3689,8 +3687,8 @@ body.mstv-admin-page .mstv-reports-body > .pdm-perm-empty { text-align: center; } -body.mstv-admin-page .mstv-groups-list > .pdm-perm-empty::before, -body.mstv-admin-page .mstv-reports-body > .pdm-perm-empty::before { +body.pdm-admin-page .mstv-groups-list > .pdm-perm-empty::before, +body.pdm-admin-page .mstv-reports-body > .pdm-perm-empty::before { content: ""; width: 40px; height: 40px; @@ -3703,17 +3701,17 @@ body.mstv-admin-page .mstv-reports-body > .pdm-perm-empty::before { mask-size: 40px 40px; } -body.mstv-admin-page .mstv-groups-list > .pdm-perm-empty::before { +body.pdm-admin-page .mstv-groups-list > .pdm-perm-empty::before { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2'/%3E%3Ccircle cx='9' cy='7' r='4'/%3E%3Cpath d='M23 21v-2a4 4 0 0 0-3-3.87'/%3E%3Cpath d='M16 3.13a4 4 0 0 1 0 7.75'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2'/%3E%3Ccircle cx='9' cy='7' r='4'/%3E%3Cpath d='M23 21v-2a4 4 0 0 0-3-3.87'/%3E%3Cpath d='M16 3.13a4 4 0 0 1 0 7.75'/%3E%3C/svg%3E"); } -body.mstv-admin-page .mstv-reports-body > .pdm-perm-empty::before { +body.pdm-admin-page .mstv-reports-body > .pdm-perm-empty::before { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='20' x2='18' y2='10'/%3E%3Cline x1='12' y1='20' x2='12' y2='4'/%3E%3Cline x1='6' y1='20' x2='6' y2='14'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='20' x2='18' y2='10'/%3E%3Cline x1='12' y1='20' x2='12' y2='4'/%3E%3Cline x1='6' y1='20' x2='6' y2='14'/%3E%3C/svg%3E"); } -body.mstv-admin-page .mstv-reports-filters { +body.pdm-admin-page .mstv-reports-filters { align-items: flex-end; gap: 14px; margin: 0 0 24px; @@ -3723,7 +3721,7 @@ body.mstv-admin-page .mstv-reports-filters { border-radius: 10px; } -body.mstv-admin-page .mstv-filter { +body.pdm-admin-page .mstv-filter { gap: 6px; font-size: 11px; font-weight: 600; @@ -3732,23 +3730,23 @@ body.mstv-admin-page .mstv-filter { color: var(--pdm-color-text-muted); } -body.mstv-admin-page .mstv-filter .pdm-select, -body.mstv-admin-page .mstv-filter .pdm-input { +body.pdm-admin-page .mstv-filter .pdm-select, +body.pdm-admin-page .mstv-filter .pdm-input { min-width: 170px; } -body.mstv-admin-page .pdm-perm-table-wrap { +body.pdm-admin-page .pdm-perm-table-wrap { margin: 0 0 16px; background: var(--pdm-color-bg-secondary); border: 1px solid var(--pdm-color-border); border-radius: 10px; } -body.mstv-admin-page .pdm-perm-table { +body.pdm-admin-page .pdm-perm-table { min-width: 520px; } -body.mstv-admin-page .pdm-perm-table th { +body.pdm-admin-page .pdm-perm-table th { padding: 10px 12px; background: var(--pdm-color-bg); border-bottom: 1px solid var(--pdm-color-border); @@ -3759,22 +3757,22 @@ body.mstv-admin-page .pdm-perm-table th { color: var(--pdm-color-text-muted); } -body.mstv-admin-page .pdm-perm-table td { +body.pdm-admin-page .pdm-perm-table td { padding: 10px 12px; vertical-align: middle; } -body.mstv-admin-page .pdm-perm-table tbody tr:hover td { +body.pdm-admin-page .pdm-perm-table tbody tr:hover td { background: #fbfcfe; } -body.mstv-admin-page .pdm-perm-table td.pdm-perm-empty { +body.pdm-admin-page .pdm-perm-table td.pdm-perm-empty { padding: 34px 20px; color: var(--pdm-color-text-muted); font-size: 13px; } -body.mstv-admin-page .pdm-perm-add { +body.pdm-admin-page .pdm-perm-add { gap: 10px; margin-top: 0; padding: 14px; @@ -3783,16 +3781,16 @@ body.mstv-admin-page .pdm-perm-add { border-radius: 10px; } -body.mstv-admin-page .pdm-perm-add-user, -body.mstv-admin-page .pdm-perm-add-group { +body.pdm-admin-page .pdm-perm-add-user, +body.pdm-admin-page .pdm-perm-add-group { flex: 1 1 240px; } -body.mstv-admin-page .mstv-quota-mb { +body.pdm-admin-page .mstv-quota-mb { width: 96px; } -body.mstv-admin-page .mstv-governance-footer { +body.pdm-admin-page .mstv-governance-footer { position: sticky; bottom: 0; z-index: 5; @@ -3805,7 +3803,7 @@ body.mstv-admin-page .mstv-governance-footer { border-top: 1px solid var(--pdm-color-border); } -body.mstv-admin-page .mstv-chip { +body.pdm-admin-page .mstv-chip { background: var(--pdm-color-bg); border: 1px solid var(--pdm-color-border); font-size: 12px; @@ -3813,12 +3811,12 @@ body.mstv-admin-page .mstv-chip { /* ---- Settings and Activity Log ------------------------------ */ -body.mstv-admin-page .pdm-settings-section { +body.pdm-admin-page .pdm-settings-section { margin-bottom: 30px; padding-bottom: 30px; } -body.mstv-admin-page .pdm-settings-section--danger { +body.pdm-admin-page .pdm-settings-section--danger { margin: 0; padding: 20px; background: #fef2f2; @@ -3826,15 +3824,15 @@ body.mstv-admin-page .pdm-settings-section--danger { border-radius: 12px; } -body.mstv-admin-page .pdm-settings-section--danger .pdm-section-title { +body.pdm-admin-page .pdm-settings-section--danger .pdm-section-title { color: #991b1b; } -body.mstv-admin-page .pdm-settings-section--danger .pdm-field-desc { +body.pdm-admin-page .pdm-settings-section--danger .pdm-field-desc { color: #7f1d1d; } -body.mstv-admin-page .pdm-settings-actions { +body.pdm-admin-page .pdm-settings-actions { position: sticky; bottom: 0; z-index: 5; @@ -3846,7 +3844,7 @@ body.mstv-admin-page .pdm-settings-actions { border-top: 1px solid var(--pdm-color-border); } -body.mstv-admin-page .pdm-settings-actions input[type="submit"] { +body.pdm-admin-page .pdm-settings-actions input[type="submit"] { min-height: 38px; padding: 8px 16px; background: var(--pdm-color-primary); @@ -3861,12 +3859,12 @@ body.mstv-admin-page .pdm-settings-actions input[type="submit"] { cursor: pointer; } -body.mstv-admin-page .pdm-settings-actions input[type="submit"]:hover { +body.pdm-admin-page .pdm-settings-actions input[type="submit"]:hover { background: var(--pdm-color-primary-hover); border-color: var(--pdm-color-primary-hover); } -body.mstv-admin-page .pdm-settings-info { +body.pdm-admin-page .pdm-settings-info { margin-top: 36px; padding: 20px; background: var(--pdm-color-bg); @@ -3874,13 +3872,13 @@ body.mstv-admin-page .pdm-settings-info { border-radius: 12px; } -body.mstv-admin-page .pdm-settings-info li { +body.pdm-admin-page .pdm-settings-info li { padding: 5px 0; line-height: 1.55; word-break: break-word; } -body.mstv-admin-page .pdm-settings-info code { +body.pdm-admin-page .pdm-settings-info code { padding: 1px 5px; background: var(--pdm-color-bg-secondary); border: 1px solid var(--pdm-color-border); @@ -3889,55 +3887,55 @@ body.mstv-admin-page .pdm-settings-info code { /* ---- Keyboard focus ----------------------------------------- */ -body.mstv-admin-page :is(.pdm-wrapper, .pdm-modal, .pdm-upload-overlay, .pdm-preview-modal, .pdm-toast-container, .pdm-governance-wrap) :is(button, a[href], select, input[type="checkbox"], input[type="radio"], input[type="date"], [tabindex]):focus-visible { +body.pdm-admin-page :is(.pdm-wrapper, .pdm-modal, .pdm-upload-overlay, .pdm-preview-modal, .pdm-toast-container, .pdm-governance-wrap) :is(button, a[href], select, input[type="checkbox"], input[type="radio"], input[type="date"], [tabindex]):focus-visible { outline: 2px solid var(--pdm-color-primary); outline-offset: 2px; } /* Overlays own the whole viewport, including the WordPress admin chrome. */ -body.mstv-admin-page .pdm-modal, -body.mstv-admin-page .pdm-upload-overlay, -body.mstv-admin-page .pdm-preview-modal { +body.pdm-admin-page .pdm-modal, +body.pdm-admin-page .pdm-upload-overlay, +body.pdm-admin-page .pdm-preview-modal { z-index: 100000; } -body.mstv-admin-page .context-menu { +body.pdm-admin-page .context-menu { z-index: 100001; } -body.mstv-admin-page .pdm-toast-container { +body.pdm-admin-page .pdm-toast-container { z-index: 100002; } /* ---- Responsive: compact toolbar on narrower desktops ------- */ @media (min-width: 769px) and (max-width: 1460px) { - body.mstv-admin-page .pdm-toolbar { + body.pdm-admin-page .pdm-toolbar { padding: 10px 16px; gap: 8px; } - body.mstv-admin-page .pdm-toolbar-right { + body.pdm-admin-page .pdm-toolbar-right { gap: 6px; } /* Sort and page size stay reachable through the filter popover; the breadcrumb remains visible wherever it fits. */ - body.mstv-admin-page .pdm-sort-dropdown { + body.pdm-admin-page .pdm-sort-dropdown { display: none; } - body.mstv-admin-page .pdm-toolbar-filters { + body.pdm-admin-page .pdm-toolbar-filters { display: flex; } - body.mstv-admin-page .pdm-filters-toggle { + body.pdm-admin-page .pdm-filters-toggle { display: inline-flex !important; } /* Keep the per-page control visually compact without dropping its label for assistive technologies. */ - body.mstv-admin-page .pdm-page-size-control .pdm-toolbar-label { + body.pdm-admin-page .pdm-page-size-control .pdm-toolbar-label { position: absolute; width: 1px; height: 1px; @@ -3952,7 +3950,7 @@ body.mstv-admin-page .pdm-toast-container { /* From this width the toolbar has room for the visible per-page label again. */ @media (min-width: 1024px) and (max-width: 1460px) { - body.mstv-admin-page .pdm-page-size-control .pdm-toolbar-label { + body.pdm-admin-page .pdm-page-size-control .pdm-toolbar-label { position: static; width: auto; height: auto; @@ -3968,7 +3966,7 @@ body.mstv-admin-page .pdm-toast-container { /* ---- Responsive: mobile toolbar ----------------------------- */ @media (max-width: 768px) { - body.mstv-admin-page .pdm-toolbar { + body.pdm-admin-page .pdm-toolbar { position: relative; flex-wrap: wrap; overflow: visible; @@ -3976,11 +3974,11 @@ body.mstv-admin-page .pdm-toast-container { gap: 8px; } - body.mstv-admin-page .pdm-toolbar-left { + body.pdm-admin-page .pdm-toolbar-left { min-width: 0; } - body.mstv-admin-page .pdm-toolbar-right { + body.pdm-admin-page .pdm-toolbar-right { flex: 1 1 auto; flex-wrap: wrap; justify-content: flex-end; @@ -3988,22 +3986,22 @@ body.mstv-admin-page .pdm-toast-container { min-width: 0; } - body.mstv-admin-page .pdm-page-size-control, - body.mstv-admin-page .pdm-sort-dropdown { + body.pdm-admin-page .pdm-page-size-control, + body.pdm-admin-page .pdm-sort-dropdown { display: none; } /* Keep the filter dropdown available as a real popover instead of an always-open row that used to clip the Export and Upload actions. */ - body.mstv-admin-page .pdm-filters-toggle { + body.pdm-admin-page .pdm-filters-toggle { display: inline-flex !important; } - body.mstv-admin-page .pdm-toolbar-filters { + body.pdm-admin-page .pdm-toolbar-filters { position: static; } - body.mstv-admin-page .pdm-toolbar-filters-dropdown { + body.pdm-admin-page .pdm-toolbar-filters-dropdown { position: absolute; top: calc(100% + 8px); right: 12px; @@ -4022,11 +4020,11 @@ body.mstv-admin-page .pdm-toast-container { z-index: 70; } - body.mstv-admin-page .pdm-toolbar-filters-dropdown.active { + body.pdm-admin-page .pdm-toolbar-filters-dropdown.active { display: flex !important; } - body.mstv-admin-page .pdm-toolbar-filters-row { + body.pdm-admin-page .pdm-toolbar-filters-row { display: flex; flex-direction: column; align-items: stretch; @@ -4034,50 +4032,51 @@ body.mstv-admin-page .pdm-toast-container { margin-bottom: 0; } - body.mstv-admin-page .pdm-toolbar-filters-label { + body.pdm-admin-page .pdm-toolbar-filters-label { display: block; } - body.mstv-admin-page .pdm-toolbar-filters-select, - body.mstv-admin-page .pdm-filters-sort { + body.pdm-admin-page .pdm-toolbar-filters-select, + body.pdm-admin-page .pdm-filters-sort { width: 100%; min-height: 38px; } - body.mstv-admin-page .pdm-view-toggle .pdm-btn { + body.pdm-admin-page .pdm-view-toggle .pdm-btn { width: 38px; height: 34px; min-height: 34px; } - body.mstv-admin-page .pdm-content { + body.pdm-admin-page .pdm-content { padding: 14px 12px 20px; } } @media (max-width: 600px) { - body.mstv-admin-page :is(.mstv-governance-title, .pdm-settings-title, .pdm-logs-title) { + body.pdm-admin-page :is(.mstv-governance-title, .pdm-settings-title, .pdm-logs-title) { font-size: 21px; } - body.mstv-admin-page :is(.mstv-governance-header, .pdm-settings-header, .pdm-logs-header) { + body.pdm-admin-page :is(.mstv-governance-header, .pdm-settings-header, .pdm-logs-header) { margin-bottom: 20px; padding-bottom: 16px; } - body.mstv-admin-page .mstv-governance-header .pdm-btn { + body.pdm-admin-page .mstv-governance-header .pdm-btn { width: 100%; } /* Icon-only Export keeps the primary actions on one row; the label stays in the accessibility tree instead of being removed with display: none. */ - body.mstv-admin-page #pdm-export-btn { + body.pdm-admin-page #pdm-export-btn { width: 36px; min-width: 36px; padding: 0; } - body.mstv-admin-page #pdm-export-btn span { + body.pdm-admin-page #pdm-export-btn span { + display: inline; position: absolute; width: 1px; height: 1px; @@ -4089,120 +4088,120 @@ body.mstv-admin-page .pdm-toast-container { border: 0; } - body.mstv-admin-page .pdm-toolbar { + body.pdm-admin-page .pdm-toolbar { gap: 6px; } - body.mstv-admin-page .mstv-groups-list { + body.pdm-admin-page .mstv-groups-list { grid-template-columns: 1fr; } - body.mstv-admin-page .mstv-reports-filters { + body.pdm-admin-page .mstv-reports-filters { flex-direction: column; align-items: stretch; } - body.mstv-admin-page .mstv-filter .pdm-select, - body.mstv-admin-page .mstv-filter .pdm-input { + body.pdm-admin-page .mstv-filter .pdm-select, + body.pdm-admin-page .mstv-filter .pdm-input { min-width: 0; width: 100%; } - body.mstv-admin-page .mstv-reports-filters .pdm-btn { + body.pdm-admin-page .mstv-reports-filters .pdm-btn { width: 100%; } - body.mstv-admin-page .pdm-perm-add { + body.pdm-admin-page .pdm-perm-add { flex-direction: column; } /* An empty quota table has no columns worth scrolling for: let the message wrap inside the card instead of being clipped by the horizontal scroller. */ - body.mstv-admin-page .pdm-perm-table-wrap:has(.pdm-perm-empty) { + body.pdm-admin-page .pdm-perm-table-wrap:has(.pdm-perm-empty) { overflow-x: hidden; } - body.mstv-admin-page .pdm-perm-table-wrap:has(.pdm-perm-empty) .pdm-perm-table { + body.pdm-admin-page .pdm-perm-table-wrap:has(.pdm-perm-empty) .pdm-perm-table { min-width: 0; } - body.mstv-admin-page .pdm-perm-add-user, - body.mstv-admin-page .pdm-perm-add-group { + body.pdm-admin-page .pdm-perm-add-user, + body.pdm-admin-page .pdm-perm-add-group { flex: 1 1 100%; width: 100%; } - body.mstv-admin-page .mstv-governance-footer .pdm-btn { + body.pdm-admin-page .mstv-governance-footer .pdm-btn { width: 100%; } - body.mstv-admin-page .pdm-settings-actions { + body.pdm-admin-page .pdm-settings-actions { justify-content: stretch; } - body.mstv-admin-page .pdm-settings-actions input[type="submit"] { + body.pdm-admin-page .pdm-settings-actions input[type="submit"] { width: 100%; } - body.mstv-admin-page .pdm-logs-toolbar { + body.pdm-admin-page .pdm-logs-toolbar { flex-direction: column; align-items: stretch; gap: 12px; } - body.mstv-admin-page .pdm-logs-toolbar .pdm-inline-form { + body.pdm-admin-page .pdm-logs-toolbar .pdm-inline-form { flex-direction: row; align-items: center; flex-wrap: wrap; gap: 8px; } - body.mstv-admin-page .pdm-inline-form .pdm-select { + body.pdm-admin-page .pdm-inline-form .pdm-select { flex: 1 1 90px; } - body.mstv-admin-page .pdm-pagination { + body.pdm-admin-page .pdm-pagination { align-items: stretch; gap: 12px; } - body.mstv-admin-page .pdm-pagination-controls { + body.pdm-admin-page .pdm-pagination-controls { justify-content: space-between; } - body.mstv-admin-page .pdm-upload-dropzone { + body.pdm-admin-page .pdm-upload-dropzone { padding: 36px 22px; } - body.mstv-admin-page .pdm-upload-text { + body.pdm-admin-page .pdm-upload-text { font-size: 16px; } - body.mstv-admin-page .pdm-empty-state { + body.pdm-admin-page .pdm-empty-state { padding: 44px 18px; } } @media (max-width: 480px) { - body.mstv-admin-page .pdm-content-grid { + body.pdm-admin-page .pdm-content-grid { grid-template-columns: repeat(auto-fill, minmax(148px, 1fr)); gap: 10px; } - body.mstv-admin-page .pdm-content { + body.pdm-admin-page .pdm-content { padding: 12px 10px 18px; } } @media (max-width: 782px) { - body.mstv-admin-page .pdm-settings-wrapper, - body.mstv-admin-page .pdm-logs-wrapper, - body.mstv-admin-page .pdm-governance-wrap { + body.pdm-admin-page .pdm-settings-wrapper, + body.pdm-admin-page .pdm-logs-wrapper, + body.pdm-admin-page .pdm-governance-wrap { min-height: calc(100dvh - var(--pdm-admin-bar-offset)); } - body.mstv-admin-page .pdm-settings-wrapper > *, - body.mstv-admin-page .pdm-governance-wrap > * { + body.pdm-admin-page .pdm-settings-wrapper > *, + body.pdm-admin-page .pdm-governance-wrap > * { max-width: 100%; } } @@ -4210,12 +4209,12 @@ body.mstv-admin-page .pdm-toast-container { /* ---- Touch targets ------------------------------------------ */ @media (hover: none) and (pointer: coarse) { - body.mstv-admin-page .pdm-btn { + body.pdm-admin-page .pdm-btn { min-height: 44px; padding: 10px 16px; } - body.mstv-admin-page .pdm-btn-icon { + body.pdm-admin-page .pdm-btn-icon { width: 44px; height: 44px; min-width: 44px; @@ -4223,24 +4222,23 @@ body.mstv-admin-page .pdm-toast-container { padding: 0; } - body.mstv-admin-page .pdm-folder-item { + body.pdm-admin-page .pdm-folder-item { min-height: 44px; padding: 10px 12px; } - body.mstv-admin-page .pdm-input, - body.mstv-admin-page .pdm-select { + body.pdm-admin-page .pdm-input, + body.pdm-admin-page .pdm-select { min-height: 44px; } - body.mstv-admin-page .pdm-toolbar-filters-select { + body.pdm-admin-page .pdm-toolbar-filters-select { min-height: 44px; } - body.mstv-admin-page .pdm-view-toggle .pdm-btn { + body.pdm-admin-page .pdm-view-toggle .pdm-btn { width: 44px; height: 40px; min-height: 40px; } } - diff --git a/includes/class-mstv-assets.php b/includes/class-mstv-assets.php index 783d526..a114126 100644 --- a/includes/class-mstv-assets.php +++ b/includes/class-mstv-assets.php @@ -29,7 +29,7 @@ public function add_admin_body_class($classes): string return $classes; } - return $classes === '' ? 'mstv-admin-page' : $classes . ' mstv-admin-page'; + return $classes === '' ? 'pdm-admin-page' : $classes . ' pdm-admin-page'; } private function is_teamvault_screen(): bool diff --git a/tests/PDMAdminAppTest.php b/tests/PDMAdminAppTest.php index 8aa7e96..3e930bb 100644 --- a/tests/PDMAdminAppTest.php +++ b/tests/PDMAdminAppTest.php @@ -173,17 +173,17 @@ public function testTeamVaultCssRemovesAdminChromeFromEveryPluginScreen(): void $source = (string) file_get_contents(dirname(__DIR__) . '/assets/css/admin.css'); self::assertStringContainsString( - 'body.mstv-admin-page #wpfooter', + 'body.pdm-admin-page #wpfooter', $source, 'Every TeamVault screen must hide the WordPress admin footer band.' ); self::assertStringContainsString( - 'body.mstv-admin-page #wpbody-content', + 'body.pdm-admin-page #wpbody-content', $source, 'Every TeamVault screen must remove the admin bottom padding under its panels.' ); self::assertStringContainsString( - 'body.mstv-admin-page .pdm-wrapper', + 'body.pdm-admin-page .pdm-wrapper', $source, 'Panel wrappers on TeamVault screens must drop the 20px gap above and below the panel.' ); @@ -204,27 +204,27 @@ public function testDesignSystemUnifiesEveryPluginScreen(): void $css = (string) file_get_contents(dirname(__DIR__) . '/assets/css/admin.css'); self::assertStringContainsString( - 'body.mstv-admin-page .pdm-settings-wrapper,', + 'body.pdm-admin-page .pdm-settings-wrapper,', $css, 'Settings, Activity Log and governance screens must share the same page canvas.' ); self::assertStringContainsString( - 'body.mstv-admin-page .pdm-logs-wrapper,', + 'body.pdm-admin-page .pdm-logs-wrapper,', $css, 'The Activity Log must use the shared page canvas.' ); self::assertStringContainsString( - 'body.mstv-admin-page .pdm-governance-wrap > *', + 'body.pdm-admin-page .pdm-governance-wrap > *', $css, 'Governance screens must share the constrained content width.' ); self::assertStringContainsString( - 'body.mstv-admin-page .mstv-governance-footer', + 'body.pdm-admin-page .mstv-governance-footer', $css, 'Governance save bars must share the sticky action pattern.' ); self::assertStringContainsString( - 'body.mstv-admin-page .pdm-settings-actions', + 'body.pdm-admin-page .pdm-settings-actions', $css, 'Settings must keep its save action visible while scrolling.' ); diff --git a/tests/PDMAssetsTest.php b/tests/PDMAssetsTest.php index 79dbc35..e945c5f 100644 --- a/tests/PDMAssetsTest.php +++ b/tests/PDMAssetsTest.php @@ -25,10 +25,10 @@ public function test_admin_body_class_marks_only_teamvault_screens(): void $assets = new MSTV_Assets(new MSTV_Settings()); $GLOBALS['pdm_test_current_screen_id'] = 'teamvault_page_mikesoft-teamvault-settings'; - self::assertSame('wp-admin mstv-admin-page', $assets->add_admin_body_class('wp-admin')); + self::assertSame('wp-admin pdm-admin-page', $assets->add_admin_body_class('wp-admin')); $GLOBALS['pdm_test_current_screen_id'] = 'toplevel_page_mikesoft-teamvault'; - self::assertSame('wp-admin mstv-admin-page', $assets->add_admin_body_class('wp-admin')); + self::assertSame('wp-admin pdm-admin-page', $assets->add_admin_body_class('wp-admin')); $GLOBALS['pdm_test_current_screen_id'] = 'edit-post'; self::assertSame('wp-admin', $assets->add_admin_body_class('wp-admin')); From 7d8ad8fb04e21d6ef702d581df4d55f7ec87c4fa Mon Sep 17 00:00:00 2001 From: Michael Gasperini <163041857+TheStreamCode@users.noreply.github.com> Date: Thu, 22 Oct 2026 13:54:58 +0200 Subject: [PATCH 4/4] fix(admin): keep full-height workspace with notices and restore desktop sort --- assets/css/admin.css | 62 ++++++++++++++++++++++++++++++++------- changelog.txt | 2 +- readme.txt | 2 +- tests/PDMAdminAppTest.php | 14 +++++++-- 4 files changed, 66 insertions(+), 14 deletions(-) diff --git a/assets/css/admin.css b/assets/css/admin.css index e7d5d45..026eeb0 100644 --- a/assets/css/admin.css +++ b/assets/css/admin.css @@ -97,12 +97,33 @@ body.pdm-admin-page .pdm-wrapper { margin: 0; } -body.toplevel_page_mikesoft-teamvault .pdm-wrapper { +body.toplevel_page_mikesoft-teamvault #wpbody-content { + display: flex; + flex-direction: column; + float: none; height: calc(100vh - var(--pdm-admin-bar-offset)); + padding-bottom: 0; + box-sizing: border-box; +} + +/* Admin notices (including the persistent storage warning) keep their natural + height above the app; the workspace then fills exactly the remaining viewport. */ +body.toplevel_page_mikesoft-teamvault #wpbody-content > .notice, +body.toplevel_page_mikesoft-teamvault #wpbody-content > .updated, +body.toplevel_page_mikesoft-teamvault #wpbody-content > .error { + flex-shrink: 0; +} + +body.toplevel_page_mikesoft-teamvault .pdm-wrapper { + display: flex; + flex: 1 1 auto; + flex-direction: column; + min-height: 0; } body.toplevel_page_mikesoft-teamvault .pdm-app { - height: 100%; + flex: 1 1 auto; + height: auto; min-height: 0; } @@ -3507,6 +3528,31 @@ body.pdm-admin-page .pdm-notice-error { color: var(--pdm-color-danger-text); } +/* Plugin-owned persistent storage notice: full-bleed alert above the page canvas. */ +body.pdm-admin-page .mstv-storage-security-notice { + box-sizing: border-box; + margin: 0 0 0 calc(-1 * var(--pdm-admin-content-pad)); + padding: 12px var(--pdm-page-pad-x); + background: var(--pdm-color-warning-light); + border: 0; + border-left: 4px solid var(--pdm-color-warning); + border-radius: 0; + box-shadow: none; + color: var(--pdm-color-warning-text); + font-size: 13px; + line-height: 1.5; +} + +body.pdm-admin-page .mstv-storage-security-notice p { + margin: 0; +} + +body.pdm-admin-page .mstv-storage-security-notice.notice-error { + background: var(--pdm-color-danger-light); + border-left-color: var(--pdm-color-danger); + color: var(--pdm-color-danger-text); +} + /* ---- Tables and status chips -------------------------------- */ body.pdm-admin-page .pdm-table { @@ -3919,18 +3965,14 @@ body.pdm-admin-page .pdm-toast-container { gap: 6px; } - /* Sort and page size stay reachable through the filter popover; the - breadcrumb remains visible wherever it fits. */ - body.pdm-admin-page .pdm-sort-dropdown { + /* Compact desktop toolbar: keep the visible sort control, hide the duplicate + filter popover, and let the sidebar provide folder context. */ + body.pdm-admin-page .pdm-breadcrumb { display: none; } body.pdm-admin-page .pdm-toolbar-filters { - display: flex; - } - - body.pdm-admin-page .pdm-filters-toggle { - display: inline-flex !important; + display: none; } /* Keep the per-page control visually compact without dropping its label for diff --git a/changelog.txt b/changelog.txt index 0fb2c01..4030813 100644 --- a/changelog.txt +++ b/changelog.txt @@ -6,7 +6,7 @@ Entries are ordered newest first. Release dates are included where recorded. - Security: folder and file uniqueness is now enforced in the database through an option-guarded migration that merges existing duplicates before adding the unique keys. The lowest folder id survives; child folders, files, and per-folder rules are re-pointed to it, and duplicate subtrees are rewritten onto the surviving path. Duplicate inserts map to 409 conflicts and duplicate paths are skipped during reindexing. The auto-reindex claim is atomic and released when the scan fails. - Security: uploads now fail closed when the private storage directory is not writable or when `.htaccess`, `web.config`, or `index.php` cannot be created, and the error names the failing files. The storage warning is persistent and non-dismissible for blocking states and for Nginx, which ignores `.htaccess`; the README documents an out-of-webroot storage path as the recommended deployment. - Admin UI: every TeamVault screen now shares one design system: unified palette and typography tokens, full-bleed white canvas, page headers, buttons, form controls, tables, badges, empty states, spacing, and radii. -- Admin UI: the File Manager removes the WordPress footer gap and the gray bands above and below the app, fills the viewport below the admin bar, pins the storage panel to the bottom edge, and no longer clips toolbar controls at common desktop widths. The filter control opens a labeled popover, icon-only Export keeps an accessible name, and the filter toggle announces its expanded state. +- Admin UI: the File Manager removes the WordPress footer gap and the gray bands above and below the app, fills the viewport below the admin bar, pins the storage panel to the bottom edge, and no longer clips toolbar controls at common desktop widths. Compact desktop toolbars keep the sort and page-size controls visible, small screens use the labeled filter popover, icon-only Export keeps an accessible name, and the filter toggle announces its expanded state. The persistent storage notice adopts the shared alert styling, and the app fills the remaining viewport when notices are present. - Accessibility: the File Manager exposes a screen-reader page heading, custom controls have visible keyboard focus, status badges and muted text meet AA contrast, and touch targets reach 44px on coarse pointers. - Responsive: settings, governance tables, forms, modals, the upload overlay, and report filters adapt to 360-390px screens without horizontal page overflow; the mobile toolbar keeps Export and Upload reachable, and the detail drawer keeps every file action available. - Fixed: secondary toolbar actions no longer hide Rename and Move in the mobile file details; the empty quota table is no longer clipped by its horizontal scroller; folder empty states size correctly at 360px; the group editor label reads "Members" and is translated in Italian, French, Spanish, and German. diff --git a/readme.txt b/readme.txt index 3fc8541..736f5d5 100644 --- a/readme.txt +++ b/readme.txt @@ -332,7 +332,7 @@ For the full release history, see `changelog.txt` in the plugin package. = 3.5.0 = -The admin interface has been refreshed for consistency, mobile use, and accessibility. The first update merges any duplicate folder and file records, then rejects new duplicates, and uploads now fail closed if the private storage protection cannot be enforced. No configuration changes are required. +Refreshes the admin UI for consistency, mobile use, and accessibility. The first update merges duplicate folder/file records and rejects new ones; uploads fail closed when storage protection cannot be enforced. Nginx sites must confirm a deny rule or use an out-of-webroot storage path. = 3.4.0 = diff --git a/tests/PDMAdminAppTest.php b/tests/PDMAdminAppTest.php index 3e930bb..aa711f4 100644 --- a/tests/PDMAdminAppTest.php +++ b/tests/PDMAdminAppTest.php @@ -188,9 +188,14 @@ public function testTeamVaultCssRemovesAdminChromeFromEveryPluginScreen(): void 'Panel wrappers on TeamVault screens must drop the 20px gap above and below the panel.' ); self::assertStringContainsString( - 'height: calc(100vh - var(--pdm-admin-bar-offset));', + 'body.toplevel_page_mikesoft-teamvault #wpbody-content {', $source, - 'The File Manager wrapper must fill exactly the viewport below the admin bar.' + 'The File Manager viewport container must own the remaining height below notices.' + ); + self::assertStringContainsString( + 'flex: 1 1 auto;', + $source, + 'The File Manager app must fill the viewport container, including when notices appear above it.' ); self::assertStringContainsString( 'body.toplevel_page_mikesoft-teamvault .pdm-sidebar', @@ -228,6 +233,11 @@ public function testDesignSystemUnifiesEveryPluginScreen(): void $css, 'Settings must keep its save action visible while scrolling.' ); + self::assertStringContainsString( + 'body.pdm-admin-page .mstv-storage-security-notice', + $css, + 'The persistent storage notice must follow the shared design system.' + ); self::assertStringContainsString( "setAttribute('aria-expanded'", $this->adminAppSource(),