Add Dark Mode public plugin source

This commit is contained in:
Jason Eugene Garrison
2026-08-23 12:11:11 -05:00
commit ddc391c687
14 changed files with 1062 additions and 0 deletions
+6
View File
@@ -0,0 +1,6 @@
* text=auto
*.png binary
*.jpg binary
*.jpeg binary
*.webp binary
*.gif binary
+4
View File
@@ -0,0 +1,4 @@
.old/
*.zip
.DS_Store
Thumbs.db
Binary file not shown.

After

Width:  |  Height:  |  Size: 662 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

+267
View File
@@ -0,0 +1,267 @@
## 4.8.18 public-track development - 2026-08-23
- Established the dedicated public source repository at https://git.christit.com/gracepress/dark-mode-by-gracepress and added the canonical public plugin page to the plugin metadata.
- Prepared the established GracePress Dark Mode engine for WordPress.org distribution without removing any Dark Mode control, option, or runtime behavior.
- Preserved optional local OmniLog event hooks and conditional GracePress Central Hub routing.
- Removed the anonymous ecosystem ping system and private ChristIT update engine from the public track.
- Compacted and reorganized the existing four-part settings interface while retaining every field and function.
- Replaced the remotely loaded administration background with an original bundled sunrise image.
The public development track remains at 4.8.18. Version 5.0.0 is reserved for the deliberate first WordPress.org release.
## 4.8.18 - 2026-08-03
- Corrected GracePress Builder hero backgrounds in dark mode: CSS-backed hero artwork now receives the same counter-inversion as normal media, preserving its original color, contrast, and full opacity.
## 4.8.17 - 2026-07-04
- Changed time-based dark mode to use the WordPress site timezone/current site hour instead of browser clock time.
- Stopped stale browser localStorage from overriding the scheduled auto mode on page load while preserving explicit URL and manual toggle behavior.
## 4.8.16 - 2026-07-03
- Added Chrome fullscreen video exceptions for dark-mode media filters so live and recorded videos do not render inverted or washed out in fullscreen.
## 4.8.15 - 2026-06-25
- Stopped applying sub-100% brightness and contrast compression to the root dark-mode page filter because it permanently muted final-composited brand art such as the ChristP2P header logo.
- Returned the header logo to a normal media-style counter-correction now that the root filter no longer caps its rendered saturation and brightness.
- Raised and isolated the GracePress UI header logo stacking context so local overlay layers cannot sit on top of the brand mark in dark mode.
## 4.8.14 - 2026-06-25
- Strengthened the GracePress UI header logo dark-mode correction after screenshot comparison showed the logo was still losing saturation and brightness under the root dark-mode filter.
- Kept the stronger compensation scoped to the top-left header logo only, without changing thumbnail, video, or general media handling.
## 4.8.13 - 2026-06-25
- Added a logo-specific dark-mode correction for the GracePress UI header logo so the root brightness/contrast filter no longer leaves the site mark washed out after media reinversion.
- Kept the change scoped to the top-left header logo without changing thumbnail or general media correction behavior.
## 4.8.12 - 2026-06-25
- Restored the GracePress UI header logo to full opacity in dark mode so it is no longer dimmed by the global media opacity rule.
- Kept the fix scoped to the shared Dark Mode media correction path without changing GracePress UI header layout.
## 4.8.11 - 2026-06-25
- Raised the specificity of GracePress Blocks media counter-correction so thumbnail images are no longer dimmed by the global dark-mode media opacity rule.
- Kept hover preview videos and static thumbnails on the same full-strength correction path in dark mode.
## 4.8.10 - 2026-06-25
- Fixed frontend Plyr video playback in dark mode by no longer forcing the poster overlay visible after playback starts.
- Preserved dark-mode media correction while allowing the active video frame to render above the poster layer.
## 4.8.9 - 2026-06-25
- Forward rollback release: restored the known-good pre-convention package behavior and republished it as a newer GracePress update.
# GracePress: Dark Mode Changelog
## 4.8.7 - 2026-06-24
- Removed GracePress Blocks overlay and text counter-correction rules from Dark Mode.
- Kept Dark Mode focused on document inversion, media pixel restoration, and transition effects while Blocks owns its own presentation.
## 4.8.6 - 2026-06-24
- Fixed mode switching so the veil now performs a real two-phase transition: cover the page, flip the mode while covered, then reveal the page smoothly.
- Added configurable transition styles for Fade, Side Wipe, Vertical Wipe, Iris, and Zoom Fade without adding a frontend animation dependency.
- Added the selected transition style to saved settings and OmniLog context.
## 4.8.5 - 2026-06-24
- Corrected GracePress Blocks overlay-card text colors and shadows under the global invert engine so titles render as white text with dark shadows instead of black text with pale glow.
- Kept media correction intact while targeting only Blocks overlay, Bento, Masonry, and post feature title layers.
## 4.8.4 - 2026-06-24
- Added dark-mode counter-correction for GracePress Blocks overlay and shade layers so card title gradients stay dark instead of inverting into pale thumbnail washout.
- Preserved media double-inversion behavior while correcting only the readability layers used by video cards, Bento cards, shorts overlays, and post feature heroes.
## 4.8.3 - 2026-06-24
- Removed the global filter transition that caused visible polarity flashing during light/dark switches.
- Changed the mode switch veil into a two-phase quick fade so the page flips instantly while covered, then fades back in.
## 4.8.2 - 2026-06-24
- Added full current GracePress release metadata, including public-release flags, author URI, license, and minimum WordPress version.
- Routed activation, deactivation, privacy toggle, filter reset, and settings-save events through structured OmniLog events with `gp_log` fallback context.
- Removed the unused legacy file logger class so Dark Mode has one active logging path.
- Updated stale admin version text and aligned the admin footer with the shared GracePress support links.
## 4.8.1 - 2026-06-24
- Added a quick black/white mode-switch veil so light/dark toggles hide transient global-filter flashes on thumbnails and media blocks.
- Tightened Gutenberg, GracePress hero, card thumbnail, widget, avatar, and player media counter-correction so images remain natural and full-strength in dark mode.
- Added current GracePress stage/release headers and a configurable blink-duration control for the transition veil.
## 4.8.0 - 2026-05-27
- Removed the admin-bar boolean output that printed a stray selectable `1` after the GracePress Dark Mode toolbar item.
- Kept dark-mode video rules scoped to actual players instead of card thumbnail hover previews.
## 4.7.9 - 2026-05-27
- Kept the current Dark Mode source in place and advanced the updater-visible version after the rollback test sequence.
- Leaves thumbnail behavior under Blocks/Video Management while giving GracePress Central a clean package to install.
## 4.7.8 - 2026-05-27
- Removed dark-mode CSS rules that forced GracePress Blocks preview videos and thumbnail images into a lazy-preview state.
- Kept the playback-safe rules for actual video players while leaving card thumbnails under Blocks control.
- Advanced the updater metadata past the already-installed 4.7.6/4.7.7 line.
## 4.7.6 - 2026-05-27
- Updated video-card dark mode preview rules to match lazy hover/focus loading and avoid hiding thumbnails before animated previews are ready.
## 4.7.5 - 2026-05-25
- Restored a backend admin-bar dark mode toggle so wp-admin can switch modes without returning to the frontend.
- Ensured admin dark mode support is enabled for existing installs once after upgrade.
- Updated the module version metadata used by the GracePress updater.
## Reconstruction Notes
- Changelog initialized during reconstruction.
<!-- GP-RECONSTRUCTED-CHANGELOG:START -->
## Reconstructed History
These entries were inferred from local distribution archives, module headers, and `.old` backups. They are intentionally conservative and may not capture the full intent of each change.
### 4.7.4 - reconstructed
- Reconstructed from archive `dark-mode-v4.7.4.zip` (2026-05-21).
- Header description at this version: A premium-grade Dark Mode engine. Features absolute Anti-FOUC synchronization, OS-level sync, hardware-accelerated CSS inversion, filter tuning, variable dimming, and keyboard shortcuts.
- Header advertised WordPress compatibility through 7.0.
- Catalog/category marker: User Interface.
- Header icon marker: 🌓.
### 4.7.3 - reconstructed
- Reconstructed from archive `dark-mode-v4.7.3.zip` (2026-05-21).
- Header description at this version: A premium-grade Dark Mode engine. Features absolute Anti-FOUC synchronization, OS-level sync, hardware-accelerated CSS inversion, filter tuning, variable dimming, and keyboard shortcuts.
- Catalog/category marker: User Interface.
- Header icon marker: 🌓.
### 4.7.2 - reconstructed
- Reconstructed from archive `dark-mode-v4.7.2.zip` (2026-05-20).
- Header description at this version: A premium-grade Dark Mode engine. Features absolute Anti-FOUC synchronization, OS-level sync, hardware-accelerated CSS inversion, filter tuning, variable dimming, and keyboard shortcuts.
- Catalog/category marker: User Interface.
- Header icon marker: 🌓.
### 4.7.1 - reconstructed
- Reconstructed from archive `dark-mode-v4.7.1.zip` (2026-05-20).
- Header description at this version: A premium-grade Dark Mode engine. Features absolute Anti-FOUC synchronization, OS-level sync, hardware-accelerated CSS inversion, filter tuning, variable dimming, and keyboard shortcuts.
- Catalog/category marker: User Interface.
- Header icon marker: 🌓.
### 4.7.0 - reconstructed
- Reconstructed from archive `dark-mode-v4.7.0.zip` (2026-05-20).
- Header description at this version: A premium-grade Dark Mode engine. Features absolute Anti-FOUC synchronization, OS-level sync, hardware-accelerated CSS inversion, filter tuning, variable dimming, and keyboard shortcuts.
- Catalog/category marker: User Interface.
- Header icon marker: 🌓.
### 4.6.9 - reconstructed
- Reconstructed from archive `dark-mode-v4.6.9.zip` (2026-05-20).
- Header description at this version: A premium-grade Dark Mode engine. Features absolute Anti-FOUC synchronization, OS-level sync, hardware-accelerated CSS inversion, filter tuning, variable dimming, and keyboard shortcuts.
- Catalog/category marker: User Interface.
- Header icon marker: 🌓.
### 4.6.8 - reconstructed
- Reconstructed from archive `dark-mode-v4.6.8.zip` (2026-05-16).
- Header description at this version: A premium-grade Dark Mode engine. Features absolute Anti-FOUC synchronization, OS-level sync, hardware-accelerated CSS inversion, filter tuning, variable dimming, and keyboard shortcuts.
- Catalog/category marker: User Interface.
- Header icon marker: 🌓.
### 4.6.7 - reconstructed
- Reconstructed from archive `dark-mode-v4.6.7.zip` (2026-05-16).
- Header description at this version: A premium-grade Dark Mode engine. Features absolute Anti-FOUC synchronization, OS-level sync, hardware-accelerated CSS inversion, filter tuning, variable dimming, and keyboard shortcuts.
- Catalog/category marker: User Interface.
- Header icon marker: 🌓.
### 4.6.6 - reconstructed
- Reconstructed from archive `dark-mode-v4.6.6.zip` (2026-05-16).
- Header description at this version: A premium-grade Dark Mode engine. Features absolute Anti-FOUC synchronization, OS-level sync, hardware-accelerated CSS inversion, filter tuning, variable dimming, and keyboard shortcuts.
- Catalog/category marker: User Interface.
- Header icon marker: 🌓.
### 4.6.5 - reconstructed
- Reconstructed from archive `dark-mode-v4.6.5.zip` (2026-04-01).
- Header description at this version: A premium-grade Dark Mode engine. Features absolute Anti-FOUC synchronization, OS-level sync, hardware-accelerated CSS inversion, filter tuning, variable dimming, and keyboard shortcuts.
- Catalog/category marker: User Interface.
- Header icon marker: 🌓.
### 4.6.4 - reconstructed
- Reconstructed from archive `dark-mode-v4.6.4.zip` (2026-04-01).
- Header description at this version: A premium-grade Dark Mode engine. Features absolute Anti-FOUC synchronization, OS-level sync, hardware-accelerated CSS inversion, filter tuning, variable dimming, and keyboard shortcuts.
- Catalog/category marker: User Interface.
- Header icon marker: 🌓.
### 4.6.3 - reconstructed
- Reconstructed from archive `dark-mode-v4.6.3.zip` (2026-04-01).
- Header description at this version: A premium-grade Dark Mode engine. Features absolute Anti-FOUC synchronization, OS-level sync, hardware-accelerated CSS inversion, filter tuning, variable dimming, and keyboard shortcuts.
- Catalog/category marker: User Interface.
- Header icon marker: 🌓.
### 4.6.2 - reconstructed
- Reconstructed from archive `dark-mode-v4.6.2.zip` (2026-04-01).
- Header description at this version: A premium-grade Dark Mode engine. Features absolute Anti-FOUC synchronization, OS-level sync, hardware-accelerated CSS inversion, filter tuning, variable dimming, and keyboard shortcuts.
- Catalog/category marker: User Interface.
- Header icon marker: 🌓.
### 4.6.1 - reconstructed
- Reconstructed from archive `dark-mode-v4.6.1.zip` (2026-04-01).
- Header description at this version: A premium-grade Dark Mode engine. Features absolute Anti-FOUC synchronization, OS-level sync, hardware-accelerated CSS inversion, filter tuning, variable dimming, and keyboard shortcuts.
- Catalog/category marker: User Interface.
- Header icon marker: 🌓.
### 4.6.0 - reconstructed
- Reconstructed from archive `dark-mode-v4.6.0.zip` (2026-04-01).
- Header description at this version: A premium-grade Dark Mode engine. Features absolute Anti-FOUC synchronization, OS-level sync, hardware-accelerated CSS inversion, filter tuning, variable dimming, and keyboard shortcuts.
- Header icon marker: 🌓.
### 4.5.0 - reconstructed
- Reconstructed from archive `dark-mode-v4.5.0.zip` (2026-03-31).
- Header description at this version: A premium-grade Dark Mode engine. Features absolute Anti-FOUC synchronization, OS-level sync, hardware-accelerated CSS inversion, filter tuning, and keyboard shortcuts.
- Header icon marker: 🌓.
### 4.4.0 - reconstructed
- Reconstructed from archive `dark-mode-v4.4.0.zip` (2026-03-30).
- Header description at this version: A premium-grade Dark Mode engine. Features absolute Anti-FOUC synchronization, OS-level sync, hardware-accelerated CSS inversion, keyboard shortcuts, and image dimming.
- Header icon marker: 🌓.
### 4.3.1 - reconstructed
- Reconstructed from archive `dark-mode-v4.3.1.zip` (2026-03-30).
- Header description at this version: A premium-grade Dark Mode engine. Features absolute Anti-FOUC synchronization, OS-level sync, hardware-accelerated CSS inversion, granular exclusions, and image dimming.
- Header icon marker: 🌓.
### 4.3.0 - reconstructed
- Reconstructed from archive `dark-mode-v4.3.0.zip` (2026-03-30).
- Header description at this version: A premium-grade Dark Mode engine. Features absolute Anti-FOUC synchronization, OS-level sync, hardware-accelerated CSS inversion, granular exclusions, and image dimming.
- Header icon marker: 🌓.
### 4.2.0 - reconstructed
- Reconstructed from archive `dark-mode-v4.2.0.zip` (2026-03-29).
- Header description at this version: A premium-grade Dark Mode engine. Features absolute Anti-FOUC synchronization, OS-level sync, hardware-accelerated CSS inversion, and image dimming.
- Header icon marker: 🌓.
### 4.1.0 - reconstructed
- Reconstructed from archive `dark-mode-v4.1.0.zip` (2026-03-27).
- Header description at this version: A premium-grade Dark Mode engine. Features absolute Anti-FOUC synchronization, hardware-accelerated CSS inversion, and image dimming.
- Header advertised WordPress compatibility through 6.4.
- Header icon marker: 🌓.
### 4.0.0 - reconstructed
- Reconstructed from archive `dark-mode-v4.0.0.zip` (2026-03-27).
- Header description at this version: A premium-grade Dark Mode engine. Features absolute Anti-FOUC (white flash) blocking, OS-level preference detection, and granular CSS exclusion rules.
- Header advertised WordPress compatibility through 6.4.
- Header icon marker: 🌓.
### 3.1.0 - reconstructed
- Reconstructed from 1 file backup(s) in `plugins/dark-mode/.old`.
- Exact intent unknown; this confirms a recoverable historical version existed.
### 3.0.0 - reconstructed
- Reconstructed from 1 file backup(s) in `plugins/dark-mode/.old`.
- Exact intent unknown; this confirms a recoverable historical version existed.
### 2.2.2 - reconstructed
- Reconstructed from 3 file backup(s) in `plugins/dark-mode/.old`.
- Exact intent unknown; this confirms a recoverable historical version existed.
<!-- GP-RECONSTRUCTED-CHANGELOG:END -->
+338
View File
@@ -0,0 +1,338 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
<https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Moe Ghoul>, 1 April 1989
Moe Ghoul, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
+50
View File
@@ -0,0 +1,50 @@
# Dark Mode by GracePress
A configurable dark mode for WordPress websites and the WordPress administration area.
Dark Mode by GracePress includes anti-flash loading, operating-system preference support, visual tuning, media correction, transitions, and accessible controls that can be placed where a site needs them.
## Project status
Version 4.8.18 is the current public-development baseline. The plugin is being prepared, documented, and tested for submission to WordPress.org. Version 5.0.0 is reserved for the deliberate first WordPress.org release.
There is no official public download yet. Candidate packages are used only for controlled testing until the public release is approved.
## Links
- [Public plugin page](https://christit.com/gracepress/plugins/dark-mode-by-gracepress/)
- [GracePress project](https://christit.com/gracepress/)
- [GracePress plugin catalog](https://christit.com/gracepress/plugins/)
- [Christ IT](https://christit.com/)
## Features
- Device-theme, scheduled, light, or dark first-visit behavior.
- Remembered visitor choice with anti-flash startup synchronization.
- Brightness, contrast, and media-dimming controls.
- Media correction for images, video, and fullscreen playback.
- Fade, horizontal wipe, vertical wipe, iris, and zoom transitions.
- Floating, menu, shortcode, administrator-bar, and keyboard controls.
- Independent frontend and WordPress administration enablement.
- Page, selector, and custom-CSS compatibility controls.
## Requirements
- WordPress 6.0 or newer.
- PHP 7.4 or newer.
## Privacy and integrations
The public plugin contains no telemetry, private update connection, license server, or required external service.
GracePress Central Hub routing and OmniLog events are optional local integrations. They are used only when those plugins are already installed and active; neither is required.
## Installation
The official installation route will be published here and on the public plugin page after the WordPress.org release is approved. See `readme.txt` for the current controlled-testing instructions and WordPress plugin documentation.
## License
Dark Mode by GracePress is licensed under [GPL-2.0-or-later](LICENSE.txt).
Published by Jason Eugene Garrison through [Christ IT](https://christit.com/). Questions may be sent to [jason@christit.com](mailto:jason@christit.com).
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

+332
View File
@@ -0,0 +1,332 @@
<?php
/**
* Plugin Name: Dark Mode by GracePress
* Plugin URI: https://christit.com/gracepress/plugins/dark-mode-by-gracepress/
* Description: A complete dark mode engine with anti-flash loading, OS preference support, visual tuning, transitions, and flexible controls.
* Version: 4.8.18
* Stage: Beta
* Release Channel: WordPress.org
* Public Release: No
* Public Candidate: Yes
* WordPress.org Slug: dark-mode-by-gracepress
* WordPress.org Status: Draft
* Internal Source Slug: dark-mode
* Conversion Status: Lab Testing
* Tested up to: 7.1
* Category: User Interface
* Settings Slug: gracepress-dark-mode
* Author: Jason Eugene Garrison
* Author URI: https://christit.com
* License: GPL-2.0-or-later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
* Text Domain: dark-mode-by-gracepress
* Requires at least: 6.0
* Requires PHP: 7.4
* Privacy: No telemetry
* External Services: None
* Optional Integrations: GracePress Central Hub, OmniLog
* Plugin Check Status: Passed
* Plugin Check Date: 2026-08-23
* Icon: 🌓
*/
if(!defined('ABSPATH'))exit;
if(!defined('GP_DARKMODE_VERSION')) define('GP_DARKMODE_VERSION','4.8.18');
function gp_darkmode_log($message,$event='message',$context=[],$level='INFO'){
$context=is_array($context)?$context:['value'=>$context];
$context['version']=GP_DARKMODE_VERSION;
$context['level']=$level;
try{
if(function_exists('gp_omnilog')) gp_omnilog('dark-mode',$event,array_merge(['message'=>$message],$context));
}catch(\Throwable $e){}
try{
if(function_exists('gp_log')) gp_log($message,'DARKMODE',array_merge(['event'=>$event],$context));
}catch(\Throwable $e){}
}
register_deactivation_hook(__FILE__,function(){
gp_darkmode_log('Dark Mode engine deactivated.','deactivated');
});
register_activation_hook(__FILE__, function() {
if(get_option('gp_dm_brightness') === false) update_option('gp_dm_brightness', 95);
if(get_option('gp_dm_contrast') === false) update_option('gp_dm_contrast', 90);
if(get_option('gp_dm_dim_level') === false) update_option('gp_dm_dim_level', 85);
if(get_option('gracepress_dark_admin_enable') === false) update_option('gracepress_dark_admin_enable', '1');
if(get_option('gp_dm_veil_ms') === false) update_option('gp_dm_veil_ms', 160);
if(get_option('gp_dm_veil_effect') === false) update_option('gp_dm_veil_effect', 'fade');
gp_darkmode_log('Dark Mode engine activated.','activated');
});
add_action('admin_init', function() {
if (get_option('gp_dm_adminbar_toggle_restored') === '1') return;
update_option('gracepress_dark_admin_enable', '1');
update_option('gp_dm_adminbar_toggle_restored', '1');
});
// Dynamic Self-Aware Router
add_action('admin_menu',function(){
$s='gracepress-dark-mode';
$t='Dark Mode';
$is_theme_active = (get_template() === 'gracepress-theme');
$is_theme_required = false;
if (!function_exists('get_plugin_data')) include_once(ABSPATH . 'wp-admin/includes/plugin.php');
$plugin_data = get_plugin_data(__FILE__);
if (isset($plugin_data['Category']) && strtolower(trim($plugin_data['Category'])) === 'theme required') {
$is_theme_required = true;
}
if(class_exists('GracePress_Central_Hub')) {
$parent_slug = ($is_theme_active && $is_theme_required) ? 'gracepress-plugins' : 'gracepress-central';
add_submenu_page($parent_slug, $t, $t, 'manage_options', $s, 'gp_darkmode_admin_page');
} else {
add_options_page($t, $t, 'manage_options', $s, 'gp_darkmode_admin_page');
}
},100);
function gp_darkmode_is_excluded(){
$ex_pages = get_option('gracepress_dark_exclude_pages','');
if(!empty($ex_pages) && (is_page() || is_single())){
$pid = get_the_ID();
$arr = array_map('trim', explode(',', $ex_pages));
if(in_array($pid, $arr)) return true;
}
return false;
}
function gp_darkmode_icons($s=''){
$s=$s?$s:get_option('gracepress_dark_icon_style','classic');
if($s=='minimal')return['l'=>'⚫','d'=>'⚪'];
if($s=='bulbs')return['l'=>'🌑','d'=>'💡'];
if($s=='text')return['l'=>'DARK','d'=>'LIGHT'];
return['l'=>'🌙','d'=>'☀️'];
}
function gp_darkmode_btn($f=false,$s=''){
$sz=get_option('gracepress_dark_button_size','normal');
$s=$s?$s:get_option('gracepress_dark_icon_style','classic');
$i=gp_darkmode_icons($s);$l=$i['l'];$d=$i['d'];$c="gracepress-dark-toggle-trigger";
if($f){$p=get_option('gracepress_dark_button_position','bottom-right');$c.=" gracepress-floating gracepress-pos-$p";}
if($s==='switch'){
$c.=" gracepress-pill-switch gracepress-size-$sz";
return "<div class='$c' data-light='$l' data-dark='$d'><div class='gracepress-pill-knob'>$l</div></div>";
}else{
$c.=" gracepress-dark-toggle-btn gracepress-size-$sz".($s==='text'?' gracepress-text-btn':'');
return "<button class='$c' data-light='$l' data-dark='$d'><span class='gracepress-icon-wrapper'>$l</span></button>";
}
}
add_action('wp_head','gp_darkmode_head',1); add_action('admin_head','gp_darkmode_head',1);
function gp_darkmode_head(){
if(!is_admin()&&gp_darkmode_is_excluded())return;
$ds=get_option('gracepress_dark_default_state','light');$sp=get_option('gracepress_dark_transition_speed','0.3s');$pl=get_option('gracepress_dark_pulse_effect','0');$ex=get_option('gracepress_dark_exclusions','');$cus=get_option('gp_dm_css','');
if(!preg_match('/^(?:\d+(?:\.\d+)?|\.\d+)(?:ms|s)$/',$sp))$sp='0.3s';
$br=get_option('gp_dm_brightness',95);
$ct=get_option('gp_dm_contrast',90);
$dim=get_option('gp_dm_dim_level',85);
$root_br = max(100, (int)$br);
$root_ct = max(100, (int)$ct);
$xstr="";if(!empty($ex)){$xp=explode(',',$ex);$xc=[];foreach($xp as $p){$p=trim($p);if(!empty($p)&&!preg_match('/[{};<>]|\/\*/',$p))$xc[]="html.gracepress-dark-active ".$p;}if(!empty($xc))$xstr=",".implode(',',$xc);}
$veil_ms=max(0,min(800,absint(get_option('gp_dm_veil_ms',160))));
$veil_effect=sanitize_key(get_option('gp_dm_veil_effect','fade'));
if(!in_array($veil_effect,['fade','wipe-right','wipe-down','iris','zoom'],true))$veil_effect='fade';
$site_dt=function_exists('current_datetime')?current_datetime():new DateTimeImmutable('now',function_exists('wp_timezone')?wp_timezone():null);
$site_hour=(int)$site_dt->format('G');
$site_tz=wp_json_encode(function_exists('wp_timezone_string')?wp_timezone_string():'');
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Values are JSON encoded before entering this early inline state script.
echo "<script>!function(){try{var p=new URLSearchParams(window.location.search),stored=localStorage.getItem('gracepressDarkMode'),d=".wp_json_encode($ds).",siteHour=".wp_json_encode($site_hour).",siteTimezone=".$site_tz.",s=null;if(p.get('darkmode')==='1')s='enabled';else if(p.get('lightmode')==='1')s='disabled';else if(d==='auto'){s=(siteHour>=18||siteHour<=6)?'enabled':'disabled';}else if(stored){s=stored;}else if(d==='os')s=window.matchMedia&&window.matchMedia('(prefers-color-scheme: dark)').matches?'enabled':'disabled';else s=(d==='dark')?'enabled':'disabled';document.documentElement.setAttribute('data-gp-dark-timezone',siteTimezone||'site');document.documentElement.setAttribute('data-gp-dark-hour',String(siteHour));if(s==='enabled'){document.documentElement.classList.add('gracepress-dark-active');}}catch(e){}}();</script>";
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Numeric, enum and selector values are validated; administrator-authored CSS is an intentional manage_options feature.
echo "<style>:root{--gp-dm-media-opacity:".esc_html((string)($dim/100)).";--gp-dm-veil-ms:".esc_html((string)$veil_ms)."ms;}html{transition:background-color $sp ease;}html.gracepress-dark-active{filter:invert(100%) hue-rotate(180deg) brightness($root_br%) contrast($root_ct%)!important;background-color:#fff!important;}html.gracepress-dark-active body{background-color:#fff!important;}html.gracepress-dark-active img,html.gracepress-dark-active video,html.gracepress-dark-active iframe,html.gracepress-dark-active picture,html.gracepress-dark-active .gracepress-no-invert,html.gracepress-dark-active #adminmenuwrap,html.gracepress-dark-active #adminmenuback,html.gracepress-dark-active #wpadminbar$xstr{filter:invert(100%) hue-rotate(180deg)!important;opacity:var(--gp-dm-media-opacity)!important;}.gracepress-darkmode-veil{position:fixed;inset:0;z-index:2147483647;pointer-events:none;opacity:0;background:#000;clip-path:inset(0);transform:none;transform-origin:center;transition:opacity var(--gp-dm-veil-ms) ease,clip-path var(--gp-dm-veil-ms) cubic-bezier(.65,0,.35,1),transform var(--gp-dm-veil-ms) ease;will-change:opacity,clip-path,transform;}.gracepress-darkmode-veil.is-active{opacity:1;}.gracepress-darkmode-veil[data-effect='wipe-right']{opacity:1;clip-path:inset(0 100% 0 0);}.gracepress-darkmode-veil[data-effect='wipe-right'].is-active{clip-path:inset(0);}.gracepress-darkmode-veil[data-effect='wipe-down']{opacity:1;clip-path:inset(0 0 100% 0);}.gracepress-darkmode-veil[data-effect='wipe-down'].is-active{clip-path:inset(0);}.gracepress-darkmode-veil[data-effect='iris']{opacity:1;clip-path:circle(0 at 50% 50%);}.gracepress-darkmode-veil[data-effect='iris'].is-active{clip-path:circle(150% at 50% 50%);}.gracepress-darkmode-veil[data-effect='zoom']{opacity:0;transform:scale(.92);}.gracepress-darkmode-veil[data-effect='zoom'].is-active{opacity:1;transform:scale(1);}html.gracepress-dark-active .gracepress-darkmode-veil{filter:invert(100%) hue-rotate(180deg)!important;}.gracepress-dark-toggle-btn{background:#222!important;color:#fff!important;border:2px solid #444!important;border-radius:50px!important;cursor:pointer;box-shadow:0 4px 6px rgba(0,0,0,.3)!important;transition:all .3s ease!important;display:inline-flex!important;align-items:center!important;justify-content:center!important;line-height:1!important;text-decoration:none!important;margin:0;z-index:999999;}.gracepress-dark-toggle-btn:hover{background:#444!important;transform:scale(1.05)!important;}.gracepress-pill-switch{background:#cbd5e1;border-radius:50px;position:relative;cursor:pointer;display:inline-block;vertical-align:middle;transition:.3s;box-shadow:inset 0 2px 4px rgba(0,0,0,.1);border:1px solid #94a3b8;box-sizing:content-box;z-index:999999;}.gracepress-pill-knob{background:#fff;border-radius:50%;position:absolute;top:2px;left:2px;display:flex;align-items:center;justify-content:center;transition:.3s;box-shadow:0 2px 5px rgba(0,0,0,.2);}html.gracepress-dark-active .gracepress-pill-switch{background:#0ea5e9;border-color:#0284c7;}.gracepress-text-btn{font-weight:bold;letter-spacing:1px;font-size:12px!important;padding:8px 16px!important;}.gracepress-size-small.gracepress-dark-toggle-btn{padding:6px 10px;font-size:14px;}.gracepress-size-normal.gracepress-dark-toggle-btn{padding:10px 15px;font-size:18px;}.gracepress-size-large.gracepress-dark-toggle-btn{padding:14px 22px;font-size:24px;}.gracepress-size-small.gracepress-pill-switch{width:50px;height:26px;}.gracepress-size-small .gracepress-pill-knob{width:20px;height:20px;font-size:12px;}html.gracepress-dark-active .gracepress-size-small .gracepress-pill-knob{transform:translateX(24px);}.gracepress-size-normal.gracepress-pill-switch{width:64px;height:34px;}.gracepress-size-normal .gracepress-pill-knob{width:28px;height:28px;font-size:16px;}html.gracepress-dark-active .gracepress-size-normal .gracepress-pill-knob{transform:translateX(30px);}.gracepress-size-large.gracepress-pill-switch{width:80px;height:42px;}.gracepress-size-large .gracepress-pill-knob{width:36px;height:36px;font-size:20px;}html.gracepress-dark-active .gracepress-size-large .gracepress-pill-knob{transform:translateX(38px);}.gracepress-floating{position:fixed;z-index:999999;}.gracepress-pos-bottom-right{bottom:25px;right:25px;}.gracepress-pos-bottom-left{bottom:25px;left:25px;}.gracepress-pos-top-right{top:25px;right:25px;}.gracepress-pos-top-left{top:25px;left:25px;}#wpadminbar .gracepress-dark-menu-trigger a{background:transparent;border:none;box-shadow:none;border-radius:0;padding:0 8px;}#wpadminbar .gracepress-dark-menu-trigger a:hover{background:transparent;transform:none;color:#72aee6;}".($pl?"@keyframes gpPulse{0%{box-shadow:0 0 0 0 rgba(100,100,100,.7);}70%{box-shadow:0 0 0 10px rgba(100,100,100,0);}100%{box-shadow:0 0 0 0 rgba(100,100,100,0);}}.gracepress-floating{animation:gpPulse 2.5s infinite;}.gracepress-floating:hover{animation:none;}":"").$cus."</style>";
echo "<style>html.gracepress-dark-active :where(.gp-header-logo-link img,.wp-block-image img,.wp-block-gallery img,.wp-block-media-text img,.wp-block-cover img,.wp-block-cover video,.wp-block-post-featured-image img,.wp-block-embed iframe,.wp-block-video video,.wp-block-audio audio,.gp-singular-hero img,.gp-singular-content img,.gp-video-archive-hero img,.gpb-hero-image,.gpb-post-feature-image,.gpb-post-feature-meta img,.gpb-card-avatar,.gpb-thumb-wrapper img,.gpb-thumb-wrapper video,.gpb-short-card img,.gpb-short-card video,.gpb-sidebar-thumb img,.gpb-series-hero-video,.gp-v-player-container video,.gp-v-next-card img,.g-up-t img,.g-up-t video,.widget img,.widget_media_image img,.widget_media_video video,.wp-caption img,.avatar){filter:invert(100%) hue-rotate(180deg) saturate(1.06) contrast(1.04) brightness(1.015)!important;opacity:1!important;mix-blend-mode:normal!important;}html.gracepress-dark-active .gpb-thumb-wrapper img,html.gracepress-dark-active .gpb-thumb-wrapper video,html.gracepress-dark-active .gpb-short-card img,html.gracepress-dark-active .gpb-short-card video,html.gracepress-dark-active .gpb-post-feature-image,html.gracepress-dark-active .gpb-hero-image,html.gracepress-dark-active .gpb-series-hero-video,html.gracepress-dark-active .gp-v-next-card img,html.gracepress-dark-active .g-up-t img,html.gracepress-dark-active .g-up-t video{filter:invert(100%) hue-rotate(180deg) saturate(1.06) contrast(1.04) brightness(1.015)!important;opacity:1!important;mix-blend-mode:normal!important;}html.gracepress-dark-active .gpb-grid-card.gpb-has-preview.gpb-preview-playing .gpb-thumb-wrapper img,html.gracepress-dark-active .gpb-short-card.gpb-has-preview.gpb-preview-playing img{opacity:0!important;visibility:hidden!important;}html.gracepress-dark-active .gpb-grid-card.gpb-preview-playing .gpb-thumb-wrapper video,html.gracepress-dark-active .gpb-short-card.gpb-preview-playing video{opacity:1!important;visibility:visible!important;}html.gracepress-dark-active .gpc video,html.gracepress-dark-active .plyr video,html.gracepress-dark-active video[controls],html.gracepress-dark-active #gp-ad-video{opacity:1!important;}html.gracepress-dark-active .gpc .plyr__poster,html.gracepress-dark-active .plyr__video-wrapper .plyr__poster{filter:invert(100%) hue-rotate(180deg)!important;}html.gracepress-dark-active .plyr--playing .plyr__poster,html.gracepress-dark-active .plyr--paused:not(.plyr--stopped) .plyr__poster{opacity:0!important;visibility:hidden!important;}html.gracepress-dark-active .gp-ad-play-fallback{filter:invert(100%) hue-rotate(180deg)!important;opacity:1!important;}</style>";
echo "<style>html.gracepress-dark-active :fullscreen video,html.gracepress-dark-active video:fullscreen,html.gracepress-dark-active .gp-live-player:fullscreen video,html.gracepress-dark-active .plyr:fullscreen video,html.gracepress-dark-active :-webkit-full-screen video,html.gracepress-dark-active video:-webkit-full-screen,html.gracepress-dark-active .gp-live-player:-webkit-full-screen video,html.gracepress-dark-active .plyr:-webkit-full-screen video{filter:none!important;opacity:1!important;mix-blend-mode:normal!important;}</style>";
echo "<style>html.gracepress-dark-active .gp-header-logo-link{position:relative!important;z-index:100002!important;isolation:isolate!important;}html.gracepress-dark-active .gp-header-logo-link,html.gracepress-dark-active .gp-header-logo-link *{opacity:1!important;mix-blend-mode:normal!important;}html.gracepress-dark-active .gp-header-logo-link img{filter:invert(100%) hue-rotate(180deg) saturate(1.08) contrast(1.02) brightness(1.02)!important;}</style>";
}
/**
* Builder hero images are CSS backgrounds rather than img elements. Counter the
* root dark-mode inversion on their composed surface so they retain the same
* color and contrast as the original artwork.
*/
function gp_darkmode_builder_hero_correction(){
if(!is_admin()&&gp_darkmode_is_excluded())return;
echo '<style>html.gracepress-dark-active .gpb-hero{filter:invert(100%) hue-rotate(180deg)!important;opacity:1!important;mix-blend-mode:normal!important;}</style>';
}
add_action('wp_head','gp_darkmode_builder_hero_correction',2);
add_action('wp_footer','gp_darkmode_ftr',99); add_action('admin_footer','gp_darkmode_ftr',99);
function gp_darkmode_ftr(){
if(!is_admin()&&gp_darkmode_is_excluded())return;
if(!is_admin()&&get_option('gracepress_dark_frontend_enable','1')==='1')echo wp_kses_post(gp_darkmode_btn(true));
$kbd=get_option('gp_dm_kbd',1)?'true':'false';
$effect_json=wp_json_encode(sanitize_key(get_option('gp_dm_veil_effect','fade')));
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- The effect is allowlisted and the keyboard flag is a PHP-generated boolean literal.
echo "<script>document.addEventListener('DOMContentLoaded',function(){const h=document.documentElement;const fx=$effect_json;let v=null,busy=false;function ms(){return Math.max(0,parseInt(getComputedStyle(h).getPropertyValue('--gp-dm-veil-ms'))||160);}function after(t,fn){window.setTimeout(fn,Math.max(60,t)+35);}function veil(n,done){const total=ms();if(total<=0){done();return;}const phase=Math.max(70,Math.round(total/2));if(!v){v=document.createElement('div');v.className='gracepress-darkmode-veil';document.body.appendChild(v);}v.dataset.effect=fx||'fade';v.style.transitionDuration=phase+'ms';v.style.background=n==='enabled'?'#000':'#fff';v.classList.remove('is-active');v.offsetHeight;requestAnimationFrame(function(){v.classList.add('is-active');after(phase,function(){done();requestAnimationFrame(function(){v.classList.remove('is-active');after(phase,function(){busy=false;});});});});}function a(s){if(s==='enabled'){h.classList.add('gracepress-dark-active');}else{h.classList.remove('gracepress-dark-active');}document.querySelectorAll('.gracepress-dark-toggle-trigger, .gracepress-dark-menu-trigger a').forEach(t=>{const l=t.getAttribute('data-light')||'🌙',d=t.getAttribute('data-dark')||'☀️',c=(s==='enabled')?d:l,i=t.querySelector('.gracepress-icon-wrapper');if(i)i.innerHTML=c;const k=t.querySelector('.gracepress-pill-knob');if(k)k.innerHTML=c;});}a(h.classList.contains('gracepress-dark-active')?'enabled':'disabled');function tgl(){if(busy)return;busy=true;const n=h.classList.contains('gracepress-dark-active')?'disabled':'enabled';localStorage.setItem('gracepressDarkMode',n);veil(n,function(){a(n);});}document.body.addEventListener('click',function(e){const t=e.target.closest('.gracepress-dark-toggle-trigger, .gracepress-dark-menu-trigger a');if(t){e.preventDefault();tgl();}});if($kbd){document.addEventListener('keydown',function(e){if(e.ctrlKey&&e.altKey&&(e.key==='d'||e.key==='D')){e.preventDefault();tgl();}});}});</script>";
}
add_shortcode('gracepress_dark_toggle',function($a){$a=shortcode_atts(['style'=>''],is_array($a)?$a:[]);return gp_darkmode_btn(false,$a['style']);});
add_action('admin_bar_menu', function($wp_admin_bar) {
if (!is_user_logged_in() || !is_admin_bar_showing()) return;
$wp_admin_bar->add_node([
'id' => 'gracepress-dark-admin-toggle',
'title' => '<span class="ab-icon dashicons dashicons-lightbulb"></span><span class="ab-label">Dark Mode</span>',
'href' => '#',
'meta' => [
'class' => 'gracepress-dark-menu-trigger',
'title' => 'Toggle GracePress dark mode',
],
]);
}, 95);
add_filter('wp_nav_menu_items',function($i,$a){static $d=false;if(get_option('gracepress_dark_menu_integration','0')==='1'&&!$d){$ic=gp_darkmode_icons();$i.="<li class='menu-item'><a href='#' class='gracepress-dark-menu-trigger' data-light='{$ic['l']}' data-dark='{$ic['d']}'>Theme</a></li>";$d=true;}return $i;},10,2);
// ADMIN UI RESTORATION
function gp_darkmode_admin_page(){
if(!current_user_can('manage_options'))return;
$post_url = esc_url(admin_url('admin.php?page=gracepress-dark-mode'));
if(isset($_POST['gp_dm_reset_filters']) && isset($_POST['_gp_dm_nonce']) && wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['_gp_dm_nonce'])), 'gp_dm_save_action')){
update_option('gp_dm_brightness', 95);
update_option('gp_dm_contrast', 90);
update_option('gp_dm_dim_level', 85);
gp_darkmode_log('Dark Mode engine reset visual filters to factory defaults.','filters_reset',['brightness'=>95,'contrast'=>90,'media_dim'=>85]);
echo '<div class="notice notice-info is-dismissible" style="border-left-color:#64748b;"><p>Visual filters instantly restored to factory default levels (95/90/85).</p></div>';
} elseif(isset($_POST['gp_dm_save']) && isset($_POST['_gp_dm_nonce']) && wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['_gp_dm_nonce'])), 'gp_dm_save_action')){
foreach(['gracepress_dark_default_state','gracepress_dark_icon_style','gracepress_dark_button_size','gracepress_dark_button_position','gracepress_dark_transition_speed','gracepress_dark_exclusions','gracepress_dark_exclude_pages'] as $k) if(isset($_POST[$k])) update_option($k,sanitize_text_field(wp_unslash($_POST[$k])));
foreach(['gracepress_dark_frontend_enable','gracepress_dark_pulse_effect','gracepress_dark_menu_integration','gracepress_dark_admin_enable'] as $k) update_option($k,isset($_POST[$k])?'1':'0');
update_option('gp_dm_kbd',isset($_POST['gp_dm_kbd'])?1:0);
update_option('gp_dm_brightness',isset($_POST['gp_dm_brightness'])?absint(wp_unslash($_POST['gp_dm_brightness'])):95);
update_option('gp_dm_contrast',isset($_POST['gp_dm_contrast'])?absint(wp_unslash($_POST['gp_dm_contrast'])):90);
update_option('gp_dm_dim_level',isset($_POST['gp_dm_dim_level'])?absint(wp_unslash($_POST['gp_dm_dim_level'])):85);
update_option('gp_dm_veil_ms',max(0,min(800,absint($_POST['gp_dm_veil_ms'] ?? 160))));
$posted_veil_effect=sanitize_key($_POST['gp_dm_veil_effect'] ?? 'fade');
if(!in_array($posted_veil_effect,['fade','wipe-right','wipe-down','iris','zoom'],true))$posted_veil_effect='fade';
update_option('gp_dm_veil_effect',$posted_veil_effect);
if(isset($_POST['gp_dm_css'])) update_option('gp_dm_css',sanitize_textarea_field(wp_unslash($_POST['gp_dm_css'])));
gp_darkmode_log('Dark Mode configuration updated successfully.','settings_saved',[
'default_state'=>get_option('gracepress_dark_default_state','light'),
'frontend_enabled'=>get_option('gracepress_dark_frontend_enable','1')==='1',
'admin_enabled'=>get_option('gracepress_dark_admin_enable','0')==='1',
'menu_integration'=>get_option('gracepress_dark_menu_integration','0')==='1',
'keyboard_shortcut'=>get_option('gp_dm_kbd',1)==1,
'brightness'=>absint(get_option('gp_dm_brightness',95)),
'contrast'=>absint(get_option('gp_dm_contrast',90)),
'media_dim'=>absint(get_option('gp_dm_dim_level',85)),
'veil_ms'=>absint(get_option('gp_dm_veil_ms',160)),
'veil_effect'=>sanitize_key(get_option('gp_dm_veil_effect','fade')),
]);
echo '<div class="notice notice-success is-dismissible"><p>Dark Mode configurations securely locked in.</p></div>';
}
$ds=get_option('gracepress_dark_default_state','light');$ic=get_option('gracepress_dark_icon_style','classic');$sz=get_option('gracepress_dark_button_size','normal');$ps=get_option('gracepress_dark_button_position','bottom-right');$sp=get_option('gracepress_dark_transition_speed','0.3s');$ex=get_option('gracepress_dark_exclusions','');$exp=get_option('gracepress_dark_exclude_pages','');
$fe=get_option('gracepress_dark_frontend_enable','1');$pl=get_option('gracepress_dark_pulse_effect','0');$mi=get_option('gracepress_dark_menu_integration','0');$ad=get_option('gracepress_dark_admin_enable','0');$kbd=get_option('gp_dm_kbd',1);$cus=get_option('gp_dm_css','');
$br=get_option('gp_dm_brightness',95);
$ct=get_option('gp_dm_contrast',90);
$dim=get_option('gp_dm_dim_level',85);
$veil_ms=max(0,min(800,absint(get_option('gp_dm_veil_ms',160))));
$veil_effect=sanitize_key(get_option('gp_dm_veil_effect','fade'));
if(!in_array($veil_effect,['fade','wipe-right','wipe-down','iris','zoom'],true))$veil_effect='fade';
$admin_sunrise_url=plugin_dir_url(__FILE__).'assets/images/admin-sunrise.png';
?>
<style>
.gp-admin-wrap{max-width:1180px;margin:18px 20px 20px 0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;color:#334155}.gp-admin-wrap *{box-sizing:border-box}
.gp-header{background:linear-gradient(100deg,rgba(8,18,35,.9) 0%,rgba(15,36,58,.72) 58%,rgba(76,47,24,.5) 100%),url('<?php echo esc_url($admin_sunrise_url)?>') center 58%/cover;color:#fff;padding:26px 30px;border-radius:10px;margin-bottom:18px;border-left:6px solid #0ea5e9;box-shadow:0 7px 18px rgba(15,23,42,.16)}
.gp-header h1{color:#fff;margin:0 0 6px;font-size:27px;font-weight:800;letter-spacing:-.35px;text-shadow:0 2px 4px rgba(0,0,0,.55)}.gp-header p{margin:0;font-size:14px;opacity:.96;line-height:1.55;max-width:860px;text-shadow:0 1px 3px rgba(0,0,0,.55)}
.gp-layout-grid{display:grid;grid-template-columns:1fr 1fr;gap:18px;align-items:start}.gp-card{background:#fff;padding:20px;border-radius:9px;border:1px solid #dbe3ec;box-shadow:0 2px 8px rgba(15,23,42,.035);margin-bottom:18px}.gp-card h3{margin:0 0 16px;padding:0 0 11px;border-bottom:1px solid #edf1f5;font-size:17px;color:#0f172a;display:flex;align-items:center;gap:8px;font-weight:700}
.gp-f{display:flex;flex-direction:column;gap:5px;margin-bottom:14px}.gp-f label{font-weight:700;font-size:13px;color:#0f172a}.gp-f input[type="text"],.gp-f input[type="number"],.gp-f select{width:min(100%,430px);min-height:34px;padding:4px 8px;border:1px solid #b8c4d1;border-radius:5px;font-size:13px;box-shadow:inset 0 1px 2px rgba(15,23,42,.025)}.gp-f textarea{width:100%;padding:8px;border:1px solid #b8c4d1;border-radius:5px;font-size:13px;box-shadow:inset 0 1px 2px rgba(15,23,42,.025)}.gp-f input[type="range"]{width:100%;margin:2px 0}.gp-f small{line-height:1.4}
.gp-cg{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:9px;margin-bottom:14px}.gp-cl{display:flex;align-items:center;gap:7px;background:#f8fafc;padding:9px 10px;border-radius:5px;border:1px solid #dbe3ec;cursor:pointer;font-weight:600;font-size:13px}.gp-btn-primary{background:#0ea5e9;color:#fff;border:1px solid #0284c7;padding:9px 18px;font-size:14px;font-weight:700;border-radius:5px;cursor:pointer;display:inline-block;text-decoration:none;transition:.2s}.gp-btn-primary:hover{background:#0284c7;color:#fff;transform:translateY(-1px);box-shadow:0 3px 5px rgba(14,165,233,.2)}.gp-btn-reset{background:#64748b;color:#fff;border:1px solid #526173;padding:9px 16px;font-size:14px;font-weight:700;border-radius:5px;cursor:pointer;display:inline-block;text-decoration:none;transition:.2s;margin-left:8px}.gp-btn-reset:hover{background:#475569;color:#fff;transform:translateY(-1px);box-shadow:0 3px 5px rgba(100,116,139,.2)}.gp-footer{text-align:center;margin-top:24px;padding:24px 20px 8px;border-top:1px solid #e2e8f0}code{background:#f1f5f9;padding:3px 6px;border-radius:4px;font-family:monospace;color:#b4236c;font-size:12px;font-weight:700;border:1px solid #e2e8f0}
.gp-live-preview { width:100%; padding:18px; background:#fff; color:#334155; border:1px dashed #cbd5e1; border-radius:7px; margin-top:12px; transition: 0.3s; }
.gp-live-preview.active { filter: invert(100%) hue-rotate(180deg) brightness(var(--prev-br, 95%)) contrast(var(--prev-ct, 90%)) !important; background:#fff !important; color:#334155 !important; }
@media(max-width:980px){.gp-layout-grid{grid-template-columns:1fr}.gp-admin-wrap{margin-right:12px}.gp-cg{grid-template-columns:1fr 1fr}}
@media(max-width:600px){.gp-header{padding:22px 20px}.gp-card{padding:17px}.gp-cg{grid-template-columns:1fr}.gp-btn-reset{margin:8px 0 0}}
</style>
<div class="gp-admin-wrap"><header class="gp-header"><h1>🌓 Dark Mode Engine</h1><p>Version <?php echo esc_html(GP_DARKMODE_VERSION)?>. Features absolute Anti-FOUC synchronization, hardware-accelerated CSS inversion, precise filter tuning, variable media correction, configurable two-phase transitions, and optional local OmniLog integration.</p></header>
<form method="post" action="<?php echo esc_url($post_url); ?>"><?php wp_nonce_field('gp_dm_save_action', '_gp_dm_nonce'); ?>
<div class="gp-layout-grid">
<div>
<div class="gp-card"><h3><span class="dashicons dashicons-visibility" style="color:#0ea5e9;"></span> 1. Core Behavior</h3>
<div class="gp-f"><label>Default State (First Visit)</label><select name="gracepress_dark_default_state"><option value="light" <?php echo selected('light',$ds)?>>Light Mode (Standard)</option><option value="dark" <?php echo selected('dark',$ds)?>>Dark Mode (Always)</option><option value="os" <?php echo selected('os',$ds)?>>Follow OS Preference (Recommended)</option><option value="auto" <?php echo selected('auto',$ds)?>>Time Based (Sunset to Sunrise)</option></select></div>
<div class="gp-f"><label>Filter Brightness (Current: <span id="br_val"><?php echo esc_html($br)?></span>%)</label><input type="range" id="inp_br" name="gp_dm_brightness" min="0" max="150" value="<?php echo esc_attr($br)?>" oninput="upd_prev()"></div>
<div class="gp-f"><label>Filter Contrast (Current: <span id="ct_val"><?php echo esc_html($ct)?></span>%)</label><input type="range" id="inp_ct" name="gp_dm_contrast" min="0" max="150" value="<?php echo esc_attr($ct)?>" oninput="upd_prev()"></div>
<div class="gp-f"><label>Media Dimming Level (Images/Videos opacity: <?php echo esc_html($dim)?>%)</label><input type="range" name="gp_dm_dim_level" min="0" max="100" value="<?php echo esc_attr($dim)?>"></div>
<div class="gp-cg"><label class="gp-cl"><input type="checkbox" name="gp_dm_kbd" value="1" <?php echo checked($kbd,1)?>> Enable Ctrl+Alt+D Shortcut</label></div>
</div>
<div class="gp-card"><h3><span class="dashicons dashicons-art" style="color:#0ea5e9;"></span> 2. Visual Aesthetics</h3>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:15px;">
<div class="gp-f"><label>Toggle Style</label><select name="gracepress_dark_icon_style"><option value="classic" <?php echo selected('classic',$ic)?>>Classic Emoji (🌙/☀️)</option><option value="minimal" <?php echo selected('minimal',$ic)?>>Minimal Dots (⚫/⚪)</option><option value="bulbs" <?php echo selected('bulbs',$ic)?>>Bulbs (🌑/💡)</option><option value="text" <?php echo selected('text',$ic)?>>Text (DARK/LIGHT)</option><option value="switch" <?php echo selected('switch',$ic)?>>Pill Switch</option></select></div>
<div class="gp-f"><label>Button Size</label><select name="gracepress_dark_button_size"><option value="small" <?php echo selected('small',$sz)?>>Small</option><option value="normal" <?php echo selected('normal',$sz)?>>Normal</option><option value="large" <?php echo selected('large',$sz)?>>Large</option></select></div>
</div>
<div class="gp-f"><label>Floating Position</label><select name="gracepress_dark_button_position"><option value="bottom-right" <?php echo selected('bottom-right',$ps)?>>Bottom Right</option><option value="bottom-left" <?php echo selected('bottom-left',$ps)?>>Bottom Left</option><option value="top-right" <?php echo selected('top-right',$ps)?>>Top Right</option><option value="top-left" <?php echo selected('top-left',$ps)?>>Top Left</option></select></div>
<div class="gp-f"><label>Transition Speed (CSS Time)</label><input type="text" name="gracepress_dark_transition_speed" value="<?php echo esc_attr($sp)?>" placeholder="e.g. 0.3s or 500ms"></div>
<div class="gp-f"><label>Mode Switch Transition</label><select name="gp_dm_veil_effect"><option value="fade" <?php echo selected('fade',$veil_effect)?>>Fade</option><option value="wipe-right" <?php echo selected('wipe-right',$veil_effect)?>>Side Wipe</option><option value="wipe-down" <?php echo selected('wipe-down',$veil_effect)?>>Vertical Wipe</option><option value="iris" <?php echo selected('iris',$veil_effect)?>>Iris</option><option value="zoom" <?php echo selected('zoom',$veil_effect)?>>Zoom Fade</option></select></div>
<div class="gp-f"><label>Mode Switch Duration (ms)</label><input type="number" name="gp_dm_veil_ms" min="0" max="800" step="10" value="<?php echo esc_attr($veil_ms)?>"><small style="color:#64748b;">0 disables the transition veil. The duration is split into a cover phase and a reveal phase, so 220ms feels like a crisp two-way transition.</small></div>
</div>
</div>
<div>
<div class="gp-card"><h3><span class="dashicons dashicons-admin-settings" style="color:#0ea5e9;"></span> 3. Integration & Rendering</h3>
<div class="gp-cg">
<label class="gp-cl"><input type="checkbox" name="gracepress_dark_frontend_enable" value="1" <?php echo checked('1',$fe)?>> Auto-Float on Frontend</label>
<label class="gp-cl"><input type="checkbox" name="gracepress_dark_admin_enable" value="1" <?php echo checked('1',$ad)?>> Enable in WP Admin</label>
<label class="gp-cl"><input type="checkbox" name="gracepress_dark_pulse_effect" value="1" <?php echo checked('1',$pl)?>> Floating Pulse Effect</label>
<label class="gp-cl"><input type="checkbox" name="gracepress_dark_menu_integration" value="1" <?php echo checked('1',$mi)?>> Auto-Inject into Menus</label>
</div>
<div style="background:#f0fdf4;border:1px solid #bbf7d0;padding:15px;border-radius:6px;font-size:13px;color:#166534;line-height:1.5;">
<strong>Manual Shortcode:</strong> Use <code>[gracepress_dark_toggle]</code> to place the button exactly where you want it. You can also override the style locally: <code>[gracepress_dark_toggle style="switch"]</code>
</div>
<div class="gp-live-preview active" id="dm_preview">
<h4 style="margin-top:0; color:#0f172a;">Matrix Filter Preview Hub</h4>
<p style="margin-bottom:0; font-size:13px;">Drag the sliders on the left to real-time sync and balance text opacity variables before saving configurations.</p>
</div>
<div style="text-align:right; margin-top:10px;"><button type="button" class="gp-btn-sm" style="background:#475569; color:#fff; border:none; padding:6px 12px; border-radius:4px; cursor:pointer; font-size:11px;" onclick="localStorage.removeItem('gracepressDarkMode');alert('Cookie memory cleared. Default parameters will trigger on next visit.');">Wipe Browser LocalStorage Cache</button></div>
</div>
<div class="gp-card" style="border-top-color:#f59e0b;"><h3><span class="dashicons dashicons-editor-code" style="color:#0ea5e9;"></span> 4. Advanced Customization</h3>
<div class="gp-f"><label>Exclude Specific Pages (Comma-separated Page IDs)</label><input type="text" name="gracepress_dark_exclude_pages" value="<?php echo esc_attr($exp)?>" placeholder="e.g. 12, 45, 102">
<small style="color:#64748b;">Completely disables the Dark Mode engine on these specific Post/Page IDs.</small></div>
<div class="gp-f"><label>Exclude Specific Elements (Comma-separated CSS Classes/IDs)</label><input type="text" name="gracepress_dark_exclusions" value="<?php echo esc_attr($ex)?>" placeholder=".no-dark, #header-logo, .elementor-image">
<small style="color:#64748b;">Protects specific HTML elements from the inversion filter.</small></div>
<div class="gp-f"><label>Custom Dark CSS Overrides</label><textarea name="gp_dm_css" rows="4" style="font-family:monospace;" placeholder="html.gracepress-dark-active .my-custom-box { background: #333; }"><?php echo esc_textarea($cus)?></textarea></div>
</div>
<div style="text-align:center; padding-top:10px;">
<button type="submit" name="gp_dm_save" class="gp-btn-primary"><span class="dashicons dashicons-lock" style="margin-top:3px;"></span> Lock In Settings</button>
<button type="submit" name="gp_dm_reset_filters" class="gp-btn-reset" onclick="return confirm('Are you sure you want to restore the visual filters to their default factory levels?');"><span class="dashicons dashicons-image-rotate" style="margin-top:3px;"></span> Factory Reset Filters</button>
</div>
</div>
</div>
</form>
<script>
function upd_prev() {
let br = document.getElementById('inp_br').value;
let ct = document.getElementById('inp_ct').value;
document.getElementById('br_val').innerText = br;
document.getElementById('ct_val').innerText = ct;
let box = document.getElementById('dm_preview');
box.style.setProperty('--prev-br', br + '%');
box.style.setProperty('--prev-ct', ct + '%');
}
setTimeout(upd_prev, 150);
</script>
<?php
$gp_footer_support = 'jason [at] christp2p [dot] com';
$gp_footer_donate_url = apply_filters('gracepress_footer_donate_url', 'https://christp2p.com/gracepress/donate/');
$gp_footer_jesus_url = apply_filters('gracepress_footer_about_jesus_url', 'https://christp2p.com/about-jesus-christ/');
$gp_footer_support_url = apply_filters('gracepress_footer_support_url', 'https://christp2p.com/gracepress/support/');
?>
<footer class="gp-footer"><p style="font-style:italic;font-size:16px;color:#1e293b;margin-bottom:15px;">"The light shines in the darkness, and the darkness has not overcome it." — John 1:5</p><div style="display:flex;justify-content:center;gap:14px;flex-wrap:wrap;margin-top:15px;font-weight:bold;color:#0ea5e9;"><a href="<?php echo esc_url($gp_footer_donate_url); ?>" style="color:inherit;text-decoration:none;">Donate</a><a href="<?php echo esc_url($gp_footer_jesus_url); ?>" style="color:inherit;text-decoration:none;">About Jesus Christ</a><a href="<?php echo esc_url($gp_footer_support_url); ?>" style="color:inherit;text-decoration:none;">Support</a></div><div style="margin-top:12px;font-weight:bold;color:#0ea5e9;">Support contact: <?php echo esc_html($gp_footer_support); ?></div><div style="margin-top:30px;font-size:13px;opacity:0.7;font-weight:700;text-transform:uppercase;letter-spacing:1px;color:#0f172a;">All Glory to Jesus Christ<br><span style="font-weight:500;text-transform:none;letter-spacing:0;display:block;margin-top:5px;">Engineered by Christ IT &bull; &copy; <?php echo esc_html(wp_date('Y')); ?></span></div></footer></div>
<?php
}
add_filter('plugin_action_links_'.plugin_basename(__FILE__),function($l){array_unshift($l,'<a href="'.(class_exists('GracePress_Central_Hub')?admin_url('admin.php?page=gracepress-dark-mode'):admin_url('options-general.php?page=gracepress-dark-mode')).'" style="font-weight:bold;color:#0ea5e9;">Configure</a>');return $l;});
+65
View File
@@ -0,0 +1,65 @@
=== Dark Mode by GracePress ===
Contributors: gracepress
Tags: dark mode, accessibility, night mode, admin dark mode, color scheme
Requires at least: 6.0
Tested up to: 7.1
Requires PHP: 7.4
Stable tag: 4.8.18
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
A complete dark mode engine with anti-flash loading, visual tuning, transitions, flexible controls, and administrator support.
== Description ==
Dark Mode by GracePress provides a complete control panel for configuring dark mode on the public site and in WordPress administration.
Features include:
* Device-theme, scheduled, light, or dark first-visit behavior.
* Five transition treatments: fade, horizontal wipe, vertical wipe, iris, and zoom.
* Brightness, contrast, and media controls.
* Five toggle styles with three sizes and four floating positions.
* Floating, menu, shortcode, administrator-bar, and keyboard controls.
* Independent public-site and WordPress administration enablement.
* Page and selector exclusions for compatibility.
* Custom dark-mode CSS overrides.
* Compatibility corrections for images, videos, fullscreen playback, and common WordPress media surfaces.
The plugin does not collect telemetry and does not depend on a remote service. If GracePress Central Hub or OmniLog is installed, Dark Mode can integrate with those local plugins; neither is required.
== Installation ==
1. Upload the plugin directory to `/wp-content/plugins/`, or install the ZIP through Plugins > Add New.
2. Activate Dark Mode by GracePress.
3. Open Settings > Dark Mode.
4. Configure the public-site and administrator behavior, then save.
Use `[gracepress_dark_toggle]` to place a toggle in content. The optional `style` attribute accepts `classic`, `minimal`, `bulbs`, `text`, or `switch`.
== Frequently Asked Questions ==
= Does it follow the visitor's device theme? =
Yes. Choose Follow device theme as the first-visit behavior.
= Does it work in WordPress administration? =
Yes. Administrator dark mode can be enabled independently, with a toolbar toggle available to signed-in users.
= Does it send data to GracePress? =
No. This public plugin contains no telemetry or private update connection.
= Does it require another GracePress plugin? =
No. Dark Mode works independently. It can use local GracePress Central Hub routing and OmniLog events when those plugins are already installed and active.
== Changelog ==
* Continued preparing the mature GracePress Dark Mode engine for public WordPress.org distribution while retaining version 4.8.18 during development.
* Preserved all established runtime behavior, settings, option keys, controls, transitions, media corrections, and local integrations.
* Removed anonymous ecosystem pings and the private external update engine.
* Reorganized the complete settings interface into a denser responsive layout without removing controls.
* Replaced the remote administration background with an original bundled sunrise image.
* Corrected CSS-backed GracePress Builder hero artwork in dark mode while preserving original color, contrast, and opacity.