2 Commits

Author SHA1 Message Date
14d87bff2e v1.0.4 - Unified theme system and consistent color definitions 2026-01-21 11:11:23 +01:00
0182174153 v1.0.3: Fix expression textbox error state and UI consistency
- Fixed theme class application from html to body element for proper CSS inheritance
- Removed CSS conflicts between base styles and error/success states
- Fixed focus state interference with error/success background colors
- Changed error message panel to fixed placement (no more UI jumping)
- Added theme-consistent styling for alert-success in all theme modes
- Expression textbox now properly shows red/green backgrounds in manual themes
- Status message now shows Expression is correct vs error message consistently
2026-01-21 10:35:34 +01:00
4 changed files with 167 additions and 111 deletions

View File

@@ -1,6 +1,6 @@
{ {
"name": "jmespath-playground", "name": "jmespath-playground",
"version": "1.0.2", "version": "1.0.4",
"description": "A React-based web application for testing JMESPath expressions against JSON data", "description": "A React-based web application for testing JMESPath expressions against JSON data",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {

View File

@@ -183,9 +183,9 @@ footer a:hover {
} }
.theme-light .jmespath-input { .theme-light .jmespath-input {
background-color: #ffffff !important; background-color: #ffffff;
border: 1px solid #ced4da !important; border: 1px solid #ced4da;
color: #495057 !important; color: #495057;
} }
.theme-light .json-input, .theme-light .json-input,
@@ -195,15 +195,26 @@ footer a:hover {
color: #495057 !important; color: #495057 !important;
} }
/* Success and Error state overrides - must come after base input rules */
.theme-light .jmespath-input.success {
background-color: #d4edda !important;
border-color: #c3e6cb !important;
color: #155724 !important;
}
.theme-light .jmespath-input.error {
background-color: #f8d7da !important;
border-color: #f5c6cb !important;
color: #721c24 !important;
}
.theme-light .text-muted { .theme-light .text-muted {
color: #6c757d !important; color: #6c757d !important;
} }
.theme-light .jmespath-input:focus { .theme-light .jmespath-input:focus {
background-color: var(--bg-primary-light) !important; border-color: var(--accent-color);
border-color: var(--accent-color) !important; box-shadow: 0 0 0 0.2rem var(--accent-shadow);
color: var(--text-secondary-light) !important;
box-shadow: 0 0 0 0.2rem var(--accent-shadow) !important;
} }
.theme-light .jmespath-input::placeholder { .theme-light .jmespath-input::placeholder {
@@ -233,6 +244,12 @@ footer a:hover {
color: #721c24 !important; color: #721c24 !important;
} }
.theme-light .alert-success {
background-color: #d4edda !important;
border-color: #c3e6cb !important;
color: #155724 !important;
}
.theme-light .btn-primary { .theme-light .btn-primary {
background-color: var(--btn-primary) !important; background-color: var(--btn-primary) !important;
border-color: var(--btn-primary) !important; border-color: var(--btn-primary) !important;
@@ -332,9 +349,22 @@ footer a:hover {
} }
.theme-dark .jmespath-input { .theme-dark .jmespath-input {
background-color: var(--bg-card-dark) !important; background-color: var(--bg-card-dark);
border: 1px solid #505050 !important; border: 1px solid #505050;
color: var(--text-primary-dark) !important; color: var(--text-primary-dark);
}
/* Success and Error state overrides - must come after base input rules */
.theme-dark .jmespath-input.success {
background-color: #1e4a1e !important;
border-color: #2c6d2c !important;
color: #d4edda !important;
}
.theme-dark .jmespath-input.error {
background-color: #4a1e1e !important;
border-color: #6d2c2c !important;
color: #f8d7da !important;
} }
.theme-dark .jmespath-input::placeholder { .theme-dark .jmespath-input::placeholder {
@@ -342,9 +372,7 @@ footer a:hover {
} }
.theme-dark .jmespath-input:focus { .theme-dark .jmespath-input:focus {
background-color: #404040 !important; border-color: var(--accent-color);
border-color: var(--accent-color) !important;
color: var(--text-primary-dark) !important;
} }
.theme-dark .json-input, .theme-dark .json-input,
@@ -376,6 +404,12 @@ footer a:hover {
color: #f8d7da !important; color: #f8d7da !important;
} }
.theme-dark .alert-success {
background-color: #1e4a1e !important;
border-color: #2c6d2c !important;
color: #d4edda !important;
}
.theme-dark .text-muted { .theme-dark .text-muted {
color: var(--text-muted-dark) !important; color: var(--text-muted-dark) !important;
} }
@@ -452,100 +486,119 @@ footer a:hover {
/* Dark mode support */ /* Dark mode support */
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
body { body:not(.theme-light):not(.theme-dark) {
background-color: #1a1a1a; background-color: var(--bg-primary-dark);
color: #e9ecef;
}
.header-section {
background-color: #2d2d2d;
border-bottom: 1px solid #404040;
}
.card {
background-color: #2d2d2d;
box-shadow: 0 2px 8px rgba(0,0,0,0.3);
color: #e9ecef;
}
.card-header {
background-color: #3a3a3a;
border-bottom: 2px solid #505050;
color: #f8f9fa;
}
.jmespath-input {
background-color: #3a3a3a;
border: 1px solid #505050;
color: #f8f9fa;
}
.jmespath-input::placeholder {
color: #adb5bd;
}
.jmespath-input:focus {
background-color: #404040;
border-color: #007bff;
color: #ffffff;
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
}
.json-input, .result-output {
background-color: #2a2a2a;
border: 1px solid #505050;
color: #e9ecef;
}
.json-input::placeholder, .result-output::placeholder {
color: #6c757d;
}
.json-input:focus, .result-output:focus {
background-color: #323232;
border-color: #007bff;
color: #ffffff;
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
}
.alert-danger {
background-color: #3d1a1a;
border-color: #dc3545;
color: #f8d7da;
}
.text-muted {
color: #adb5bd !important;
}
footer {
background-color: var(--bg-secondary-dark) !important;
border-top: 1px solid #404040 !important;
color: var(--text-secondary-dark); color: var(--text-secondary-dark);
} }
footer .text-muted { body:not(.theme-light):not(.theme-dark) .header-section {
color: var(--text-muted-dark) !important; background-color: var(--bg-secondary-dark);
border-bottom: 1px solid var(--border-dark);
} }
footer a { body:not(.theme-light):not(.theme-dark) .card {
background-color: var(--bg-secondary-dark);
box-shadow: 0 2px 8px rgba(0,0,0,0.3);
color: var(--text-secondary-dark);
}
body:not(.theme-light):not(.theme-dark) .card-header {
background-color: var(--bg-card-dark);
border-bottom: 2px solid var(--border-dark);
color: var(--text-primary-dark);
}
body:not(.theme-light):not(.theme-dark) .jmespath-input {
background-color: var(--bg-card-dark) !important;
border: 1px solid var(--border-input-dark) !important;
color: var(--text-primary-dark) !important;
}
body:not(.theme-light):not(.theme-dark) .jmespath-input.success {
background-color: var(--success-bg-dark) !important;
border-color: var(--success-border-dark) !important;
color: var(--success-text-dark) !important;
}
body:not(.theme-light):not(.theme-dark) .jmespath-input.error {
background-color: var(--error-bg-dark) !important;
border-color: var(--error-border-dark) !important;
color: var(--error-text-dark) !important;
}
body:not(.theme-light):not(.theme-dark) .jmespath-input::placeholder {
color: var(--text-muted-dark); color: var(--text-muted-dark);
} }
footer a:hover { body:not(.theme-light):not(.theme-dark) .jmespath-input:focus {
border-color: var(--accent-color);
box-shadow: 0 0 0 0.2rem var(--accent-shadow);
}
body:not(.theme-light):not(.theme-dark) .json-input,
body:not(.theme-light):not(.theme-dark) .result-output {
background-color: #2a2a2a;
border: 1px solid var(--border-input-dark);
color: var(--text-secondary-dark); color: var(--text-secondary-dark);
} }
/* Bootstrap dark mode overrides */ body:not(.theme-light):not(.theme-dark) .json-input::placeholder,
.btn-outline-success { body:not(.theme-light):not(.theme-dark) .result-output::placeholder {
color: #28a745; color: var(--text-muted-dark);
border-color: #28a745;
} }
.btn-outline-success:hover { body:not(.theme-light):not(.theme-dark) .json-input:focus,
background-color: #28a745; body:not(.theme-light):not(.theme-dark) .result-output:focus {
border-color: #28a745; background-color: #323232;
color: #fff; border-color: var(--accent-color);
color: var(--text-primary-dark);
box-shadow: 0 0 0 0.2rem var(--accent-shadow);
}
body:not(.theme-light):not(.theme-dark) .alert-danger {
background-color: var(--error-bg-dark);
border-color: var(--error-border-dark);
color: var(--error-text-dark);
}
body:not(.theme-light):not(.theme-dark) .alert-success {
background-color: var(--success-bg-dark);
border-color: var(--success-border-dark);
color: var(--success-text-dark);
}
body:not(.theme-light):not(.theme-dark) .text-muted {
color: var(--text-muted-dark) !important;
}
body:not(.theme-light):not(.theme-dark) footer.bg-light {
background-color: var(--bg-secondary-dark) !important;
border-top: 1px solid var(--border-dark) !important;
color: var(--text-secondary-dark) !important;
}
body:not(.theme-light):not(.theme-dark) footer .text-muted {
color: var(--text-muted-dark) !important;
}
body:not(.theme-light):not(.theme-dark) footer a {
color: var(--text-muted-dark) !important;
}
body:not(.theme-light):not(.theme-dark) footer a:hover {
color: var(--text-secondary-dark) !important;
}
/* Bootstrap dark mode overrides */
body:not(.theme-light):not(.theme-dark) .btn-outline-success {
color: var(--btn-success);
border-color: var(--btn-success);
}
body:not(.theme-light):not(.theme-dark) .btn-outline-success:hover {
background-color: var(--btn-success);
border-color: var(--btn-success);
color: var(--bg-primary-light);
} }
.btn-outline-info { .btn-outline-info {

View File

@@ -1,5 +1,6 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import jmespath from 'jmespath'; import jmespath from 'jmespath';
import packageJson from '../package.json';
import './App.css'; import './App.css';
// JMESPath Testing Tool - Main Application Component // JMESPath Testing Tool - Main Application Component
@@ -33,12 +34,16 @@ function App() {
// Apply theme to document // Apply theme to document
const applyTheme = (selectedTheme) => { const applyTheme = (selectedTheme) => {
const root = document.documentElement; const root = document.documentElement;
root.className = ''; // Clear existing theme classes const body = document.body;
// Clear existing theme classes from both html and body
root.className = '';
body.classList.remove('theme-light', 'theme-dark');
if (selectedTheme === 'light') { if (selectedTheme === 'light') {
root.classList.add('theme-light'); body.classList.add('theme-light');
} else if (selectedTheme === 'dark') { } else if (selectedTheme === 'dark') {
root.classList.add('theme-dark'); body.classList.add('theme-dark');
} }
// 'auto' uses CSS media queries (no class needed) // 'auto' uses CSS media queries (no class needed)
}; };
@@ -310,16 +315,14 @@ function App() {
<div className="card-body"> <div className="card-body">
<input <input
type="text" type="text"
className={`form-control jmespath-input ${error ? 'error' : ''}`} className={`form-control jmespath-input ${error ? 'error' : 'success'}`}
value={jmespathExpression} value={jmespathExpression}
onChange={handleJmespathChange} onChange={handleJmespathChange}
placeholder="Enter JMESPath expression (e.g., people[*].name)" placeholder="Enter JMESPath expression (e.g., people[*].name)"
/> />
{error && ( <div className={`alert mt-2 mb-0 ${error ? 'alert-danger' : 'alert-success'}`}>
<div className="alert alert-danger mt-2 mb-0"> <small>{error || 'Expression is correct'}</small>
<small>{error}</small> </div>
</div>
)}
</div> </div>
</div> </div>
</div> </div>
@@ -386,7 +389,7 @@ function App() {
<div className="row"> <div className="row">
<div className="col-md-6"> <div className="col-md-6">
<p className="mb-0 text-muted small"> <p className="mb-0 text-muted small">
<strong>JMESPath Testing Tool</strong> - Created for testing and validating JMESPath expressions <strong>JMESPath Testing Tool</strong> v{packageJson.version} - Created for testing and validating JMESPath expressions
</p> </p>
</div> </div>
<div className="col-md-6 text-md-end"> <div className="col-md-6 text-md-end">

View File

@@ -96,13 +96,13 @@ code {
/* Additional specificity for jmespath-input with error class */ /* Additional specificity for jmespath-input with error class */
.theme-dark .jmespath-input.error { .theme-dark .jmespath-input.error {
background-color: var(--error-bg-dark) !important; background-color: #4a1e1e !important;
border-color: var(--error-border-dark) !important; border-color: #6d2c2c !important;
color: var(--error-text-dark) !important; color: #f8d7da !important;
} }
.theme-light .jmespath-input.error { .theme-light .jmespath-input.error {
background-color: var(--error-bg-light) !important; background-color: #f8d7da !important;
border-color: var(--error-border-light) !important; border-color: #f5c6cb !important;
color: var(--error-text-light) !important; color: #721c24 !important;
} }