lots of progress

This commit is contained in:
2025-04-20 17:54:08 +03:00
parent de8775d0c3
commit bb3c9c82e0
12 changed files with 2293 additions and 29 deletions
+291
View File
@@ -0,0 +1,291 @@
@extends('layouts.app')
@section('title', 'JSON API Documentation')
@push('styles')
<style>
.endpoint-card {
border: 1px solid var(--bs-border-color);
border-radius: 0.5rem;
transition: all 0.3s ease;
margin-bottom: 2rem;
}
.endpoint-card:hover {
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.1);
}
.endpoint-header {
background-color: var(--bs-body-bg);
border-bottom: 1px solid var(--bs-border-color);
padding: 1rem;
border-radius: 0.5rem 0.5rem 0 0;
}
.endpoint-method {
display: inline-block;
padding: 0.25rem 0.5rem;
border-radius: 0.25rem;
font-weight: bold;
margin-right: 0.5rem;
}
.method-post {
background-color: #49cc90;
color: white;
}
.endpoint-path {
font-family: 'Courier New', monospace;
font-size: 1.1rem;
}
.endpoint-body {
padding: 1rem;
}
.request-example {
background-color: var(--bs-body-bg);
border: 1px solid var(--bs-border-color);
border-radius: 0.375rem;
padding: 1rem;
margin: 1rem 0;
font-family: 'Courier New', monospace;
font-size: 0.875rem;
}
.response-example {
background-color: var(--bs-body-bg);
border: 1px solid var(--bs-border-color);
border-radius: 0.375rem;
padding: 1rem;
margin: 1rem 0;
font-family: 'Courier New', monospace;
font-size: 0.875rem;
}
.hero-section {
background: linear-gradient(135deg, var(--primary-color) 0%, #6a8eff 100%);
color: white;
padding: 3rem 0;
margin-bottom: 2rem;
border-radius: 0.5rem;
}
.code-block {
background-color: var(--bs-body-bg);
border: 1px solid var(--bs-border-color);
border-radius: 0.375rem;
padding: 1rem;
margin: 1rem 0;
font-family: 'Courier New', monospace;
font-size: 0.875rem;
overflow-x: auto;
}
</style>
@endpush
@section('content')
<div class="hero-section text-center">
<h1 class="display-4 fw-bold mb-3">JSON API Documentation</h1>
<p class="lead mb-4">Programmatic access to JSON validation and formatting tools</p>
</div>
<div class="card shadow-sm mb-4">
<div class="card-body">
<h2 class="h4 mb-3">Getting Started</h2>
<p>Our JSON API provides endpoints for validating, formatting, and comparing JSON documents. All endpoints accept and return JSON data.</p>
<h3 class="h5 mt-4">Base URL</h3>
<div class="code-block">
{{ url('/api/json') }}
</div>
<h3 class="h5 mt-4">Authentication</h3>
<p>Currently, the API is open and does not require authentication. However, rate limiting may be implemented in the future.</p>
</div>
</div>
<div class="endpoint-card">
<div class="endpoint-header">
<span class="endpoint-method method-post">POST</span>
<span class="endpoint-path">/validate</span>
</div>
<div class="endpoint-body">
<h3 class="h5">Validate JSON</h3>
<p>Validates a JSON document and returns the parsed data if valid.</p>
<h4 class="h6 mt-3">Request</h4>
<div class="request-example">
<pre><code>{
"json": "{\"name\":\"John\",\"age\":30}"
}</code></pre>
</div>
<h4 class="h6 mt-3">Response (Success)</h4>
<div class="response-example">
<pre><code>{
"status": "success",
"message": "Valid JSON",
"data": {
"name": "John",
"age": 30
}
}</code></pre>
</div>
<h4 class="h6 mt-3">Response (Error)</h4>
<div class="response-example">
<pre><code>{
"status": "error",
"message": "Invalid JSON",
"error": "Syntax error"
}</code></pre>
</div>
</div>
</div>
<div class="endpoint-card">
<div class="endpoint-header">
<span class="endpoint-method method-post">POST</span>
<span class="endpoint-path">/validate-schema</span>
</div>
<div class="endpoint-body">
<h3 class="h5">Validate JSON Against Schema</h3>
<p>Validates a JSON document against a JSON Schema.</p>
<h4 class="h6 mt-3">Request</h4>
<div class="request-example">
<pre><code>{
"json": "{\"name\":\"John\",\"age\":30}",
"schema": "{
\"type\":\"object\",
\"properties\":{
\"name\":{\"type\":\"string\"},
\"age\":{\"type\":\"number\"}
},
\"required\":[\"name\",\"age\"]
}"
}</code></pre>
</div>
<h4 class="h6 mt-3">Response (Success)</h4>
<div class="response-example">
<pre><code>{
"status": "success",
"message": "JSON is valid according to the schema",
"data": {
"name": "John",
"age": 30
}
}</code></pre>
</div>
<h4 class="h6 mt-3">Response (Error)</h4>
<div class="response-example">
<pre><code>{
"status": "error",
"message": "JSON does not match schema",
"errors": [
{
"instancePath": "/age",
"message": "must be a number"
}
]
}</code></pre>
</div>
</div>
</div>
<div class="endpoint-card">
<div class="endpoint-header">
<span class="endpoint-method method-post">POST</span>
<span class="endpoint-path">/format</span>
</div>
<div class="endpoint-body">
<h3 class="h5">Format JSON</h3>
<p>Formats a JSON document with specified indentation.</p>
<h4 class="h6 mt-3">Request</h4>
<div class="request-example">
<pre><code>{
"json": "{\"name\":\"John\",\"age\":30}",
"indent": 2
}</code></pre>
</div>
<h4 class="h6 mt-3">Response (Success)</h4>
<div class="response-example">
<pre><code>{
"status": "success",
"message": "JSON formatted successfully",
"data": "{
\"name\": \"John\",
\"age\": 30
}"
}</code></pre>
</div>
</div>
</div>
<div class="endpoint-card">
<div class="endpoint-header">
<span class="endpoint-method method-post">POST</span>
<span class="endpoint-path">/compare</span>
</div>
<div class="endpoint-body">
<h3 class="h5">Compare JSON Documents</h3>
<p>Compares two JSON documents and returns the differences.</p>
<h4 class="h6 mt-3">Request</h4>
<div class="request-example">
<pre><code>{
"json1": "{\"name\":\"John\",\"age\":30}",
"json2": "{\"name\":\"John\",\"age\":31}"
}</code></pre>
</div>
<h4 class="h6 mt-3">Response (Success)</h4>
<div class="response-example">
<pre><code>{
"status": "success",
"message": "JSON comparison completed",
"data": {
"are_equal": false,
"differences": [
{
"path": ["age"],
"old_value": 30,
"new_value": 31
}
]
}
}</code></pre>
</div>
</div>
</div>
<div class="card shadow-sm mt-4">
<div class="card-body">
<h2 class="h4 mb-3">Example Usage</h2>
<p>Here's an example of how to use the API with cURL:</p>
<div class="code-block">
<pre><code># Validate JSON
curl -X POST {{ url('/api/json/validate') }} \
-H "Content-Type: application/json" \
-d '{"json":"{\"name\":\"John\",\"age\":30}"}'
# Format JSON
curl -X POST {{ url('/api/json/format') }} \
-H "Content-Type: application/json" \
-d '{"json":"{\"name\":\"John\",\"age\":30}","indent":2}'
# Compare JSON
curl -X POST {{ url('/api/json/compare') }} \
-H "Content-Type: application/json" \
-d '{"json1":"{\"name\":\"John\",\"age\":30}","json2":"{\"name\":\"John\",\"age\":31}"}'</code></pre>
</div>
</div>
</div>
@endsection
+251
View File
@@ -0,0 +1,251 @@
@extends('layouts.app')
@section('title', 'JSON Compare - Free Online JSON Diff Tool')
@push('styles')
<link href="https://cdn.jsdelivr.net/npm/jsondiffpatch@0.4.1/dist/formatters-styles/html.css" rel="stylesheet">
<style>
.json-input {
min-height: 300px;
font-family: 'Courier New', monospace;
background-color: var(--bs-body-bg);
border: 1px solid var(--bs-border-color);
transition: all 0.3s ease;
}
.json-input:focus {
border-color: var(--primary-color);
box-shadow: 0 0 0 0.25rem rgba(74, 107, 255, 0.25);
}
.result-box {
display: none;
animation: fadeIn 0.3s ease;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(-10px); }
to { opacity: 1; transform: translateY(0); }
}
.result-box.show {
display: block;
}
.diff-viewer {
height: 500px;
border: 1px solid var(--bs-border-color);
border-radius: 0.375rem;
margin-top: 1rem;
background-color: var(--bs-body-bg);
transition: all 0.3s ease;
overflow: auto;
}
.hero-section {
background: linear-gradient(135deg, var(--primary-color) 0%, #6a8eff 100%);
color: white;
padding: 3rem 0;
margin-bottom: 2rem;
border-radius: 0.5rem;
}
.feature-icon {
font-size: 2rem;
color: var(--primary-color);
margin-bottom: 1rem;
}
.feature-card {
text-align: center;
padding: 1.5rem;
border-radius: 0.5rem;
background-color: var(--bs-body-bg);
border: 1px solid var(--bs-border-color);
transition: all 0.3s ease;
}
.feature-card:hover {
transform: translateY(-5px);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.1);
}
/* Dark mode styles for jsondiffpatch */
[data-bs-theme="dark"] .jsondiffpatch-delta {
background-color: var(--bs-dark);
}
[data-bs-theme="dark"] .jsondiffpatch-delta pre {
color: var(--bs-light);
}
[data-bs-theme="dark"] .jsondiffpatch-added {
background-color: rgba(40, 167, 69, 0.2);
}
[data-bs-theme="dark"] .jsondiffpatch-removed {
background-color: rgba(220, 53, 69, 0.2);
}
[data-bs-theme="dark"] .jsondiffpatch-modified {
background-color: rgba(255, 193, 7, 0.2);
}
</style>
@endpush
@section('content')
<div class="hero-section text-center">
<h1 class="display-4 fw-bold mb-3">JSON Compare Tool</h1>
<p class="lead mb-4">Compare and visualize differences between two JSON documents</p>
</div>
<div class="row mb-4">
<div class="col-md-4 mb-3">
<div class="feature-card">
<i class="bi bi-arrows-angle-contract feature-icon"></i>
<h3>Side-by-Side Diff</h3>
<p>View differences between two JSON documents in a clear, visual format</p>
</div>
</div>
<div class="col-md-4 mb-3">
<div class="feature-card">
<i class="bi bi-code-slash feature-icon"></i>
<h3>Color-Coded</h3>
<p>Easily identify additions, deletions, and modifications with color coding</p>
</div>
</div>
<div class="col-md-4 mb-3">
<div class="feature-card">
<i class="bi bi-arrows-collapse feature-icon"></i>
<h3>Collapsible</h3>
<p>Navigate large JSON documents with collapsible nodes</p>
</div>
</div>
</div>
<div class="card shadow-sm">
<div class="card-body">
<div class="row">
<div class="col-md-6 mb-3">
<label for="jsonInput1" class="form-label">First JSON:</label>
<textarea class="form-control json-input" id="jsonInput1" rows="10" placeholder='{
"example": "json",
"format": "here"
}'></textarea>
</div>
<div class="col-md-6 mb-3">
<label for="jsonInput2" class="form-label">Second JSON:</label>
<textarea class="form-control json-input" id="jsonInput2" rows="10" placeholder='{
"example": "json",
"format": "here"
}'></textarea>
</div>
</div>
<div class="d-flex gap-2">
<button class="btn btn-primary" id="compareBtn">
<i class="bi bi-arrows-angle-contract me-2"></i>Compare JSON
</button>
<button class="btn btn-outline-secondary" id="clearBtn">
<i class="bi bi-trash me-2"></i>Clear
</button>
</div>
</div>
</div>
<div class="card shadow-sm mt-4 result-box" id="resultBox">
<div class="card-body">
<h3 class="h5 card-title">Comparison Result</h3>
<div id="resultContent"></div>
<div class="diff-viewer" id="diffViewer"></div>
</div>
</div>
<div class="mt-5">
<h2 class="h4 mb-3">About JSON Compare Tool</h2>
<div class="card">
<div class="card-body">
<p>Our JSON Compare Tool helps you identify differences between two JSON documents quickly and efficiently. Whether you're comparing API responses, configuration files, or any other JSON data, our tool provides a clear visualization of the changes.</p>
<h3 class="h5 mt-4">Key Features:</h3>
<ul>
<li>Side-by-side JSON comparison</li>
<li>Color-coded differences (green for additions, red for deletions, yellow for modifications)</li>
<li>Collapsible nodes for easy navigation</li>
<li>Dark and light mode support</li>
<li>Mobile-friendly interface</li>
</ul>
<h3 class="h5 mt-4">How to Use:</h3>
<ol>
<li>Enter or paste your first JSON document in the left textarea</li>
<li>Enter or paste your second JSON document in the right textarea</li>
<li>Click the "Compare JSON" button to see the differences</li>
<li>Use the collapsible nodes to navigate through the differences</li>
</ol>
</div>
</div>
</div>
@endsection
@push('scripts')
<script src="https://cdn.jsdelivr.net/npm/jsondiffpatch@0.4.1/dist/jsondiffpatch.umd.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jsondiffpatch@0.4.1/dist/formatters-styles/html.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
const compareBtn = document.getElementById('compareBtn');
const clearBtn = document.getElementById('clearBtn');
const jsonInput1 = document.getElementById('jsonInput1');
const jsonInput2 = document.getElementById('jsonInput2');
const resultBox = document.getElementById('resultBox');
const resultContent = document.getElementById('resultContent');
const diffViewer = document.getElementById('diffViewer');
// Compare JSON
compareBtn.addEventListener('click', function() {
try {
const json1 = JSON.parse(jsonInput1.value);
const json2 = JSON.parse(jsonInput2.value);
const delta = jsondiffpatch.diff(json1, json2);
if (!delta) {
resultContent.innerHTML = `
<div class="alert alert-success">
<i class="bi bi-check-circle-fill me-2"></i>
The JSON documents are identical!
</div>
`;
diffViewer.innerHTML = '';
} else {
resultContent.innerHTML = `
<div class="alert alert-info">
<i class="bi bi-info-circle-fill me-2"></i>
Differences found between the JSON documents
</div>
`;
diffViewer.innerHTML = jsondiffpatch.formatters.html.format(delta, json1);
}
resultBox.classList.add('show');
} catch (e) {
resultContent.innerHTML = `
<div class="alert alert-danger">
<i class="bi bi-exclamation-circle-fill me-2"></i>
Error comparing JSON: ${e.message}
</div>
`;
resultBox.classList.add('show');
diffViewer.innerHTML = '';
}
});
// Clear input
clearBtn.addEventListener('click', function() {
jsonInput1.value = '';
jsonInput2.value = '';
resultBox.classList.remove('show');
diffViewer.innerHTML = '';
});
});
</script>
@endpush
+577
View File
@@ -0,0 +1,577 @@
@extends('layouts.app')
@section('title', 'JSON Lint - Free Online JSON Validator and Formatter')
@push('styles')
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/jsoneditor@9.10.2/dist/jsoneditor.min.css" rel="stylesheet">
<style>
:root {
--primary-color: #4a6bff;
--primary-hover: #3a5bef;
}
body {
background-color: var(--bs-body-bg);
transition: background-color 0.3s ease;
}
.json-input {
min-height: 300px;
font-family: 'Courier New', monospace;
background-color: var(--bs-body-bg);
border: 1px solid var(--bs-border-color);
transition: all 0.3s ease;
}
.json-input:focus {
border-color: var(--primary-color);
box-shadow: 0 0 0 0.25rem rgba(74, 107, 255, 0.25);
}
.theme-switch {
cursor: pointer;
padding: 0.5rem;
border-radius: 50%;
transition: all 0.3s ease;
background-color: var(--bs-body-bg);
border: 1px solid var(--bs-border-color);
}
.theme-switch:hover {
background-color: var(--bs-border-color);
}
.result-box {
display: none;
animation: fadeIn 0.3s ease;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(-10px); }
to { opacity: 1; transform: translateY(0); }
}
.result-box.show {
display: block;
}
.tree-view-container {
height: 500px;
border: 1px solid var(--bs-border-color);
border-radius: 0.375rem;
margin-top: 1rem;
background-color: var(--bs-body-bg);
transition: all 0.3s ease;
overflow: auto;
}
/* Tree view animations */
.jsoneditor-tree {
transition: all 0.3s ease;
}
.jsoneditor-tree .jsoneditor-expandable {
transition: transform 0.3s ease;
}
.jsoneditor-tree .jsoneditor-expandable:hover {
transform: scale(1.02);
}
.jsoneditor-tree .jsoneditor-field {
transition: color 0.3s ease;
}
.jsoneditor-tree .jsoneditor-field:hover {
color: var(--primary-color);
}
.jsoneditor-tree .jsoneditor-value {
transition: color 0.3s ease;
}
.jsoneditor-tree .jsoneditor-value:hover {
color: var(--primary-color);
}
.jsoneditor-tree .jsoneditor-separator {
transition: opacity 0.3s ease;
}
.jsoneditor-tree .jsoneditor-separator:hover {
opacity: 0.8;
}
/* Collapsible node styles */
.jsoneditor-tree .jsoneditor-navigation-bar {
padding: 8px;
}
.jsoneditor-tree .jsoneditor-navigation-bar button {
transition: all 0.3s ease;
}
.jsoneditor-tree .jsoneditor-navigation-bar button:hover {
background-color: var(--bs-border-color);
}
/* Smooth collapse/expand animation */
.jsoneditor-tree .jsoneditor-expandable {
transition: all 0.3s ease;
}
.jsoneditor-tree .jsoneditor-expandable.collapsed {
opacity: 0.8;
}
.jsoneditor-tree .jsoneditor-expandable.expanded {
opacity: 1;
}
.nav-tabs {
margin-bottom: 1rem;
border-bottom: 1px solid var(--bs-border-color);
}
.nav-tabs .nav-link {
color: var(--bs-body-color);
border: none;
padding: 0.5rem 1rem;
transition: all 0.3s ease;
}
.nav-tabs .nav-link.active {
color: var(--primary-color);
border-bottom: 2px solid var(--primary-color);
background-color: transparent;
}
.nav-tabs .nav-link:hover {
color: var(--primary-color);
border-color: transparent;
}
.jsoneditor {
border: none !important;
}
.jsoneditor-menu {
background-color: var(--bs-body-bg) !important;
border-bottom: 1px solid var(--bs-border-color) !important;
}
.jsoneditor-navigation-bar {
background-color: var(--bs-body-bg) !important;
border-bottom: 1px solid var(--bs-border-color) !important;
}
.btn-primary {
background-color: var(--primary-color);
border-color: var(--primary-color);
}
.btn-primary:hover {
background-color: var(--primary-hover);
border-color: var(--primary-hover);
}
.card {
border: none;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
}
.card:hover {
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
}
.hero-section {
background: linear-gradient(135deg, var(--primary-color) 0%, #6a8eff 100%);
color: white;
padding: 3rem 0;
margin-bottom: 2rem;
border-radius: 0.5rem;
}
.feature-icon {
font-size: 2rem;
color: var(--primary-color);
margin-bottom: 1rem;
}
.feature-card {
text-align: center;
padding: 1.5rem;
border-radius: 0.5rem;
background-color: var(--bs-body-bg);
border: 1px solid var(--bs-border-color);
transition: all 0.3s ease;
}
.feature-card:hover {
transform: translateY(-5px);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.1);
}
</style>
@endpush
@section('content')
<div class="hero-section text-center">
<h1 class="display-4 fw-bold mb-3">JSON Lint Tool</h1>
<p class="lead mb-4">Validate, format, and beautify your JSON data with our powerful online tool</p>
</div>
<div class="row mb-4">
<div class="col-md-4 mb-3">
<div class="feature-card">
<i class="bi bi-check-circle feature-icon"></i>
<h3>Validate JSON</h3>
<p>Quickly check if your JSON data is valid and well-formed</p>
</div>
</div>
<div class="col-md-4 mb-3">
<div class="feature-card">
<i class="bi bi-code-slash feature-icon"></i>
<h3>Format JSON</h3>
<p>Automatically format and beautify your JSON for better readability</p>
</div>
</div>
<div class="col-md-4 mb-3">
<div class="feature-card">
<i class="bi bi-diagram-3 feature-icon"></i>
<h3>Tree View</h3>
<p>Visualize your JSON structure with an interactive tree view</p>
</div>
</div>
</div>
<div class="card shadow-sm">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center mb-3">
<h2 class="h4 mb-0">JSON Editor</h2>
</div>
<div class="mb-3">
<label for="jsonInput" class="form-label">Enter your JSON:</label>
<textarea class="form-control json-input" id="jsonInput" rows="10" placeholder='{
"example": "json",
"format": "here"
}'></textarea>
</div>
<div class="d-flex gap-2">
<button class="btn btn-primary" id="validateBtn">
<i class="bi bi-check-circle me-2"></i>Validate JSON
</button>
<button class="btn btn-outline-secondary" id="formatBtn">
<i class="bi bi-code-slash me-2"></i>Format JSON
</button>
<button class="btn btn-outline-secondary" id="shareBtn">
<i class="bi bi-share me-2"></i>Share
</button>
<button class="btn btn-outline-secondary" id="clearBtn">
<i class="bi bi-trash me-2"></i>Clear
</button>
</div>
</div>
</div>
<!-- New section for formatted JSON with tabs -->
<div class="card shadow-sm mt-4" id="formattedJsonBox">
<div class="card-body">
<h3 class="h5 card-title mb-3">Formatted JSON</h3>
<ul class="nav nav-tabs" id="jsonTabs" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="tree-tab" data-bs-toggle="tab" data-bs-target="#tree-view" type="button" role="tab">
<i class="bi bi-diagram-3 me-2"></i>Tree View
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="raw-tab" data-bs-toggle="tab" data-bs-target="#raw-view" type="button" role="tab">
<i class="bi bi-code me-2"></i>Raw JSON
</button>
</li>
</ul>
<div class="tab-content mt-3" id="jsonTabsContent">
<div class="tab-pane fade show active" id="tree-view" role="tabpanel">
<div class="tree-view-container" id="treeView"></div>
</div>
<div class="tab-pane fade" id="raw-view" role="tabpanel">
<pre class="tree-view-container" id="rawView"></pre>
</div>
</div>
</div>
</div>
<div class="mt-5">
<h2 class="h4 mb-3">About JSON Lint Tool</h2>
<div class="card">
<div class="card-body">
<p>Our JSON Lint Tool is a free online service that helps developers and data analysts work with JSON data more efficiently. Whether you're validating API responses, debugging JSON configurations, or just need to format your JSON data, our tool provides a simple and intuitive interface to get the job done.</p>
<h3 class="h5 mt-4">Key Features:</h3>
<ul>
<li>Real-time JSON validation</li>
<li>Automatic JSON formatting and beautification</li>
<li>Interactive tree view for easy navigation</li>
<li>Dark and light mode support</li>
<li>Mobile-friendly interface</li>
</ul>
<h3 class="h5 mt-4">What is JSON?</h3>
<p>JSON (JavaScript Object Notation) is a lightweight data-interchange format that is easy for humans to read and write and easy for machines to parse and generate. It is widely used for transmitting data between a server and web application, as well as for configuration files and data storage.</p>
</div>
</div>
</div>
@endsection
@push('scripts')
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jsoneditor@9.10.2/dist/jsoneditor.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
const jsonInput = document.getElementById('jsonInput');
const validateBtn = document.getElementById('validateBtn');
const formatBtn = document.getElementById('formatBtn');
const shareBtn = document.getElementById('shareBtn');
const clearBtn = document.getElementById('clearBtn');
const treeView = document.getElementById('treeView');
const rawView = document.getElementById('rawView');
const formattedJsonBox = document.getElementById('formattedJsonBox');
let editor = null;
function showError(message) {
const errorAlert = document.createElement('div');
errorAlert.className = 'alert alert-danger alert-dismissible fade show';
errorAlert.innerHTML = `
<i class="bi bi-exclamation-circle-fill me-2"></i>
${message}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
`;
formattedJsonBox.querySelector('.card-body').insertBefore(errorAlert, formattedJsonBox.querySelector('.nav-tabs'));
}
function showSuccess(message) {
const successAlert = document.createElement('div');
successAlert.className = 'alert alert-success alert-dismissible fade show';
successAlert.innerHTML = `
<i class="bi bi-check-circle-fill me-2"></i>
${message}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
`;
formattedJsonBox.querySelector('.card-body').insertBefore(successAlert, formattedJsonBox.querySelector('.nav-tabs'));
}
function updateTreeView(json) {
// Clear previous editor
if (editor) {
editor.destroy();
}
// Create new editor with enhanced options
const options = {
mode: 'tree',
modes: ['tree', 'view', 'form', 'code', 'text'],
theme: document.documentElement.getAttribute('data-bs-theme') === 'dark' ? 'ace/theme/monokai' : 'ace/theme/github',
enableSort: false,
enableTransform: false,
search: true,
history: true,
navigationBar: true,
statusBar: true,
mainMenuBar: true,
onChange: function() {
try {
const updatedJson = editor.get();
jsonInput.value = JSON.stringify(updatedJson, null, 2);
rawView.textContent = JSON.stringify(updatedJson, null, 2);
} catch (e) {
console.error('Error updating JSON:', e);
}
},
onNodeName: function(node) {
// Safely handle node animation
if (node && node.dom && node.dom.expandable) {
const expandable = node.dom.expandable;
expandable.classList.add('expanded');
setTimeout(() => {
expandable.classList.remove('expanded');
}, 300);
}
},
onEditable: function(node) {
return false; // Make the tree view read-only
}
};
editor = new JSONEditor(treeView, options);
// Add initial animation
setTimeout(() => {
const container = treeView.querySelector('.jsoneditor-tree');
if (container) {
container.style.opacity = '0';
container.style.transform = 'translateY(20px)';
setTimeout(() => {
container.style.opacity = '1';
container.style.transform = 'translateY(0)';
}, 100);
}
}, 100);
// Set the JSON after a small delay to ensure DOM is ready
setTimeout(() => {
editor.set(json);
}, 150);
// Update raw view
rawView.textContent = JSON.stringify(json, null, 2);
// Show the formatted JSON box
document.getElementById('formattedJsonBox').style.display = 'block';
}
// Hide formatted JSON box initially
document.getElementById('formattedJsonBox').style.display = 'none';
// Load saved JSON from local storage
const savedJson = localStorage.getItem('jsonlint_history');
if (savedJson) {
try {
const parsedJson = JSON.parse(savedJson);
jsonInput.value = JSON.stringify(parsedJson, null, 2);
updateTreeView(parsedJson);
} catch (e) {
console.error('Error loading saved JSON:', e);
}
}
// Save JSON to local storage
function saveToHistory() {
try {
const json = JSON.parse(jsonInput.value);
if (json && Object.keys(json).length > 0) {
localStorage.setItem('jsonlint_history', JSON.stringify(json));
}
} catch (e) {
console.error('Error saving JSON to history:', e);
}
}
// Generate shareable link
function generateShareLink() {
try {
const json = JSON.parse(jsonInput.value);
const jsonString = JSON.stringify(json);
const encodedJson = encodeURIComponent(jsonString);
const url = new URL(window.location.href);
url.searchParams.set('json', encodedJson);
return url.toString();
} catch (e) {
console.error('Error generating share link:', e);
return null;
}
}
// Share button click handler
shareBtn.addEventListener('click', function() {
const shareLink = generateShareLink();
if (shareLink) {
// Copy to clipboard
navigator.clipboard.writeText(shareLink).then(function() {
// Show success message
const originalText = shareBtn.innerHTML;
shareBtn.innerHTML = '<i class="bi bi-check-circle me-2"></i>Copied!';
setTimeout(function() {
shareBtn.innerHTML = originalText;
}, 2000);
}).catch(function(err) {
console.error('Error copying to clipboard:', err);
alert('Failed to copy link to clipboard. Please copy the URL manually.');
});
} else {
alert('Failed to generate share link. Please make sure your JSON is valid.');
}
});
// Validate JSON
validateBtn.addEventListener('click', function() {
try {
const json = JSON.parse(jsonInput.value);
showSuccess('Valid JSON!');
updateTreeView(json);
} catch (e) {
showError(`Invalid JSON: ${e.message}`);
formattedJsonBox.style.display = 'block';
if (editor) {
editor.destroy();
editor = null;
}
treeView.innerHTML = '';
rawView.textContent = '';
}
});
// Format JSON
formatBtn.addEventListener('click', function() {
try {
const json = JSON.parse(jsonInput.value);
jsonInput.value = JSON.stringify(json, null, 2);
showSuccess('JSON formatted successfully!');
updateTreeView(json);
} catch (e) {
showError(`Cannot format invalid JSON: ${e.message}`);
formattedJsonBox.style.display = 'block';
if (editor) {
editor.destroy();
editor = null;
}
treeView.innerHTML = '';
rawView.textContent = '';
}
});
// Clear input
clearBtn.addEventListener('click', function() {
jsonInput.value = '';
formattedJsonBox.style.display = 'none';
if (editor) {
editor.destroy();
editor = null;
}
treeView.innerHTML = '';
rawView.textContent = '';
localStorage.removeItem('jsonlint_history');
});
// Auto-save when input changes
jsonInput.addEventListener('input', function() {
try {
const json = JSON.parse(jsonInput.value);
if (json && Object.keys(json).length > 0) {
saveToHistory();
}
} catch (e) {
// Don't save invalid JSON
}
});
// Load JSON from URL if present
const urlParams = new URLSearchParams(window.location.search);
const jsonParam = urlParams.get('json');
if (jsonParam) {
try {
const decodedJson = decodeURIComponent(jsonParam);
const json = JSON.parse(decodedJson);
jsonInput.value = JSON.stringify(json, null, 2);
updateTreeView(json);
} catch (e) {
console.error('Error loading JSON from URL:', e);
}
}
});
</script>
@endpush
+356
View File
@@ -0,0 +1,356 @@
@extends('layouts.app')
@section('title', 'JSON Schema Validator - Free Online JSON Schema Validation Tool')
@push('styles')
<link href="https://cdn.jsdelivr.net/npm/jsoneditor@9.10.2/dist/jsoneditor.min.css" rel="stylesheet">
<style>
.json-input {
min-height: 300px;
font-family: 'Courier New', monospace;
background-color: var(--bs-body-bg);
border: 1px solid var(--bs-border-color);
transition: all 0.3s ease;
}
.json-input:focus {
border-color: var(--primary-color);
box-shadow: 0 0 0 0.25rem rgba(74, 107, 255, 0.25);
}
.result-box {
display: none;
animation: fadeIn 0.3s ease;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(-10px); }
to { opacity: 1; transform: translateY(0); }
}
.result-box.show {
display: block;
}
.tree-view-container {
height: 500px;
border: 1px solid var(--bs-border-color);
border-radius: 0.375rem;
margin-top: 1rem;
background-color: var(--bs-body-bg);
transition: all 0.3s ease;
}
.nav-tabs {
margin-bottom: 1rem;
border-bottom: 1px solid var(--bs-border-color);
}
.nav-tabs .nav-link {
color: var(--bs-body-color);
border: none;
padding: 0.5rem 1rem;
transition: all 0.3s ease;
}
.nav-tabs .nav-link.active {
color: var(--primary-color);
border-bottom: 2px solid var(--primary-color);
background-color: transparent;
}
.nav-tabs .nav-link:hover {
color: var(--primary-color);
border-color: transparent;
}
.jsoneditor {
border: none !important;
}
.jsoneditor-menu {
background-color: var(--bs-body-bg) !important;
border-bottom: 1px solid var(--bs-border-color) !important;
}
.jsoneditor-navigation-bar {
background-color: var(--bs-body-bg) !important;
border-bottom: 1px solid var(--bs-border-color) !important;
}
.hero-section {
background: linear-gradient(135deg, var(--primary-color) 0%, #6a8eff 100%);
color: white;
padding: 3rem 0;
margin-bottom: 2rem;
border-radius: 0.5rem;
}
.feature-icon {
font-size: 2rem;
color: var(--primary-color);
margin-bottom: 1rem;
}
.feature-card {
text-align: center;
padding: 1.5rem;
border-radius: 0.5rem;
background-color: var(--bs-body-bg);
border: 1px solid var(--bs-border-color);
transition: all 0.3s ease;
}
.feature-card:hover {
transform: translateY(-5px);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.1);
}
</style>
@endpush
@section('content')
<div class="hero-section text-center">
<h1 class="display-4 fw-bold mb-3">JSON Schema Validator</h1>
<p class="lead mb-4">Validate your JSON data against a JSON Schema</p>
</div>
<div class="row mb-4">
<div class="col-md-4 mb-3">
<div class="feature-card">
<i class="bi bi-file-earmark-check feature-icon"></i>
<h3>Schema Validation</h3>
<p>Validate your JSON data against a JSON Schema specification</p>
</div>
</div>
<div class="col-md-4 mb-3">
<div class="feature-card">
<i class="bi bi-code-slash feature-icon"></i>
<h3>Interactive Editor</h3>
<p>Edit both JSON and Schema in a user-friendly interface</p>
</div>
</div>
<div class="col-md-4 mb-3">
<div class="feature-card">
<i class="bi bi-lightning-charge feature-icon"></i>
<h3>Real-time Feedback</h3>
<p>Get instant validation results with detailed error messages</p>
</div>
</div>
</div>
<div class="card shadow-sm">
<div class="card-body">
<div class="row">
<div class="col-md-6 mb-3">
<label for="jsonInput" class="form-label">JSON Data:</label>
<textarea class="form-control json-input" id="jsonInput" rows="10" placeholder='{
"name": "John Doe",
"age": 30,
"email": "john@example.com"
}'></textarea>
</div>
<div class="col-md-6 mb-3">
<label for="schemaInput" class="form-label">JSON Schema:</label>
<textarea class="form-control json-input" id="schemaInput" rows="10" placeholder='{
"type": "object",
"properties": {
"name": { "type": "string" },
"age": { "type": "number" },
"email": { "type": "string", "format": "email" }
},
"required": ["name", "age", "email"]
}'></textarea>
</div>
</div>
<div class="d-flex gap-2">
<button class="btn btn-primary" id="validateBtn">
<i class="bi bi-check-circle me-2"></i>Validate
</button>
<button class="btn btn-outline-secondary" id="clearBtn">
<i class="bi bi-trash me-2"></i>Clear
</button>
</div>
</div>
</div>
<div class="card shadow-sm mt-4 result-box" id="resultBox">
<div class="card-body">
<h3 class="h5 card-title">Validation Result</h3>
<div id="resultContent"></div>
<ul class="nav nav-tabs" id="viewTabs" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="tree-tab" data-bs-toggle="tab" data-bs-target="#tree-view" type="button" role="tab">Tree View</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="raw-tab" data-bs-toggle="tab" data-bs-target="#raw-view" type="button" role="tab">Raw JSON</button>
</li>
</ul>
<div class="tab-content" id="viewTabsContent">
<div class="tab-pane fade show active" id="tree-view" role="tabpanel">
<div class="tree-view-container" id="treeView"></div>
</div>
<div class="tab-pane fade" id="raw-view" role="tabpanel">
<pre class="tree-view-container" id="rawView"></pre>
</div>
</div>
</div>
</div>
<div class="mt-5">
<h2 class="h4 mb-3">About JSON Schema Validation</h2>
<div class="card">
<div class="card-body">
<p>JSON Schema is a powerful tool for validating the structure of JSON data. It allows you to define the expected format, data types, and constraints for your JSON documents. Our JSON Schema Validator makes it easy to validate your JSON data against a schema specification.</p>
<h3 class="h5 mt-4">Key Features:</h3>
<ul>
<li>Validate JSON data against JSON Schema specifications</li>
<li>Interactive JSON and Schema editors</li>
<li>Detailed validation error messages</li>
<li>Tree view and raw JSON view options</li>
<li>Dark and light mode support</li>
</ul>
<h3 class="h5 mt-4">How to Use:</h3>
<ol>
<li>Enter or paste your JSON data in the left textarea</li>
<li>Enter or paste your JSON Schema in the right textarea</li>
<li>Click the "Validate" button to check if your JSON conforms to the schema</li>
<li>View the validation results and any error messages</li>
</ol>
<h3 class="h5 mt-4">Example Schema:</h3>
<pre class="bg-light p-3 rounded"><code>{
"type": "object",
"properties": {
"name": { "type": "string" },
"age": { "type": "number", "minimum": 0 },
"email": { "type": "string", "format": "email" }
},
"required": ["name", "age", "email"]
}</code></pre>
</div>
</div>
</div>
@endsection
@push('scripts')
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jsoneditor@9.10.2/dist/jsoneditor.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/ajv@8.12.0/dist/ajv.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
const validateBtn = document.getElementById('validateBtn');
const clearBtn = document.getElementById('clearBtn');
const jsonInput = document.getElementById('jsonInput');
const schemaInput = document.getElementById('schemaInput');
const resultBox = document.getElementById('resultBox');
const resultContent = document.getElementById('resultContent');
const treeView = document.getElementById('treeView');
const rawView = document.getElementById('rawView');
let editor = null;
const ajv = new Ajv();
function updateTreeView(json) {
// Clear previous editor
if (editor) {
editor.destroy();
}
// Create new editor
const options = {
mode: 'tree',
modes: ['tree', 'view', 'form', 'code', 'text'],
theme: document.documentElement.getAttribute('data-bs-theme') === 'dark' ? 'ace/theme/monokai' : 'ace/theme/github',
onChange: function() {
try {
const updatedJson = editor.get();
jsonInput.value = JSON.stringify(updatedJson, null, 2);
rawView.textContent = JSON.stringify(updatedJson, null, 2);
} catch (e) {
console.error('Error updating JSON:', e);
}
}
};
editor = new JSONEditor(treeView, options);
editor.set(json);
// Update raw view
rawView.textContent = JSON.stringify(json, null, 2);
}
// Validate JSON against Schema
validateBtn.addEventListener('click', function() {
try {
const json = JSON.parse(jsonInput.value);
const schema = JSON.parse(schemaInput.value);
// Compile schema
const validate = ajv.compile(schema);
const valid = validate(json);
if (valid) {
resultContent.innerHTML = `
<div class="alert alert-success">
<i class="bi bi-check-circle-fill me-2"></i>
JSON data is valid according to the schema!
</div>
`;
resultBox.classList.add('show');
updateTreeView(json);
} else {
const errors = validate.errors.map(error => {
return `<li>${error.instancePath || 'root'}: ${error.message}</li>`;
}).join('');
resultContent.innerHTML = `
<div class="alert alert-danger">
<i class="bi bi-exclamation-circle-fill me-2"></i>
JSON data is invalid according to the schema:
<ul class="mt-2 mb-0">${errors}</ul>
</div>
`;
resultBox.classList.add('show');
if (editor) {
editor.destroy();
editor = null;
}
treeView.innerHTML = '';
rawView.textContent = '';
}
} catch (e) {
resultContent.innerHTML = `
<div class="alert alert-danger">
<i class="bi bi-exclamation-circle-fill me-2"></i>
Error: ${e.message}
</div>
`;
resultBox.classList.add('show');
if (editor) {
editor.destroy();
editor = null;
}
treeView.innerHTML = '';
rawView.textContent = '';
}
});
// Clear input
clearBtn.addEventListener('click', function() {
jsonInput.value = '';
schemaInput.value = '';
resultBox.classList.remove('show');
if (editor) {
editor.destroy();
editor = null;
}
treeView.innerHTML = '';
rawView.textContent = '';
});
});
</script>
@endpush
+384
View File
@@ -0,0 +1,384 @@
@extends('layouts.app')
@section('title', 'JSON Templates - Common JSON Formats and Examples')
@push('styles')
<link href="https://cdn.jsdelivr.net/npm/jsoneditor@9.10.2/dist/jsoneditor.min.css" rel="stylesheet">
<style>
.template-card {
border: 1px solid var(--bs-border-color);
border-radius: 0.5rem;
transition: all 0.3s ease;
height: 100%;
}
.template-card:hover {
transform: translateY(-5px);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.1);
}
.template-card .card-body {
display: flex;
flex-direction: column;
}
.template-card .card-footer {
background: transparent;
border-top: 1px solid var(--bs-border-color);
}
.template-preview {
background-color: var(--bs-body-bg);
border: 1px solid var(--bs-border-color);
border-radius: 0.375rem;
padding: 1rem;
margin-top: 1rem;
max-height: 300px;
overflow-y: auto;
font-family: 'Courier New', monospace;
font-size: 0.875rem;
}
.template-icon {
font-size: 2rem;
color: var(--primary-color);
margin-bottom: 1rem;
}
.template-category {
margin-bottom: 2rem;
}
.template-category h2 {
margin-bottom: 1.5rem;
padding-bottom: 0.5rem;
border-bottom: 2px solid var(--primary-color);
}
.copy-btn {
cursor: pointer;
transition: all 0.3s ease;
}
.copy-btn:hover {
color: var(--primary-color);
}
.copy-btn.copied {
color: var(--bs-success);
}
.hero-section {
background: linear-gradient(135deg, var(--primary-color) 0%, #6a8eff 100%);
color: white;
padding: 3rem 0;
margin-bottom: 2rem;
border-radius: 0.5rem;
}
</style>
@endpush
@section('content')
<div class="hero-section text-center">
<h1 class="display-4 fw-bold mb-3">JSON Templates</h1>
<p class="lead mb-4">Common JSON formats and examples for various use cases</p>
</div>
<div class="template-category">
<h2 class="h4">API Responses</h2>
<div class="row">
<div class="col-md-6 mb-4">
<div class="card template-card">
<div class="card-body">
<i class="bi bi-cloud-arrow-down template-icon"></i>
<h3 class="h5">REST API Response</h3>
<p class="text-muted">Standard REST API response with status, data, and pagination</p>
<div class="template-preview">
<pre><code>{
"status": "success",
"code": 200,
"message": "Data retrieved successfully",
"data": {
"items": [
{
"id": 1,
"name": "Item 1",
"description": "Description of item 1"
},
{
"id": 2,
"name": "Item 2",
"description": "Description of item 2"
}
],
"pagination": {
"total": 100,
"per_page": 10,
"current_page": 1,
"last_page": 10
}
}
}</code></pre>
</div>
</div>
<div class="card-footer">
<button class="btn btn-link copy-btn" data-template="rest-api">
<i class="bi bi-clipboard me-2"></i>Copy Template
</button>
</div>
</div>
</div>
<div class="col-md-6 mb-4">
<div class="card template-card">
<div class="card-body">
<i class="bi bi-graph-up template-icon"></i>
<h3 class="h5">GraphQL Response</h3>
<p class="text-muted">GraphQL API response with nested data structure</p>
<div class="template-preview">
<pre><code>{
"data": {
"user": {
"id": "1",
"name": "John Doe",
"email": "john@example.com",
"posts": [
{
"id": "101",
"title": "First Post",
"content": "Content of the first post",
"comments": [
{
"id": "1001",
"text": "Great post!",
"author": {
"id": "2",
"name": "Jane Smith"
}
}
]
}
]
}
}
}</code></pre>
</div>
</div>
<div class="card-footer">
<button class="btn btn-link copy-btn" data-template="graphql">
<i class="bi bi-clipboard me-2"></i>Copy Template
</button>
</div>
</div>
</div>
</div>
</div>
<div class="template-category">
<h2 class="h4">Configuration Files</h2>
<div class="row">
<div class="col-md-6 mb-4">
<div class="card template-card">
<div class="card-body">
<i class="bi bi-gear template-icon"></i>
<h3 class="h5">Application Config</h3>
<p class="text-muted">Common application configuration settings</p>
<div class="template-preview">
<pre><code>{
"app": {
"name": "My Application",
"version": "1.0.0",
"environment": "production",
"debug": false
},
"database": {
"host": "localhost",
"port": 3306,
"name": "mydb",
"username": "user",
"password": "secret"
},
"logging": {
"level": "info",
"file": "app.log",
"max_size": "10MB"
},
"api": {
"base_url": "https://api.example.com",
"timeout": 30,
"retry_attempts": 3
}
}</code></pre>
</div>
</div>
<div class="card-footer">
<button class="btn btn-link copy-btn" data-template="app-config">
<i class="bi bi-clipboard me-2"></i>Copy Template
</button>
</div>
</div>
</div>
<div class="col-md-6 mb-4">
<div class="card template-card">
<div class="card-body">
<i class="bi bi-box template-icon"></i>
<h3 class="h5">Package.json</h3>
<p class="text-muted">Node.js package configuration</p>
<div class="template-preview">
<pre><code>{
"name": "my-package",
"version": "1.0.0",
"description": "A sample Node.js package",
"main": "index.js",
"scripts": {
"start": "node index.js",
"test": "jest",
"build": "webpack"
},
"dependencies": {
"express": "^4.17.1",
"lodash": "^4.17.21"
},
"devDependencies": {
"jest": "^27.0.6",
"webpack": "^5.50.0"
},
"author": "John Doe",
"license": "MIT"
}</code></pre>
</div>
</div>
<div class="card-footer">
<button class="btn btn-link copy-btn" data-template="package-json">
<i class="bi bi-clipboard me-2"></i>Copy Template
</button>
</div>
</div>
</div>
</div>
</div>
<div class="template-category">
<h2 class="h4">Data Structures</h2>
<div class="row">
<div class="col-md-6 mb-4">
<div class="card template-card">
<div class="card-body">
<i class="bi bi-person template-icon"></i>
<h3 class="h5">User Profile</h3>
<p class="text-muted">User profile data structure</p>
<div class="template-preview">
<pre><code>{
"id": "user123",
"username": "johndoe",
"email": "john@example.com",
"profile": {
"firstName": "John",
"lastName": "Doe",
"age": 30,
"gender": "male",
"location": {
"country": "USA",
"city": "New York"
}
},
"preferences": {
"theme": "dark",
"notifications": true,
"language": "en"
},
"createdAt": "2023-01-01T00:00:00Z",
"lastLogin": "2023-06-15T14:30:00Z"
}</code></pre>
</div>
</div>
<div class="card-footer">
<button class="btn btn-link copy-btn" data-template="user-profile">
<i class="bi bi-clipboard me-2"></i>Copy Template
</button>
</div>
</div>
</div>
<div class="col-md-6 mb-4">
<div class="card template-card">
<div class="card-body">
<i class="bi bi-cart template-icon"></i>
<h3 class="h5">E-commerce Order</h3>
<p class="text-muted">E-commerce order data structure</p>
<div class="template-preview">
<pre><code>{
"orderId": "ORD-2023-001",
"customer": {
"id": "CUST-001",
"name": "John Doe",
"email": "john@example.com",
"shippingAddress": {
"street": "123 Main St",
"city": "New York",
"state": "NY",
"zipCode": "10001",
"country": "USA"
}
},
"items": [
{
"productId": "PROD-001",
"name": "Product 1",
"quantity": 2,
"price": 29.99,
"total": 59.98
},
{
"productId": "PROD-002",
"name": "Product 2",
"quantity": 1,
"price": 49.99,
"total": 49.99
}
],
"subtotal": 109.97,
"tax": 10.99,
"shipping": 5.99,
"total": 126.95,
"status": "processing",
"createdAt": "2023-06-15T10:30:00Z"
}</code></pre>
</div>
</div>
<div class="card-footer">
<button class="btn btn-link copy-btn" data-template="ecommerce-order">
<i class="bi bi-clipboard me-2"></i>Copy Template
</button>
</div>
</div>
</div>
</div>
</div>
@endsection
@push('scripts')
<script>
document.addEventListener('DOMContentLoaded', function() {
const copyButtons = document.querySelectorAll('.copy-btn');
copyButtons.forEach(button => {
button.addEventListener('click', function() {
const template = this.getAttribute('data-template');
const templateContent = this.closest('.card').querySelector('pre code').textContent;
navigator.clipboard.writeText(templateContent).then(() => {
const originalText = this.innerHTML;
this.innerHTML = '<i class="bi bi-check2 me-2"></i>Copied!';
this.classList.add('copied');
setTimeout(() => {
this.innerHTML = originalText;
this.classList.remove('copied');
}, 2000);
}).catch(err => {
console.error('Failed to copy text: ', err);
});
});
});
});
</script>
@endpush
+135 -26
View File
@@ -1,36 +1,145 @@
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<html lang="en" data-bs-theme="light">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Free online JSON tools. Validate, format, and compare JSON documents with our easy-to-use tools. Perfect for developers and data analysts.">
<meta name="keywords" content="JSON validator, JSON formatter, JSON lint, JSON compare, JSON diff, JSON beautifier, JSON parser, JSON editor, JSON tool">
<meta name="author" content="JSON Tools">
<title>@yield('title', 'JSON Tools')</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css" rel="stylesheet">
@stack('styles')
<style>
:root {
--primary-color: #4a6bff;
--primary-hover: #3a5bef;
}
body {
background-color: var(--bs-body-bg);
transition: background-color 0.3s ease;
}
<title>{{ config('app.name', 'Laravel') }}</title>
.navbar {
background-color: var(--bs-body-bg);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
padding: 1rem 0;
}
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.bunny.net">
<link href="https://fonts.bunny.net/css?family=figtree:400,500,600&display=swap" rel="stylesheet" />
.navbar-brand {
font-weight: bold;
color: var(--primary-color) !important;
}
<!-- Scripts -->
@vite(['resources/css/app.css', 'resources/js/app.js'])
.nav-link {
color: var(--bs-body-color);
transition: all 0.3s ease;
padding: 0.5rem 1rem;
border-radius: 0.375rem;
}
.nav-link:hover {
color: var(--primary-color);
background-color: rgba(74, 107, 255, 0.1);
}
.nav-link.active {
color: var(--primary-color);
background-color: rgba(74, 107, 255, 0.1);
}
.theme-switch {
cursor: pointer;
padding: 0.5rem;
border-radius: 50%;
transition: all 0.3s ease;
background-color: var(--bs-body-bg);
border: 1px solid var(--bs-border-color);
margin-left: 1rem;
}
.theme-switch:hover {
background-color: var(--bs-border-color);
}
.container {
padding-top: 2rem;
}
@yield('styles')
</style>
</head>
<body class="font-sans antialiased">
<div class="min-h-screen bg-gray-100 dark:bg-gray-900">
@include('layouts.navigation')
<body>
<nav class="navbar navbar-expand-lg">
<div class="container">
<a class="navbar-brand" href="/">
<i class="bi bi-code-square me-2"></i>
JSON Tools
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav me-auto">
<li class="nav-item">
<a class="nav-link {{ request()->is('jsonlint') ? 'active' : '' }}" href="{{ url('/jsonlint') }}">
<i class="bi bi-code-slash me-2"></i>JSON Lint
</a>
</li>
<li class="nav-item">
<a class="nav-link {{ request()->is('jsoncompare') ? 'active' : '' }}" href="{{ url('/jsoncompare') }}">
<i class="bi bi-arrows-angle-contract me-2"></i>JSON Compare
</a>
</li>
<li class="nav-item">
<a class="nav-link {{ request()->is('jsonschema') ? 'active' : '' }}" href="{{ url('/jsonschema') }}">
<i class="bi bi-file-earmark-check me-2"></i>JSON Schema
</a>
</li>
<li class="nav-item">
<a class="nav-link {{ request()->is('jsontemplates') ? 'active' : '' }}" href="{{ url('/jsontemplates') }}">
<i class="bi bi-file-earmark-text me-2"></i>JSON Templates
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ route('api') }}">API</a>
</li>
</ul>
<button class="theme-switch" id="themeSwitch" title="Toggle dark/light mode">
<i class="bi bi-moon-fill"></i>
</button>
</div>
</div>
</nav>
<!-- Page Heading -->
@isset($header)
<header class="bg-white dark:bg-gray-800 shadow">
<div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
{{ $header }}
</div>
</header>
@endisset
<!-- Page Content -->
<main>
{{ $slot }}
</main>
<div class="container">
@yield('content')
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
const themeSwitch = document.getElementById('themeSwitch');
const html = document.documentElement;
// Check for saved theme preference
const savedTheme = localStorage.getItem('theme');
if (savedTheme) {
html.setAttribute('data-bs-theme', savedTheme);
themeSwitch.innerHTML = savedTheme === 'dark' ? '<i class="bi bi-sun-fill"></i>' : '<i class="bi bi-moon-fill"></i>';
}
// Theme switching
themeSwitch.addEventListener('click', function() {
const isDark = html.getAttribute('data-bs-theme') === 'dark';
const newTheme = isDark ? 'light' : 'dark';
html.setAttribute('data-bs-theme', newTheme);
themeSwitch.innerHTML = isDark ? '<i class="bi bi-moon-fill"></i>' : '<i class="bi bi-sun-fill"></i>';
localStorage.setItem('theme', newTheme);
});
});
</script>
@stack('scripts')
</body>
</html>