Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 39 additions & 1 deletion assets/css/magicauth-admin.css
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,44 @@ body.admin-bar .magicauth-admin .magicauth-topbar__bar { top: 32px; }
line-height: 1.55;
}

/* <details>/<summary> disclosure widget. <summary> is keyboard-focusable
natively; no JS. Native marker hidden so we can render our own chevron. */
.magicauth-admin details.magicauth-block > summary {
list-style: none;
cursor: pointer;
user-select: none;
position: relative;
padding-right: 32px;
}

.magicauth-admin details.magicauth-block > summary::-webkit-details-marker { display: none; }

.magicauth-admin details.magicauth-block > summary::after {
content: "";
position: absolute;
top: 0;
bottom: 0;
right: 8px;
margin: auto 0;
width: 9px;
height: 9px;
border-right: 2px solid var(--tx-muted);
border-bottom: 2px solid var(--tx-muted);
transform: rotate(45deg);
transform-origin: center;
transition: transform 0.15s ease;
}

.magicauth-admin details.magicauth-block[open] > summary::after {
transform: rotate(-135deg);
}

.magicauth-admin details.magicauth-block > summary:focus-visible {
outline: 2px solid var(--ettic-accent, #2271b1);
outline-offset: 4px;
border-radius: 4px;
}

/* Cards. Namespaced to avoid colliding with WP core `.card` (caps at 520px). */
.magicauth-admin .magicauth-card {
background: var(--ettic-surface);
Expand Down Expand Up @@ -833,7 +871,7 @@ body.admin-bar .magicauth-admin .magicauth-topbar__bar { top: 32px; }
align-items: center;
justify-content: space-between;
gap: 16px;
padding: 14px 8px;
padding: 14px;
position: relative;
}

Expand Down
45 changes: 44 additions & 1 deletion assets/css/magicauth.css
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
--magicauth-color-divider: #e9ecef;
--magicauth-color-error: #b32d2e;
--magicauth-color-focus-ring: var(--magicauth-color-primary);
--magicauth-color-link: var(--magicauth-color-primary);
--magicauth-card-max-width: 480px;
--magicauth-card-padding: 56px 48px;
--magicauth-card-padding-mobile: 32px 24px;
Expand Down Expand Up @@ -325,7 +326,7 @@
}

.magicauth-link {
color: var(--magicauth-color-primary);
color: var(--magicauth-color-link, var(--magicauth-color-primary));
text-decoration: underline;
text-underline-offset: 2px;
}
Expand Down Expand Up @@ -446,3 +447,45 @@
outline: 2px solid CanvasText;
}
}

/* Dark mode — explicit. Body-class specificity (0,1,1) beats :root (0,0,1),
so the shell-vars block can still set per-instance brand_color / link_color /
font_stack without being overridden. Curated values, not exposed to admin
pickers.
!!! SYNC-LOCK !!! --magicauth-color-surface (#181c22) MUST equal the PHP
constant MagicAuth\Admin\Settings::DARK_SURFACE_HEX
(includes/Admin/Settings.php:~42). The PHP constant feeds the brand-color
contrast check; the CSS variable paints the card. If either changes without
the other, dark-mode contrast warnings will lie. Value also duplicated at
line ~482 below (auto-mode @media block) — update all three together. */
body.magicauth-mode-dark {
--magicauth-color-page: #0e1116;
--magicauth-color-surface: #181c22; /* SYNC with Settings::DARK_SURFACE_HEX */
--magicauth-color-code-bg: #202832;
--magicauth-color-text: #eef0f3;
--magicauth-color-text-muted: #9aa3ad;
--magicauth-color-border: #2a313a;
--magicauth-color-border-strong: #3a424c;
--magicauth-color-divider: #262d36;
--magicauth-color-error: #ff6b6b;
}

/* Dark mode — auto. Only kicks in when admin chose color_mode = auto AND
the visitor's browser reports a dark preference.
!!! SYNC-LOCK !!! --magicauth-color-surface (#181c22) MUST equal the PHP
constant MagicAuth\Admin\Settings::DARK_SURFACE_HEX
(includes/Admin/Settings.php:~42). See full note above the explicit-dark
block (~line 451). Three locations to update in lockstep. */
@media (prefers-color-scheme: dark) {
body.magicauth-mode-auto {
--magicauth-color-page: #0e1116;
--magicauth-color-surface: #181c22; /* SYNC with Settings::DARK_SURFACE_HEX */
--magicauth-color-code-bg: #202832;
--magicauth-color-text: #eef0f3;
--magicauth-color-text-muted: #9aa3ad;
--magicauth-color-border: #2a313a;
--magicauth-color-border-strong: #3a424c;
--magicauth-color-divider: #262d36;
--magicauth-color-error: #ff6b6b;
}
}
49 changes: 49 additions & 0 deletions assets/js/magicauth-admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
function init() {
initMediaPickers();
initColorPickers();
initColorFollowers();
initRowDirtyMarks();
initDirtyTracking();
initCharCounters();
Expand Down Expand Up @@ -107,6 +108,54 @@
} );
}

// Follower color pickers: when the text input is blank, the swatch mirrors
// a source picker (e.g. link_color follows brand_color). Typing a hex or
// picking a swatch color writes to the text input, which disconnects.
function initColorFollowers() {
var HEX_RE = /^#?[0-9a-fA-F]{6}$/;
var normalize = function ( v ) { return v.charAt( 0 ) === '#' ? v : '#' + v; };

document.querySelectorAll( '.magicauth-admin .magicauth-color[data-magicauth-color-follows]' ).forEach( function ( follower ) {
var sourceKey = follower.getAttribute( 'data-magicauth-color-follows' );
if ( ! sourceKey ) {
return;
}
var sourceText = document.querySelector( 'input[name="magicauth_settings[' + sourceKey + ']"]' );
var swatch = follower.querySelector( 'input[type="color"]' );
var text = follower.querySelector( 'input[type="text"]' );
if ( ! sourceText || ! swatch || ! text ) {
return;
}

function isConnected() { return '' === text.value.trim(); }
function mirrorFromSource() {
var v = sourceText.value.trim();
if ( HEX_RE.test( v ) ) {
swatch.value = normalize( v );
}
}

// Cleared text → snap swatch back to source.
text.addEventListener( 'input', function () {
if ( isConnected() ) {
mirrorFromSource();
}
} );

// Source moved → mirror only while connected.
sourceText.addEventListener( 'input', function () {
if ( isConnected() ) {
mirrorFromSource();
}
} );

// Initial render: if follower is blank, mirror immediately.
if ( isConnected() ) {
mirrorFromSource();
}
} );
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

// Per-row dirty mark — auto-injected, opacity toggled via .is-dirty
function initRowDirtyMarks() {
document.querySelectorAll( '.magicauth-admin .magicauth-row' ).forEach( function ( row ) {
Expand Down
Loading
Loading