Skip to content

Commit 0a95280

Browse files
authored
feat: implement dark/light mode theme selection and admin configuration section (#131)
1 parent 11d3c45 commit 0a95280

8 files changed

Lines changed: 186 additions & 21 deletions

File tree

src/Block/Inspector.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,16 @@ public function getJsUrl(): string
8181
return $this->getViewFileUrl('OpenForgeProject_MageForge::js/inspector.js');
8282
}
8383

84+
/**
85+
* Get configured theme
86+
*
87+
* @return string
88+
*/
89+
public function getTheme(): string
90+
{
91+
return (string) $this->scopeConfig->getValue('mageforge/inspector/theme') ?: 'dark';
92+
}
93+
8494
/**
8595
* Render block HTML
8696
*
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace OpenForgeProject\MageForge\Model\Config\Source;
6+
7+
use Magento\Framework\Data\OptionSourceInterface;
8+
9+
class InspectorTheme implements OptionSourceInterface
10+
{
11+
/**
12+
* @return array<int, array<string, string>>
13+
*/
14+
public function toOptionArray(): array
15+
{
16+
return [
17+
['value' => 'dark', 'label' => (string) __('Dark')],
18+
['value' => 'light', 'label' => (string) __('Light')],
19+
['value' => 'auto', 'label' => (string) __('Auto (System Preference)')],
20+
];
21+
}
22+
}

src/etc/acl.xml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?xml version="1.0"?>
2+
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Acl/etc/acl.xsd">
3+
<acl>
4+
<resources>
5+
<resource id="Magento_Backend::admin">
6+
<resource id="Magento_Backend::stores">
7+
<resource id="Magento_Backend::stores_settings">
8+
<resource id="Magento_Config::config">
9+
<resource id="OpenForgeProject_MageForge::config_inspector" title="MageForge Inspector" sortOrder="50" />
10+
</resource>
11+
</resource>
12+
</resource>
13+
</resource>
14+
</resources>
15+
</acl>
16+
</config>

src/etc/adminhtml/system.xml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?xml version="1.0"?>
2+
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
3+
<system>
4+
<tab id="mageforge" translate="label" sortOrder="200">
5+
<label>MageForge</label>
6+
</tab>
7+
<section id="mageforge_inspector" translate="label" type="text" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
8+
<label>Inspector</label>
9+
<tab>mageforge</tab>
10+
<resource>OpenForgeProject_MageForge::config_inspector</resource>
11+
<group id="general" translate="label" type="text" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
12+
<label>General Settings</label>
13+
<field id="enabled" translate="label" type="select" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
14+
<label>Enabled</label>
15+
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
16+
<config_path>dev/mageforge_inspector/enabled</config_path>
17+
</field>
18+
<field id="theme" translate="label" type="select" sortOrder="20" showInDefault="1" showInWebsite="1" showInStore="1">
19+
<label>Theme</label>
20+
<source_model>OpenForgeProject\MageForge\Model\Config\Source\InspectorTheme</source_model>
21+
<config_path>mageforge/inspector/theme</config_path>
22+
<comment>Choose between Dark, Light, or Auto (System Preference) theme.</comment>
23+
</field>
24+
</group>
25+
</section>
26+
</system>
27+
</config>

src/etc/config.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,10 @@
77
<enabled>0</enabled>
88
</mageforge_inspector>
99
</dev>
10+
<mageforge>
11+
<inspector>
12+
<theme>dark</theme>
13+
</inspector>
14+
</mageforge>
1015
</default>
1116
</config>

src/view/frontend/templates/inspector.phtml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@
4444
<script defer src="<?= $escaper->escapeUrl($block->getJsUrl()) ?>"></script>
4545

4646
<!-- Inspector Component Wrapper -->
47-
<div class="mageforge-inspector" x-data="mageforgeInspector"></div>
47+
<div class="mageforge-inspector"
48+
x-data="mageforgeInspector"
49+
data-theme="<?= $escaper->escapeHtmlAttr($block->getTheme()) ?>"></div>
4850

4951

src/view/frontend/web/css/inspector.css

Lines changed: 79 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@
3333
--mageforge-bg-dark: rgba(15, 23, 42, 0.98);
3434
--mageforge-bg-dark-alt: rgba(30, 41, 59, 0.98);
3535
--mageforge-border-color: rgba(148, 163, 184, 0.15);
36+
37+
/* Glass/Overlay Variables */
38+
--mageforge-surface-glass: rgba(255, 255, 255, 0.05);
39+
--mageforge-surface-glass-hover: rgba(255, 255, 255, 0.08); /* slightly lighter for hover */
40+
--mageforge-border-glass: rgba(255, 255, 255, 0.1);
41+
--mageforge-shadow-glow: rgba(255, 255, 255, 0.05);
3642
}
3743

3844
.mageforge-inspector {
@@ -157,8 +163,8 @@
157163
right: 12px;
158164
width: 28px;
159165
height: 28px;
160-
background: rgba(255, 255, 255, 0.05);
161-
border: 1px solid rgba(255, 255, 255, 0.1);
166+
background: var(--mageforge-surface-glass);
167+
border: 1px solid var(--mageforge-border-glass);
162168
border-radius: 6px;
163169
color: var(--mageforge-color-slate-400);
164170
font-size: 16px;
@@ -502,18 +508,18 @@
502508
display: inline-block;
503509
transition: all 0.2s ease;
504510
padding: 6px 10px;
505-
background: rgba(255, 255, 255, 0.03);
511+
background: var(--mageforge-surface-glass); /* ~3% opacity */
506512
border-radius: 6px;
507-
border: 1px solid rgba(255, 255, 255, 0.08);
513+
border: 1px solid var(--mageforge-border-glass); /* ~8% opacity */
508514
width: 100%;
509515
box-sizing: border-box;
510516
font-family: 'SF Mono', 'Monaco', 'Consolas', monospace;
511517
pointer-events: auto;
512518
}
513519

514520
.mageforge-info-value:hover {
515-
background: rgba(255, 255, 255, 0.06);
516-
border-color: rgba(255, 255, 255, 0.15);
521+
background: var(--mageforge-surface-glass-hover);
522+
border-color: var(--mageforge-border-color); /* fallback or stronger border */
517523
transform: translateY(-1px);
518524
}
519525

@@ -589,7 +595,7 @@
589595
}
590596

591597
.mageforge-code-tag {
592-
background: rgba(255,255,255,0.05);
598+
background: var(--mageforge-surface-glass);
593599
padding: 2px 6px;
594600
border-radius: 4px;
595601
font-family: monospace;
@@ -671,3 +677,69 @@
671677
from { stroke-dashoffset: 500; }
672678
to { stroke-dashoffset: 0; }
673679
}
680+
681+
/* ============================================================================
682+
Theme Overrides
683+
========================================================================== */
684+
685+
/* Explicit Light Mode */
686+
.mageforge-inspector[data-theme="light"] {
687+
--mageforge-bg-dark: rgba(255, 255, 255, 0.98);
688+
--mageforge-bg-dark-alt: rgba(248, 250, 252, 0.98);
689+
--mageforge-border-color: rgba(0, 0, 0, 0.12);
690+
691+
--mageforge-color-slate-100: #0f172a; /* Slate 900 */
692+
--mageforge-color-slate-200: #1e293b; /* Slate 800 */
693+
--mageforge-color-slate-300: #334155; /* Slate 700 */
694+
--mageforge-color-slate-400: #64748b; /* Slate 500 */
695+
--mageforge-color-slate-500: #94a3b8; /* Slate 400 */
696+
697+
/* Glass Overlays - Inverted for light mode */
698+
--mageforge-surface-glass: rgba(0, 0, 0, 0.05);
699+
--mageforge-surface-glass-hover: rgba(0, 0, 0, 0.08);
700+
--mageforge-border-glass: rgba(0, 0, 0, 0.1);
701+
--mageforge-shadow-glow: rgba(0, 0, 0, 0.05);
702+
}
703+
704+
/* Auto Mode - Light Preference */
705+
@media (prefers-color-scheme: light) {
706+
.mageforge-inspector[data-theme="auto"] {
707+
--mageforge-bg-dark: rgba(255, 255, 255, 0.98);
708+
--mageforge-bg-dark-alt: rgba(248, 250, 252, 0.98);
709+
--mageforge-border-color: rgba(0, 0, 0, 0.12);
710+
711+
--mageforge-color-slate-100: #0f172a;
712+
--mageforge-color-slate-200: #1e293b;
713+
--mageforge-color-slate-300: #334155;
714+
--mageforge-color-slate-400: #64748b;
715+
--mageforge-color-slate-500: #94a3b8;
716+
717+
/* Glass Overlays - Inverted for light mode */
718+
--mageforge-surface-glass: rgba(0, 0, 0, 0.05);
719+
--mageforge-surface-glass-hover: rgba(0, 0, 0, 0.08);
720+
--mageforge-border-glass: rgba(0, 0, 0, 0.1);
721+
--mageforge-shadow-glow: rgba(0, 0, 0, 0.05);
722+
}
723+
}
724+
725+
/* Fix for hardcoded white text in light mode */
726+
.mageforge-inspector[data-theme="light"] .mageforge-text-white {
727+
color: var(--mageforge-color-slate-100);
728+
}
729+
730+
@media (prefers-color-scheme: light) {
731+
.mageforge-inspector[data-theme="auto"] .mageforge-text-white {
732+
color: var(--mageforge-color-slate-100);
733+
}
734+
735+
.mageforge-inspector[data-theme="auto"].mageforge-inspector-float-button,
736+
.mageforge-inspector[data-theme="auto"] .mageforge-inspector-float-button {
737+
color: white; /* Button should stay white */
738+
}
739+
}
740+
741+
.mageforge-inspector[data-theme="light"].mageforge-inspector-float-button,
742+
.mageforge-inspector[data-theme="light"] .mageforge-inspector-float-button {
743+
color: white;
744+
}
745+

src/view/frontend/web/js/inspector.js

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,12 @@ document.addEventListener('alpine:init', () => {
269269
createHighlightBox() {
270270
this.highlightBox = document.createElement('div');
271271
this.highlightBox.className = 'mageforge-inspector mageforge-inspector-highlight';
272+
273+
// Propagate theme from root element to injected body element
274+
if (this.$el && this.$el.hasAttribute('data-theme')) {
275+
this.highlightBox.setAttribute('data-theme', this.$el.getAttribute('data-theme'));
276+
}
277+
272278
this.highlightBox.style.display = 'none';
273279

274280
document.body.appendChild(this.highlightBox);
@@ -280,6 +286,12 @@ document.addEventListener('alpine:init', () => {
280286
createInfoBadge() {
281287
this.infoBadge = document.createElement('div');
282288
this.infoBadge.className = 'mageforge-inspector mageforge-inspector-info-badge';
289+
290+
// Propagate theme from root element to injected body element
291+
if (this.$el && this.$el.hasAttribute('data-theme')) {
292+
this.infoBadge.setAttribute('data-theme', this.$el.getAttribute('data-theme'));
293+
}
294+
283295
this.infoBadge.style.display = 'none';
284296

285297
// Create arrow element
@@ -296,6 +308,12 @@ document.addEventListener('alpine:init', () => {
296308
createFloatingButton() {
297309
this.floatingButton = document.createElement('button');
298310
this.floatingButton.className = 'mageforge-inspector mageforge-inspector-float-button';
311+
312+
// Propagate theme from root element to injected body element
313+
if (this.$el && this.$el.hasAttribute('data-theme')) {
314+
this.floatingButton.setAttribute('data-theme', this.$el.getAttribute('data-theme'));
315+
}
316+
299317
this.floatingButton.type = 'button';
300318
this.floatingButton.title = 'Activate Inspector (Ctrl+Shift+I)';
301319

@@ -304,19 +322,12 @@ document.addEventListener('alpine:init', () => {
304322

305323
// Icon + Text with unique gradient ID
306324
this.floatingButton.innerHTML = `
307-
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" viewBox="0 0 64 64" width="16" height="16" style="flex-shrink: 0;">
308-
<defs>
309-
<linearGradient id="${gradientId}" x1="32" x2="32" y1="36" y2="4" gradientUnits="userSpaceOnUse">
310-
<stop offset="0%" stop-color="#ffc837"/>
311-
<stop offset="50%" stop-color="#ff3d00"/>
312-
<stop offset="100%" stop-color="#7b1fa2"/>
313-
</linearGradient>
314-
</defs>
315-
<path fill="white" d="M56 36H44v-4c0-1.1046-.8954-2-2-2H16c-2.6569 0-5.1046.8954-7 2.4472V36H8c-1.10457 0-2 .8954-2 2v2c0 1.1046.89543 2 2 2h10.6484c1.6969 3.2887 3.5871 6.4797 5.6503 9.5605L22 56H12c-1.1046 0-2 .8954-2 2v2h44v-2c0-1.1046-.8954-2-2-2H42l-2.2987-4.4395c2.0632-3.0808 3.9534-6.2718 5.6503-9.5605H56c1.1046 0 2-.8954 2-2v-2c0-1.1046-.8954-2-2-2" opacity="0.9"/>
316-
<path fill="url(#${gradientId})" d="M32 4S22 18 22 27c0 4.9706 4.4772 9 10 9s10-4.0294 10-9c0-9-10-23-10-23m0 10s-4 6-4 10c0 2.2091 1.7909 4 4 4s4-1.7909 4-4c0-4-4-10-4-10"/>
317-
<circle cx="20" cy="18" r="1.5" fill="#ffc837" opacity="0.8"/>
318-
<circle cx="44" cy="18" r="1.5" fill="#e0b3ff" opacity="0.8"/>
319-
<circle cx="32" cy="10" r="1" fill="#ff3d00" opacity="0.9"/>
325+
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="currentColor" height="20" width="20">
326+
<g stroke-width="0"></g>
327+
<g stroke-linecap="round" stroke-linejoin="round"></g>
328+
<g>
329+
<path fill-rule="evenodd" clip-rule="evenodd" d="M1 3l1-1h12l1 1v6h-1V3H2v8h5v1H2l-1-1V3zm14.707 9.707L9 6v9.414l2.707-2.707h4zM10 13V8.414l3.293 3.293h-2L10 13z"></path>
330+
</g>
320331
</svg>
321332
<span>MageForge Inspector</span>
322333
`;

0 commit comments

Comments
 (0)