| @@ -23,15 +23,18 @@ | ||
| 23 | 23 | public function __construct() |
| 24 | 24 | { |
| 25 | 25 | add_action('admin_enqueue_scripts', array($this, 'darkmode_scripts'), 100); |
| 26 | 26 | add_action( 'enqueue_block_editor_assets', array($this, "gutenberg_block_editor_darkmode_assets")); |
| 27 | - // WP 6.3+/7.0: the block editor canvas runs in an iframe. The AdminifyDarkMode | |
| 28 | - // script has no built-in iframe support, so inject the same script INTO the | |
| 29 | - // iframe and call .enable() from inside — that way Darkreader runs over the | |
| 30 | - // iframe DOM the same dynamic way it runs on the parent admin. | |
| 31 | - // Use admin_footer (not enqueue_block_editor_assets — wp_add_inline_script | |
| 32 | - // silently dropped the bridge) and direct-print via wp_print_inline_script_tag. | |
| 33 | - add_action('admin_footer', array($this, 'inject_darkmode_into_editor_iframe'), 999); | |
| 27 | + // Block editor canvas (iframe[name="editor-canvas"]) is a frontend style | |
| 28 | + // PREVIEW — Adminify is an admin-focus plugin, so dark mode must NOT darken | |
| 29 | + // the previewed content. Only the controller chrome (sidebar/panels) goes | |
| 30 | + // dark, handled by the parent-admin dark mode + gutenberg_block_editor_darkmode_assets. | |
| 31 | + // (Intentionally no iframe injection into the block canvas.) | |
| 32 | + // Classic editor (TinyMCE) renders the Visual tab inside its own iframe | |
| 33 | + // (#content_ifr). Same iframe-isolation problem as the block canvas: the | |
| 34 | + // parent Darkreader run can't reach the iframe DOM, so the editor body | |
| 35 | + // stays white in dark mode. Inject the same script into TinyMCE iframes. | |
| 36 | + add_action('admin_footer', array($this, 'inject_darkmode_into_classic_editor_iframe'), 999); | |
| 34 | 37 | // customize.php controls: Adminify scripts are skipped there by design |
| 35 | 38 | // (Assets::should_skip_adminify_scripts), so enqueue dark-mode only on this |
| 36 | 39 | // dedicated hook to keep the customize panel dark without the rest of Adminify. |
| 37 | 40 | add_action('customize_controls_enqueue_scripts', array($this, 'customize_controls_darkmode_enqueue')); |
| @@ -417,14 +420,74 @@ | ||
| 417 | 420 | |
| 418 | 421 | // $parent_selector = 'body.wp-adminify.adminify-dark-mode'; |
| 419 | 422 | $parent_selector = 'body.wp-adminify'; |
| 420 | 423 | |
| 421 | - $dark_mode_style = "$parent_selector .components-modal__content .components-text, | |
| 422 | - $parent_selector .components-popover__content .components-text { color: black!important; } | |
| 424 | + $dark_mode_style = "$parent_selector .editor-document-bar__title .editor-document-bar__post-title {color: black;} | |
| 425 | + $parent_selector .interface-complementary-area {border-left: 1px solid #dedee7!important;} | |
| 426 | + $parent_selector .block-editor-inserter__main-area .block-editor-tabbed-sidebar .block-editor-tabbed-sidebar__tablist button, .block-editor-tabbed-sidebar .block-editor-tabbed-sidebar__tab {color: black;} | |
| 427 | + $parent_selector .block-editor-inserter__main-area .block-editor-inserter__category-tablist button {color: black;} | |
| 428 | + $parent_selector .interface-interface-skeleton__body .interface-interface-skeleton__secondary-sidebar {border-right: 1px solid #e0e0e0;} | |
| 429 | + $parent_selector .block-editor__container .edit-post-header {border-bottom: 1px solid #e0e0e0} | |
| 430 | + $parent_selector .components-modal__content .components-text, | |
| 431 | + $parent_selector .components-panel .components-text, | |
| 432 | + $parent_selector .components-popover__content .components-text, | |
| 433 | + $parent_selector .preferences__tabs button[aria-selected=false] > span { color: black!important; } | |
| 423 | 434 | $parent_selector .block-editor-block-inspector .components-tools-panel { border-top-color: #e0e0e0; } |
| 424 | 435 | $parent_selector .admin-ui-navigable-region .components-panel__header > div > button { color: black; } |
| 425 | - $parent_selector .editor-sidebar__panel .editor-post-card-panel__header svg, | |
| 436 | + $parent_selector .editor-sidebar__panel .editor-post-card-panel__header svg, | |
| 426 | 437 | $parent_selector .commands-command-menu__container .commands-command-menu__header svg { fill: black; } |
| 438 | + /** Typography & Size */ | |
| 439 | + $parent_selector .components-toggle-group-control { | |
| 440 | + background: #1e1e1e!important; border-color: #4a4a4a!important; | |
| 441 | + } | |
| 442 | + /* Advanced > ADDITIONAL CSS textarea + WIDTH/number/unit inputs render white | |
| 443 | + (the dark engine skips them), clashing with the dark inspector. Force dark. */ | |
| 444 | + $parent_selector .block-editor-block-inspector textarea, | |
| 445 | + $parent_selector .block-editor-block-inspector .components-textarea-control__input, | |
| 446 | + $parent_selector .block-editor-block-inspector input[type=\"number\"], | |
| 447 | + $parent_selector .block-editor-block-inspector input[type=\"text\"], | |
| 448 | + $parent_selector .block-editor-block-inspector .components-input-control__input, | |
| 449 | + $parent_selector .block-editor-block-inspector .components-unit-control input { | |
| 450 | + background: #1e1e1e!important; color: #f0f0f1!important; border-color: #4a4a4a!important; | |
| 451 | + } | |
| 452 | + /* Unit suffix/select (the \"px\" box) is a separate element the engine leaves | |
| 453 | + white — force it dark to match the WIDTH input. Its popover is an Ariakit | |
| 454 | + dialog, so match it on the attributes it carries WHILE OPEN; a bare | |
| 455 | + [data-dialog] also hits every closed one and any other dialog on the page. */ | |
| 456 | + $parent_selector div[data-dialog][data-open=\"true\"][role=\"menu\"], | |
| 457 | + $parent_selector .block-editor-block-inspector .components-unit-control__unit-select, | |
| 458 | + $parent_selector .block-editor-block-inspector .components-unit-control select, | |
| 459 | + $parent_selector .block-editor-block-inspector .components-input-control__suffix, | |
| 460 | + $parent_selector .block-editor-block-inspector .components-input-control__suffix * { | |
| 461 | + background: #1e1e1e!important; color: #f0f0f1!important; border-color: #4a4a4a!important; | |
| 462 | + } | |
| 463 | + /* ToolsPanel \"Settings\" three-dot dropdown menu: item labels (e.g. WIDTH) render | |
| 464 | + dark on the dark popover and disappear — force them light. The newer block | |
| 465 | + editor uses an Ariakit menu with hashed class names (css-*-Item-baseItem), so | |
| 466 | + target the ARIA roles too, not just the legacy .components-menu-item__item. */ | |
| 467 | + $parent_selector .components-dropdown-menu__menu .components-menu-item__item, | |
| 468 | + $parent_selector .components-menu-group .components-menu-item__item, | |
| 469 | + $parent_selector [role=\"menu\"] .components-menu-item__item, | |
| 470 | + $parent_selector [role=\"menu\"] [role=\"menuitem\"], | |
| 471 | + $parent_selector [role=\"menu\"] [role=\"menuitemcheckbox\"], | |
| 472 | + $parent_selector [role=\"menu\"] [role=\"menuitemradio\"], | |
| 473 | + $parent_selector [role=\"menu\"] [role=\"menuitem\"] *, | |
| 474 | + $parent_selector [role=\"menu\"] [role=\"menuitemcheckbox\"] *, | |
| 475 | + $parent_selector [role=\"menu\"] [role=\"menuitemradio\"] * { | |
| 476 | + color: #f0f0f1!important; | |
| 477 | + } | |
| 478 | + /* Block card description (text under the block name, e.g. \"A single column | |
| 479 | + within a columns block\") renders too dark to read — force a light color. */ | |
| 480 | + $parent_selector .block-editor-block-inspector .block-editor-block-card__description, | |
| 481 | + $parent_selector .block-editor-block-card__description { | |
| 482 | + color: #c0c0c5!important; | |
| 483 | + } | |
| 484 | + /* Inspector tab icons (Settings gear / Styles) render dark on the dark panel — | |
| 485 | + force a light fill so they stay visible. */ | |
| 486 | + $parent_selector .block-editor-block-inspector [role=\"tab\"] svg, | |
| 487 | + $parent_selector .block-editor-block-inspector-tabs__tablist svg { | |
| 488 | + fill: #e0e0e0!important; | |
| 489 | + } | |
| 427 | 490 | "; |
| 428 | 491 | wp_add_inline_style('adminify-gutenberg-dark', wp_strip_all_tags($dark_mode_style)); |
| 429 | 492 | } |
| 430 | 493 | |
| @@ -441,42 +504,44 @@ | ||
| 441 | 504 | return !empty($user_mode) ? $user_mode : $global_mode; |
| 442 | 505 | } |
| 443 | 506 | |
| 444 | 507 | /** |
| 445 | - * Inject the AdminifyDarkMode script INTO the WP 6.3+/7.0 block editor iframe | |
| 446 | - * canvas. The script attaches a global `window.AdminifyDarkMode` and uses a | |
| 447 | - * Darkreader-style dynamic theme that rewrites colors based on the running | |
| 448 | - * document — so it must be loaded inside the iframe's window to darken the | |
| 449 | - * canvas DOM, not just the parent admin chrome. | |
| 508 | + * Inject the AdminifyDarkMode script INTO every classic-editor TinyMCE iframe. | |
| 450 | 509 | * |
| 451 | - * The bridge below watches for `iframe[name="editor-canvas"]` (added/changed | |
| 452 | - * across edits or full-site editor route changes), injects the dark-mode JS | |
| 453 | - * into the iframe's document, and calls `AdminifyDarkMode.enable()` once it | |
| 454 | - * loads. `__adminifyDarkInjected` guards against double-injection. | |
| 510 | + * The TinyMCE Visual tab renders post content inside an iframe (`#content_ifr`, | |
| 511 | + * generally `{editor_id}_ifr`) whose body carries the `mce-content-body` class. | |
| 512 | + * As with the block-editor canvas, the parent Darkreader run never touches the | |
| 513 | + * iframe document, so the editor background stays white in dark mode. The bridge | |
| 514 | + * below watches for TinyMCE iframes (created lazily, and re-created when toggling | |
| 515 | + * Visual/Text or initializing extra editors), injects the dark-mode JS into each | |
| 516 | + * iframe's document and calls `AdminifyDarkMode.enable()` from inside. `__adminifyDM` | |
| 517 | + * guards against double-injection per iframe window. | |
| 455 | 518 | */ |
| 456 | - public function inject_darkmode_into_editor_iframe() | |
| 519 | + public function inject_darkmode_into_classic_editor_iframe() | |
| 457 | 520 | { |
| 458 | - if ( $this->pxlbsadminify_resolve_color_mode() !== 'dark' ) { | |
| 521 | + $mode = $this->pxlbsadminify_resolve_color_mode(); | |
| 522 | + if ( $mode === 'auto' ) { | |
| 523 | + $mode = 'system'; | |
| 524 | + } | |
| 525 | + // 'dark' = always on; 'system' = follow OS prefers-color-scheme (decided client-side). | |
| 526 | + if ( $mode !== 'dark' && $mode !== 'system' ) { | |
| 459 | 527 | return; |
| 460 | 528 | } |
| 461 | - // Only run on block-editor pages (post.php / post-new.php / site editor). | |
| 462 | - $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null; | |
| 463 | - if ( ! $screen || ! method_exists( $screen, 'is_block_editor' ) || ! $screen->is_block_editor() ) { | |
| 464 | - // also accept Site Editor screen ids | |
| 465 | - $is_site_editor = $screen && in_array( $screen->id, array( 'site-editor', 'gutenberg_page_gutenberg-edit-site' ), true ); | |
| 466 | - if ( ! $is_site_editor ) { | |
| 467 | - return; | |
| 468 | - } | |
| 469 | - } | |
| 470 | 529 | $dark_js_url = PXLBSADMINIFY_ASSETS . 'admin/js/wp-adminify-dark-mode' . Utils::assets_ext( '.js' ); |
| 530 | + // For 'system' mode, only proceed when the OS currently prefers dark; otherwise bail | |
| 531 | + // out of the bridge entirely so the iframe stays light (matches the parent admin). | |
| 532 | + $apply_guard = ( $mode === 'system' ) | |
| 533 | + ? 'if(!(window.matchMedia&&window.matchMedia("(prefers-color-scheme: dark)").matches)){return;}' | |
| 534 | + : ''; | |
| 471 | 535 | $bridge = '(function(){' |
| 536 | + . $apply_guard | |
| 472 | 537 | . 'var URL=' . wp_json_encode( $dark_js_url ) . ';' |
| 473 | - . 'function looksLikeEditor(ifr){try{if(ifr.name==="editor-canvas")return true;var d=ifr.contentDocument;return !!(d&&d.body&&d.body.classList&&(d.body.classList.contains("block-editor-iframe__body")||d.body.classList.contains("editor-styles-wrapper")));}catch(e){return false;}}' | |
| 538 | + . 'function looksLikeMCE(ifr){try{if(/_ifr$/.test(ifr.id||""))return true;var d=ifr.contentDocument;return !!(d&&d.body&&d.body.classList&&d.body.classList.contains("mce-content-body"));}catch(e){return false;}}' | |
| 474 | 539 | . 'function activate(w){try{if(w&&w.AdminifyDarkMode){w.AdminifyDarkMode.enable({brightness:120});return true;}}catch(e){}return false;}' |
| 475 | - . 'function inject(ifr){try{var d=ifr.contentDocument,w=ifr.contentWindow;if(!d||!w)return;if(w.__adminifyDM){activate(w);return;}w.__adminifyDM=true;if(activate(w))return;var s=d.createElement("script");s.src=URL;s.onload=function(){if(!activate(w)){setTimeout(function(){activate(w);},100);setTimeout(function(){activate(w);},500);}};(d.head||d.documentElement||d.body).appendChild(s);}catch(e){}}' | |
| 540 | + . 'function inject(ifr){try{var d=ifr.contentDocument,w=ifr.contentWindow;if(!d||!w||!d.body)return;if(w.__adminifyDM){activate(w);return;}w.__adminifyDM=true;if(activate(w))return;var s=d.createElement("script");s.src=URL;s.onload=function(){if(!activate(w)){setTimeout(function(){activate(w);},100);setTimeout(function(){activate(w);},500);}};(d.head||d.documentElement||d.body).appendChild(s);}catch(e){}}' | |
| 476 | 541 | . 'var seen=new WeakSet();' |
| 477 | 542 | . 'function watch(ifr){if(seen.has(ifr))return;seen.add(ifr);inject(ifr);ifr.addEventListener("load",function(){try{ifr.contentWindow.__adminifyDM=false;}catch(e){}inject(ifr);});}' |
| 478 | - . 'function scan(){var all=document.querySelectorAll("iframe");for(var i=0;i<all.length;i++){if(looksLikeEditor(all[i]))watch(all[i]);}}' | |
| 543 | + . 'function scan(){var all=document.querySelectorAll("iframe");for(var i=0;i<all.length;i++){if(looksLikeMCE(all[i]))watch(all[i]);}}' | |
| 479 | 544 | . 'if(document.readyState!=="loading"){scan();}else{document.addEventListener("DOMContentLoaded",scan);}' |
| 480 | 545 | . 'new MutationObserver(scan).observe(document.documentElement,{childList:true,subtree:true});' |
| 481 | 546 | . '}());'; |
| 482 | 547 | if ( function_exists( 'wp_print_inline_script_tag' ) ) { |
| @@ -483,9 +548,8 @@ | ||
| 483 | 548 | wp_print_inline_script_tag( $bridge ); |
| 484 | 549 | } else { |
| 485 | 550 | echo '<script>' . $bridge . '</script>'; // phpcs:ignore WordPress.WP.EnqueuedResources |
| 486 | 551 | } |
| 487 | - return; // sentinel — never reach legacy enqueue path below | |
| 488 | 552 | } |
| 489 | 553 | |
| 490 | 554 | /** |
| 491 | 555 | * customize.php controls: Adminify's general scripts are deliberately skipped on |
| @@ -493,9 +557,13 @@ | ||
| 493 | 557 | * the controls panel. Enqueue dark-mode standalone on the customize controls hook. |
| 494 | 558 | */ |
| 495 | 559 | public function customize_controls_darkmode_enqueue() |
| 496 | 560 | { |
| 497 | - if ($this->pxlbsadminify_resolve_color_mode() !== 'dark') { | |
| 561 | + $mode = $this->pxlbsadminify_resolve_color_mode(); | |
| 562 | + if ($mode === 'auto') { | |
| 563 | + $mode = 'system'; | |
| 564 | + } | |
| 565 | + if ($mode !== 'dark' && $mode !== 'system') { | |
| 498 | 566 | return; |
| 499 | 567 | } |
| 500 | 568 | wp_enqueue_script( |
| 501 | 569 | 'adminify--dark-mode', |
| @@ -503,9 +571,21 @@ | ||
| 503 | 571 | array(), |
| 504 | 572 | PXLBSADMINIFY_VER, |
| 505 | 573 | false |
| 506 | 574 | ); |
| 507 | - $inline = 'if(window.AdminifyDarkMode){window.AdminifyDarkMode.enable({brightness:120});}' | |
| 508 | - . 'addEventListener("load",function(){if(window.AdminifyDarkMode){window.AdminifyDarkMode.enable({brightness:120});}});'; | |
| 509 | - wp_add_inline_script('adminify--dark-mode', $inline); | |
| 575 | + wp_add_inline_script('adminify--dark-mode', $this->darkmode_enable_inline($mode)); | |
| 576 | + } | |
| 577 | + | |
| 578 | + /** | |
| 579 | + * Build the inline enable() snippet. For 'dark' it always enables; for 'system' it | |
| 580 | + * enables only when the OS currently prefers dark (prefers-color-scheme), matching | |
| 581 | + * the parent-admin behavior in Assets::header_scripts. | |
| 582 | + */ | |
| 583 | + private function darkmode_enable_inline($mode) | |
| 584 | + { | |
| 585 | + $enable = ($mode === 'system') | |
| 586 | + ? 'if(window.matchMedia&&window.matchMedia("(prefers-color-scheme: dark)").matches){window.AdminifyDarkMode.enable({brightness:120});}' | |
| 587 | + : 'window.AdminifyDarkMode.enable({brightness:120});'; | |
| 588 | + return 'if(window.AdminifyDarkMode){' . $enable . '}' | |
| 589 | + . 'addEventListener("load",function(){if(window.AdminifyDarkMode){' . $enable . '}});'; | |
| 510 | 590 | } |
| 511 | 591 | } |