Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6f8c4518ce | |||
| 97d83923d9 | |||
| fef9c9732e | |||
| 61408d6362 | |||
| ce508d32b5 | |||
| db3b6beaa3 |
11
Dockerfile
11
Dockerfile
@@ -7,8 +7,8 @@ WORKDIR /app
|
||||
# Copy package files
|
||||
COPY package*.json ./
|
||||
|
||||
# Install dependencies
|
||||
RUN npm ci --only=production
|
||||
# Install dependencies (including serve for production)
|
||||
RUN npm ci
|
||||
|
||||
# Copy application source
|
||||
COPY . .
|
||||
@@ -16,8 +16,11 @@ COPY . .
|
||||
# Build the application
|
||||
RUN npm run build
|
||||
|
||||
# Install serve globally for production serving
|
||||
RUN npm install -g serve
|
||||
|
||||
# Expose port 3000
|
||||
EXPOSE 3000
|
||||
|
||||
# Start the application
|
||||
CMD ["npm", "run", "serve"]
|
||||
# Start the application using serve directly
|
||||
CMD ["serve", "-s", "build", "-l", "3000"]
|
||||
9
compose.yaml
Normal file
9
compose.yaml
Normal file
@@ -0,0 +1,9 @@
|
||||
services:
|
||||
jmespath-playground:
|
||||
build: .
|
||||
image: skoszewski/jmespath-playground
|
||||
ports:
|
||||
- "3000:3000"
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
restart: unless-stopped
|
||||
@@ -1,25 +0,0 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
jmespath-playground:
|
||||
build: .
|
||||
ports:
|
||||
- "3000:3000"
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
restart: unless-stopped
|
||||
|
||||
# Development service
|
||||
jmespath-playground-dev:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.dev
|
||||
ports:
|
||||
- "3001:3000"
|
||||
volumes:
|
||||
- .:/app
|
||||
- /app/node_modules
|
||||
environment:
|
||||
- CHOKIDAR_USEPOLLING=true
|
||||
profiles:
|
||||
- dev
|
||||
2
package-lock.json
generated
2
package-lock.json
generated
@@ -17,7 +17,7 @@
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-scripts": "^5.0.1",
|
||||
"serve": "^14.2.1",
|
||||
"serve": "^14.2.5",
|
||||
"web-vitals": "^3.5.0"
|
||||
},
|
||||
"engines": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "jmespath-playground",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.2",
|
||||
"description": "A React-based web application for testing JMESPath expressions against JSON data",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
@@ -22,7 +22,7 @@
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-scripts": "^5.0.1",
|
||||
"serve": "^14.2.1",
|
||||
"serve": "^14.2.5",
|
||||
"web-vitals": "^3.5.0"
|
||||
},
|
||||
"eslintConfig": {
|
||||
@@ -52,4 +52,4 @@
|
||||
],
|
||||
"author": "",
|
||||
"license": "MIT"
|
||||
}
|
||||
}
|
||||
|
||||
533
src/App.css
533
src/App.css
@@ -1,12 +1,64 @@
|
||||
/* JMESPath Testing Tool Custom Styles */
|
||||
|
||||
:root {
|
||||
/* Light theme colors */
|
||||
--bg-primary-light: #ffffff;
|
||||
--bg-secondary-light: #f8f9fa;
|
||||
--text-primary-light: #212529;
|
||||
--text-secondary-light: #495057;
|
||||
--text-muted-light: #6c757d;
|
||||
--border-light: #dee2e6;
|
||||
--border-input-light: #ced4da;
|
||||
--accent-color: #007bff;
|
||||
--accent-shadow: rgba(0, 123, 255, 0.25);
|
||||
|
||||
/* Dark theme colors */
|
||||
--bg-primary-dark: #1a1a1a;
|
||||
--bg-secondary-dark: #2d2d2d;
|
||||
--bg-card-dark: #323232;
|
||||
--text-primary-dark: #ffffff;
|
||||
--text-secondary-dark: #e9ecef;
|
||||
--text-muted-dark: #adb5bd;
|
||||
--border-dark: #495057;
|
||||
--border-input-dark: #6c757d;
|
||||
|
||||
/* State colors */
|
||||
--success-bg-light: #d4edda;
|
||||
--success-border-light: #c3e6cb;
|
||||
--success-text-light: #155724;
|
||||
--success-bg-dark: #1e4a1e;
|
||||
--success-border-dark: #2c6d2c;
|
||||
--success-text-dark: #d4edda;
|
||||
|
||||
--error-bg-light: #f8d7da;
|
||||
--error-border-light: #f5c6cb;
|
||||
--error-text-light: #721c24;
|
||||
--error-bg-dark: #4a1e1e;
|
||||
--error-border-dark: #6d2c2c;
|
||||
--error-text-dark: #f8d7da;
|
||||
|
||||
/* Button variants */
|
||||
--btn-success: #28a745;
|
||||
--btn-info: #17a2b8;
|
||||
--btn-primary: #007bff;
|
||||
--btn-danger: #dc3545;
|
||||
--btn-secondary: #6c757d;
|
||||
|
||||
/* Common transitions */
|
||||
--transition-fast: 0.2s ease;
|
||||
--transition-normal: 0.3s ease;
|
||||
|
||||
/* Font families */
|
||||
--font-sans: 'Noto Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
|
||||
--font-mono: 'Noto Sans Mono', 'Consolas', 'Monaco', 'Courier New', monospace;
|
||||
}
|
||||
|
||||
/* Base font family */
|
||||
body {
|
||||
font-family: 'Noto Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
||||
sans-serif;
|
||||
font-family: var(--font-sans);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
transition: background-color var(--transition-normal), color var(--transition-normal);
|
||||
}
|
||||
|
||||
/* Layout structure */
|
||||
@@ -17,6 +69,7 @@ body {
|
||||
/* Header section styling - more compact */
|
||||
.header-section {
|
||||
/* Removed gradient background to fix text visibility */
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
/* Custom card styling */
|
||||
@@ -24,44 +77,43 @@ body {
|
||||
border: none;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||
border-radius: 8px;
|
||||
transition: background-color 0.3s ease, box-shadow 0.3s ease;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
background-color: #f8f9fa;
|
||||
border-bottom: 2px solid #dee2e6;
|
||||
font-weight: 600;
|
||||
color: #212529;
|
||||
transition: background-color 0.3s ease, border-color 0.3s ease, color 0.3s ease;
|
||||
}
|
||||
|
||||
/* Input and textarea styling */
|
||||
.jmespath-input, .json-input, .result-output {
|
||||
font-family: var(--font-mono);
|
||||
font-weight: 400;
|
||||
transition: background-color var(--transition-normal), border-color var(--transition-normal), color var(--transition-normal);
|
||||
}
|
||||
|
||||
.jmespath-input {
|
||||
font-family: 'Noto Sans Mono', 'Consolas', 'Monaco', 'Courier New', monospace;
|
||||
font-size: 14px;
|
||||
padding: 10px;
|
||||
font-weight: 400;
|
||||
background-color: var(--bg-primary-light);
|
||||
border: 1px solid var(--border-input-light);
|
||||
color: var(--text-secondary-light);
|
||||
}
|
||||
|
||||
.json-input, .result-output {
|
||||
font-family: 'Noto Sans Mono', 'Consolas', 'Monaco', 'Courier New', monospace;
|
||||
font-size: 13px;
|
||||
background-color: #f8f9fa;
|
||||
border: 1px solid #dee2e6;
|
||||
font-weight: 400;
|
||||
background-color: var(--bg-secondary-light);
|
||||
border: 1px solid var(--border-light);
|
||||
color: var(--text-secondary-light);
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.json-input.error {
|
||||
border-color: #dc3545;
|
||||
background-color: #fff5f5;
|
||||
}
|
||||
|
||||
.result-output.success {
|
||||
border-color: #28a745;
|
||||
background-color: #f0fff4;
|
||||
}
|
||||
|
||||
/* Button styling */
|
||||
.btn {
|
||||
transition: all 0.2s ease;
|
||||
transition: all var(--transition-fast);
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
@@ -74,12 +126,12 @@ footer {
|
||||
}
|
||||
|
||||
footer a {
|
||||
color: #6c757d;
|
||||
transition: color 0.2s ease;
|
||||
color: var(--text-muted-light);
|
||||
transition: color var(--transition-fast);
|
||||
}
|
||||
|
||||
footer a:hover {
|
||||
color: #495057;
|
||||
color: var(--text-secondary-light);
|
||||
}
|
||||
|
||||
/* Responsive adjustments */
|
||||
@@ -104,4 +156,439 @@ footer a:hover {
|
||||
.card-body textarea {
|
||||
min-height: 300px !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Manual theme overrides */
|
||||
.theme-light {
|
||||
/* Force light theme regardless of system preference */
|
||||
background-color: #ffffff !important;
|
||||
color: #212529 !important;
|
||||
}
|
||||
|
||||
.theme-light .header-section {
|
||||
background-color: transparent !important;
|
||||
border-bottom: none !important;
|
||||
}
|
||||
|
||||
.theme-light .card {
|
||||
background-color: #ffffff !important;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1) !important;
|
||||
color: #212529 !important;
|
||||
}
|
||||
|
||||
.theme-light .card-header {
|
||||
background-color: #f8f9fa !important;
|
||||
border-bottom: 2px solid #dee2e6 !important;
|
||||
color: #212529 !important;
|
||||
}
|
||||
|
||||
.theme-light .jmespath-input {
|
||||
background-color: #ffffff !important;
|
||||
border: 1px solid #ced4da !important;
|
||||
color: #495057 !important;
|
||||
}
|
||||
|
||||
.theme-light .json-input,
|
||||
.theme-light .result-output {
|
||||
background-color: #f8f9fa !important;
|
||||
border: 1px solid #dee2e6 !important;
|
||||
color: #495057 !important;
|
||||
}
|
||||
|
||||
.theme-light .text-muted {
|
||||
color: #6c757d !important;
|
||||
}
|
||||
|
||||
.theme-light .jmespath-input:focus {
|
||||
background-color: var(--bg-primary-light) !important;
|
||||
border-color: var(--accent-color) !important;
|
||||
color: var(--text-secondary-light) !important;
|
||||
box-shadow: 0 0 0 0.2rem var(--accent-shadow) !important;
|
||||
}
|
||||
|
||||
.theme-light .jmespath-input::placeholder {
|
||||
color: var(--text-muted-light) !important;
|
||||
}
|
||||
|
||||
.theme-light .json-input::placeholder,
|
||||
.theme-light .result-output::placeholder {
|
||||
color: var(--text-muted-light) !important;
|
||||
}
|
||||
|
||||
.theme-light .json-input:focus,
|
||||
.theme-light .result-output:focus {
|
||||
background-color: var(--bg-primary-light) !important;
|
||||
border-color: var(--accent-color) !important;
|
||||
color: var(--text-secondary-light) !important;
|
||||
box-shadow: 0 0 0 0.2rem var(--accent-shadow) !important;
|
||||
}
|
||||
|
||||
.theme-light .output-section .form-control {
|
||||
background-color: #f8f9fa !important;
|
||||
}
|
||||
|
||||
.theme-light .alert-danger {
|
||||
background-color: #f8d7da !important;
|
||||
border-color: #f5c6cb !important;
|
||||
color: #721c24 !important;
|
||||
}
|
||||
|
||||
.theme-light .btn-primary {
|
||||
background-color: var(--btn-primary) !important;
|
||||
border-color: var(--btn-primary) !important;
|
||||
color: var(--bg-primary-light) !important;
|
||||
}
|
||||
|
||||
.theme-light .btn-outline-secondary {
|
||||
color: var(--btn-secondary) !important;
|
||||
border-color: var(--btn-secondary) !important;
|
||||
}
|
||||
|
||||
.theme-light .btn-outline-secondary:hover {
|
||||
background-color: var(--btn-secondary) !important;
|
||||
border-color: var(--btn-secondary) !important;
|
||||
color: var(--bg-primary-light) !important;
|
||||
}
|
||||
|
||||
.theme-light .btn-outline-success {
|
||||
color: var(--btn-success) !important;
|
||||
border-color: var(--btn-success) !important;
|
||||
}
|
||||
|
||||
.theme-light .btn-outline-success:hover {
|
||||
background-color: var(--btn-success) !important;
|
||||
border-color: var(--btn-success) !important;
|
||||
color: var(--bg-primary-light) !important;
|
||||
}
|
||||
|
||||
.theme-light .btn-outline-info {
|
||||
color: var(--btn-info) !important;
|
||||
border-color: var(--btn-info) !important;
|
||||
}
|
||||
|
||||
.theme-light .btn-outline-info:hover {
|
||||
background-color: var(--btn-info) !important;
|
||||
border-color: var(--btn-info) !important;
|
||||
color: var(--bg-primary-light) !important;
|
||||
}
|
||||
|
||||
.theme-light .btn-outline-primary {
|
||||
color: var(--btn-primary) !important;
|
||||
border-color: var(--btn-primary) !important;
|
||||
}
|
||||
|
||||
.theme-light .btn-outline-primary:hover {
|
||||
background-color: var(--btn-primary) !important;
|
||||
border-color: var(--btn-primary) !important;
|
||||
color: var(--bg-primary-light) !important;
|
||||
}
|
||||
|
||||
.theme-light .btn-outline-danger {
|
||||
color: var(--btn-danger) !important;
|
||||
border-color: var(--btn-danger) !important;
|
||||
}
|
||||
|
||||
.theme-light .btn-outline-danger:hover {
|
||||
background-color: var(--btn-danger) !important;
|
||||
border-color: var(--btn-danger) !important;
|
||||
color: var(--bg-primary-light) !important;
|
||||
}
|
||||
|
||||
.theme-light footer {
|
||||
background-color: #f8f9fa !important;
|
||||
border-top: 1px solid #dee2e6 !important;
|
||||
color: #212529 !important;
|
||||
}
|
||||
|
||||
.theme-light footer a {
|
||||
color: #6c757d !important;
|
||||
}
|
||||
|
||||
.theme-light footer a:hover {
|
||||
color: #495057 !important;
|
||||
}
|
||||
|
||||
/* Force dark theme regardless of system preference */
|
||||
.theme-dark {
|
||||
background-color: var(--bg-primary-dark) !important;
|
||||
color: var(--text-secondary-dark) !important;
|
||||
}
|
||||
|
||||
.theme-dark .header-section {
|
||||
background-color: var(--bg-secondary-dark) !important;
|
||||
border-bottom: 1px solid #404040 !important;
|
||||
}
|
||||
|
||||
.theme-dark .card {
|
||||
background-color: var(--bg-secondary-dark) !important;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.3) !important;
|
||||
color: var(--text-secondary-dark) !important;
|
||||
}
|
||||
|
||||
.theme-dark .card-header {
|
||||
background-color: var(--bg-card-dark) !important;
|
||||
border-bottom: 2px solid #505050 !important;
|
||||
color: var(--text-primary-dark) !important;
|
||||
}
|
||||
|
||||
.theme-dark .jmespath-input {
|
||||
background-color: var(--bg-card-dark) !important;
|
||||
border: 1px solid #505050 !important;
|
||||
color: var(--text-primary-dark) !important;
|
||||
}
|
||||
|
||||
.theme-dark .jmespath-input::placeholder {
|
||||
color: var(--text-muted-dark) !important;
|
||||
}
|
||||
|
||||
.theme-dark .jmespath-input:focus {
|
||||
background-color: #404040 !important;
|
||||
border-color: var(--accent-color) !important;
|
||||
color: var(--text-primary-dark) !important;
|
||||
}
|
||||
|
||||
.theme-dark .json-input,
|
||||
.theme-dark .result-output {
|
||||
background-color: #2a2a2a !important;
|
||||
border: 1px solid #505050 !important;
|
||||
color: var(--text-secondary-dark) !important;
|
||||
}
|
||||
|
||||
.theme-dark .json-input::placeholder,
|
||||
.theme-dark .result-output::placeholder {
|
||||
color: var(--text-muted-dark) !important;
|
||||
}
|
||||
|
||||
.theme-dark .json-input:focus,
|
||||
.theme-dark .result-output:focus {
|
||||
background-color: var(--bg-card-dark) !important;
|
||||
border-color: var(--accent-color) !important;
|
||||
color: var(--text-primary-dark) !important;
|
||||
}
|
||||
|
||||
.theme-dark .output-section .form-control {
|
||||
background-color: var(--bg-secondary-dark) !important;
|
||||
}
|
||||
|
||||
.theme-dark .alert-danger {
|
||||
background-color: #3d1a1a !important;
|
||||
border-color: #dc3545 !important;
|
||||
color: #f8d7da !important;
|
||||
}
|
||||
|
||||
.theme-dark .text-muted {
|
||||
color: var(--text-muted-dark) !important;
|
||||
}
|
||||
|
||||
.theme-dark footer {
|
||||
background-color: var(--bg-secondary-dark) !important;
|
||||
border-top: 1px solid #404040 !important;
|
||||
color: var(--text-secondary-dark) !important;
|
||||
}
|
||||
|
||||
.theme-dark footer a {
|
||||
color: var(--text-muted-dark) !important;
|
||||
}
|
||||
|
||||
.theme-dark footer a:hover {
|
||||
color: var(--text-secondary-dark) !important;
|
||||
}
|
||||
|
||||
.theme-dark .btn-primary {
|
||||
background-color: var(--btn-primary) !important;
|
||||
border-color: var(--btn-primary) !important;
|
||||
color: var(--bg-primary-light) !important;
|
||||
}
|
||||
|
||||
.theme-dark .btn-outline-secondary {
|
||||
color: var(--btn-secondary) !important;
|
||||
border-color: var(--btn-secondary) !important;
|
||||
}
|
||||
.theme-dark .btn-outline-secondary:hover {
|
||||
background-color: var(--btn-secondary) !important;
|
||||
border-color: var(--btn-secondary) !important;
|
||||
color: var(--bg-primary-light) !important;
|
||||
}
|
||||
|
||||
.theme-dark .btn-outline-success {
|
||||
color: var(--btn-success) !important;
|
||||
border-color: var(--btn-success) !important;
|
||||
}
|
||||
.theme-dark .btn-outline-success:hover {
|
||||
background-color: var(--btn-success) !important;
|
||||
border-color: var(--btn-success) !important;
|
||||
color: var(--bg-primary-light) !important;
|
||||
}
|
||||
|
||||
.theme-dark .btn-outline-info {
|
||||
color: var(--btn-info) !important;
|
||||
border-color: var(--btn-info) !important;
|
||||
}
|
||||
.theme-dark .btn-outline-info:hover {
|
||||
background-color: var(--btn-info) !important;
|
||||
border-color: var(--btn-info) !important;
|
||||
color: var(--bg-primary-light) !important;
|
||||
}
|
||||
|
||||
.theme-dark .btn-outline-primary {
|
||||
color: var(--btn-primary) !important;
|
||||
border-color: var(--btn-primary) !important;
|
||||
}
|
||||
.theme-dark .btn-outline-primary:hover {
|
||||
background-color: var(--btn-primary) !important;
|
||||
border-color: var(--btn-primary) !important;
|
||||
color: var(--bg-primary-light) !important;
|
||||
}
|
||||
|
||||
.theme-dark .btn-outline-danger {
|
||||
color: var(--btn-danger) !important;
|
||||
border-color: var(--btn-danger) !important;
|
||||
}
|
||||
.theme-dark .btn-outline-danger:hover {
|
||||
background-color: var(--btn-danger) !important;
|
||||
border-color: var(--btn-danger) !important;
|
||||
color: var(--bg-primary-light) !important;
|
||||
}
|
||||
|
||||
/* Dark mode support */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
body {
|
||||
background-color: #1a1a1a;
|
||||
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);
|
||||
}
|
||||
|
||||
footer .text-muted {
|
||||
color: var(--text-muted-dark) !important;
|
||||
}
|
||||
|
||||
footer a {
|
||||
color: var(--text-muted-dark);
|
||||
}
|
||||
|
||||
footer a:hover {
|
||||
color: var(--text-secondary-dark);
|
||||
}
|
||||
|
||||
/* Bootstrap dark mode overrides */
|
||||
.btn-outline-success {
|
||||
color: #28a745;
|
||||
border-color: #28a745;
|
||||
}
|
||||
|
||||
.btn-outline-success:hover {
|
||||
background-color: #28a745;
|
||||
border-color: #28a745;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.btn-outline-info {
|
||||
color: #17a2b8;
|
||||
border-color: #17a2b8;
|
||||
}
|
||||
|
||||
.btn-outline-info:hover {
|
||||
background-color: #17a2b8;
|
||||
border-color: #17a2b8;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.btn-outline-primary {
|
||||
color: #007bff;
|
||||
border-color: #007bff;
|
||||
}
|
||||
|
||||
.btn-outline-primary:hover {
|
||||
background-color: #007bff;
|
||||
border-color: #007bff;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.btn-outline-secondary {
|
||||
color: #6c757d;
|
||||
border-color: #6c757d;
|
||||
}
|
||||
|
||||
.btn-outline-secondary:hover {
|
||||
background-color: #6c757d;
|
||||
border-color: var(--btn-secondary);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.btn-outline-danger {
|
||||
color: var(--btn-danger);
|
||||
border-color: var(--btn-danger);
|
||||
}
|
||||
|
||||
.btn-outline-danger:hover {
|
||||
background-color: var(--btn-danger);
|
||||
border-color: var(--btn-danger);
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
64
src/App.js
64
src/App.js
@@ -5,6 +5,10 @@ import './App.css';
|
||||
// JMESPath Testing Tool - Main Application Component
|
||||
function App() {
|
||||
const [jmespathExpression, setJmespathExpression] = useState('people[0].name');
|
||||
const [theme, setTheme] = useState(() => {
|
||||
// Load theme from localStorage or default to 'auto'
|
||||
return localStorage.getItem('theme') || 'auto';
|
||||
});
|
||||
const [jsonData, setJsonData] = useState(`{
|
||||
"people": [
|
||||
{
|
||||
@@ -24,6 +28,29 @@ function App() {
|
||||
const [error, setError] = useState('');
|
||||
const [jsonError, setJsonError] = useState('');
|
||||
|
||||
// Theme management
|
||||
useEffect(() => {
|
||||
// Apply theme to document
|
||||
const applyTheme = (selectedTheme) => {
|
||||
const root = document.documentElement;
|
||||
root.className = ''; // Clear existing theme classes
|
||||
|
||||
if (selectedTheme === 'light') {
|
||||
root.classList.add('theme-light');
|
||||
} else if (selectedTheme === 'dark') {
|
||||
root.classList.add('theme-dark');
|
||||
}
|
||||
// 'auto' uses CSS media queries (no class needed)
|
||||
};
|
||||
|
||||
applyTheme(theme);
|
||||
localStorage.setItem('theme', theme);
|
||||
}, [theme]);
|
||||
|
||||
const handleThemeChange = (newTheme) => {
|
||||
setTheme(newTheme);
|
||||
};
|
||||
|
||||
const evaluateExpression = () => {
|
||||
try {
|
||||
// Clear previous errors
|
||||
@@ -185,8 +212,37 @@ function App() {
|
||||
<div className="header-section py-2">
|
||||
<div className="container">
|
||||
<div className="row">
|
||||
<div className="col-12 text-center">
|
||||
<div className="col-12 text-center position-relative">
|
||||
<h2 className="mb-1">JMESPath Testing Tool</h2>
|
||||
{/* Theme switcher */}
|
||||
<div className="position-absolute top-0 end-0">
|
||||
<div className="btn-group btn-group-sm" role="group" aria-label="Theme switcher">
|
||||
<button
|
||||
type="button"
|
||||
className={`btn ${theme === 'auto' ? 'btn-primary' : 'btn-outline-secondary'}`}
|
||||
onClick={() => handleThemeChange('auto')}
|
||||
title="Auto (follow system)"
|
||||
>
|
||||
🌓 Auto
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className={`btn ${theme === 'light' ? 'btn-primary' : 'btn-outline-secondary'}`}
|
||||
onClick={() => handleThemeChange('light')}
|
||||
title="Light theme"
|
||||
>
|
||||
☀️ Light
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className={`btn ${theme === 'dark' ? 'btn-primary' : 'btn-outline-secondary'}`}
|
||||
onClick={() => handleThemeChange('dark')}
|
||||
title="Dark theme"
|
||||
>
|
||||
🌙 Dark
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -283,7 +339,7 @@ function App() {
|
||||
<div className="card-body d-flex flex-column" style={{ minHeight: 0 }}>
|
||||
<div className="flex-grow-1" style={{ minHeight: 0 }}>
|
||||
<textarea
|
||||
className={`form-control h-100 json-input ${jsonError ? 'error' : ''}`}
|
||||
className="form-control h-100 json-input"
|
||||
value={jsonData}
|
||||
onChange={handleJsonChange}
|
||||
placeholder="Enter JSON data here..."
|
||||
@@ -311,7 +367,7 @@ function App() {
|
||||
<div className="card-body d-flex flex-column" style={{ minHeight: 0 }}>
|
||||
<div className="flex-grow-1" style={{ minHeight: 0 }}>
|
||||
<textarea
|
||||
className={`form-control h-100 result-output ${result && !error && !jsonError ? 'success' : ''}`}
|
||||
className="form-control h-100 result-output"
|
||||
value={result}
|
||||
readOnly
|
||||
placeholder="Results will appear here..."
|
||||
@@ -335,7 +391,7 @@ function App() {
|
||||
</div>
|
||||
<div className="col-md-6 text-md-end">
|
||||
<p className="mb-0 text-muted small">
|
||||
Licensed under <a href="#" className="text-decoration-none">MIT License</a> |
|
||||
Licensed under <a href="https://opensource.org/licenses/MIT" target="_blank" rel="noopener noreferrer" className="text-decoration-none">MIT License</a> |
|
||||
<a href="https://jmespath.org/" target="_blank" rel="noopener noreferrer" className="text-decoration-none ms-2">
|
||||
Learn JMESPath
|
||||
</a>
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
||||
sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
@@ -32,8 +27,6 @@ code {
|
||||
|
||||
.form-control {
|
||||
resize: vertical;
|
||||
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.input-section .form-control {
|
||||
@@ -48,27 +41,15 @@ code {
|
||||
}
|
||||
|
||||
.error {
|
||||
background-color: #f8d7da !important;
|
||||
border-color: #f5c6cb !important;
|
||||
color: #721c24;
|
||||
background-color: var(--error-bg-light) !important;
|
||||
border-color: var(--error-border-light) !important;
|
||||
color: var(--error-text-light);
|
||||
}
|
||||
|
||||
.success {
|
||||
background-color: #d4edda !important;
|
||||
border-color: #c3e6cb !important;
|
||||
color: #155724;
|
||||
}
|
||||
|
||||
.btn-outline-success:hover {
|
||||
background-color: #28a745;
|
||||
border-color: #28a745;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-outline-info:hover {
|
||||
background-color: #17a2b8;
|
||||
border-color: #17a2b8;
|
||||
color: white;
|
||||
background-color: var(--success-bg-light) !important;
|
||||
border-color: var(--success-border-light) !important;
|
||||
color: var(--success-text-light);
|
||||
}
|
||||
|
||||
.header-section {
|
||||
@@ -78,18 +59,50 @@ code {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.jmespath-input {
|
||||
background-color: #fff3cd;
|
||||
border-color: #ffeaa7;
|
||||
font-weight: 500;
|
||||
/* Dark mode support for error states */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.error {
|
||||
background-color: var(--error-bg-dark) !important;
|
||||
border-color: var(--error-border-dark) !important;
|
||||
color: var(--error-text-dark) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.json-input {
|
||||
background-color: #e8f5e8;
|
||||
border-color: #c3e6cb;
|
||||
/* Manual theme overrides for error states */
|
||||
.theme-dark .error {
|
||||
background-color: var(--error-bg-dark) !important;
|
||||
border-color: var(--error-border-dark) !important;
|
||||
color: var(--error-text-dark) !important;
|
||||
}
|
||||
|
||||
.result-output {
|
||||
background-color: #e7f3ff;
|
||||
border-color: #b3d7ff;
|
||||
.theme-light .error {
|
||||
background-color: var(--error-bg-light) !important;
|
||||
border-color: var(--error-border-light) !important;
|
||||
color: var(--error-text-light) !important;
|
||||
}
|
||||
|
||||
/* Manual theme overrides for success states */
|
||||
.theme-dark .success {
|
||||
background-color: var(--success-bg-dark) !important;
|
||||
border-color: var(--success-border-dark) !important;
|
||||
color: var(--success-text-dark) !important;
|
||||
}
|
||||
|
||||
.theme-light .success {
|
||||
background-color: var(--success-bg-light) !important;
|
||||
border-color: var(--success-border-light) !important;
|
||||
color: var(--success-text-light) !important;
|
||||
}
|
||||
|
||||
/* Additional specificity for jmespath-input with error class */
|
||||
.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;
|
||||
}
|
||||
|
||||
.theme-light .jmespath-input.error {
|
||||
background-color: var(--error-bg-light) !important;
|
||||
border-color: var(--error-border-light) !important;
|
||||
color: var(--error-text-light) !important;
|
||||
}
|
||||
Reference in New Issue
Block a user