Skip to content

Commit 3c0016c

Browse files
Add JSON Path Viewer & Copy feature to JSON viewer
Introduces a modal popup for viewing and copying the full JSON path, type, and value of any property in the JSON viewer. Includes: - New JsonPathInfo model for path metadata - JsonPathDisplay.razor modal component with copy support and keyboard shortcuts - Clickable property names in JsonViewer with JS interop for event handling - Fullscreen and modal overlay compatibility - New icons and CSS for enhanced UX - Documentation for feature usage and integration
1 parent 87dde02 commit 3c0016c

File tree

9 files changed

+1105
-16
lines changed

9 files changed

+1105
-16
lines changed

JSON_PATH_FEATURE_README.md

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# 🎯 JSON Path Viewer & Copy Feature
2+
3+
## ✅ فایل‌های اضافه شده
4+
5+
### 1️⃣ Model
6+
- **`src/Component/Models/JsonPathInfo.cs`**
7+
- Model برای نگهداری اطلاعات JSON Path
8+
- Properties: Path, PropertyName, PropertyValue, PropertyType, IsSelected, Level
9+
10+
### 2️⃣ Component
11+
- **`src/Component/Core/Features/JsonPathDisplay.razor`**
12+
- Component نمایش JSON Path با UI زیبا
13+
- نمایش Path، Property Name، Type و Value
14+
- دکمه Copy با feedback
15+
16+
- **`src/Component/Core/Features/JsonPathDisplay.razor.css`**
17+
- استایل‌های کامل برای JsonPathDisplay
18+
- پشتیبانی Dark/Light Theme
19+
- Responsive و با Animation
20+
21+
### 3️⃣ CSS Enhancement
22+
- **`src/Component/Core/JsonViewer.razor.css`**
23+
- استایل clickable برای property names
24+
- Hover effects با رنگ primary
25+
26+
## 📋 مراحل باقیمانده برای تکمیل فیچر
27+
28+
### ⚠️ نیاز به انجام:
29+
30+
1. **اضافه کردن به JsonViewer.razor:**
31+
- اضافه کردن `JsonPathDisplay` component
32+
- اضافه کردن متغیر `currentJsonPath`
33+
- اضافه کردن JavaScript handler برای کلیک
34+
- اضافه کردن متدهای محاسبه JSON Path
35+
36+
2. **تغییر در rendering:**
37+
- اضافه کردن `clickable-property` class به property names
38+
- اضافه کردن `data-line-index` و `data-property-name` attributes
39+
40+
## 🎨 نحوه کار فیچر
41+
42+
1. کاربر روی یک property name کلیک می‌کند
43+
2. JavaScript event را catch می‌کند و به C# منتقل می‌کند
44+
3. متد `OnPropertyClick` صدا زده می‌شود
45+
4. JSON Path محاسبه می‌شود (مثل `$.user.profile.name`)
46+
5. یک popup در گوشه صفحه نمایش داده می‌شود با:
47+
- JSON Path کامل
48+
- نام Property
49+
- نوع داده (String, Number, Object, ...)
50+
- مقدار Property
51+
- دکمه Copy
52+
53+
## 🚀 مثال استفاده
54+
55+
```json
56+
{
57+
"user": {
58+
"profile": {
59+
"name": "John",
60+
"age": 30
61+
}
62+
}
63+
}
64+
```
65+
66+
وقتی کاربر روی `"name"` کلیک کنه:
67+
- **Path**: `$.user.profile.name`
68+
- **Property**: `name`
69+
- **Type**: `String`
70+
- **Value**: `John`
71+
72+
## 📦 وضعیت فعلی
73+
74+
**کامل شده:**
75+
- Model (JsonPathInfo)
76+
- UI Component (JsonPathDisplay)
77+
- CSS و Styling
78+
- Structure آماده است
79+
80+
⚠️ **نیاز به تکمیل:**
81+
- Integration با JsonViewer
82+
- JavaScript event handlers
83+
- متدهای محاسبه Path
84+
85+
## 🔧 کدهای آماده برای Integration
86+
87+
تمام کدهای لازم نوشته شده و آماده است فقط باید به JsonViewer اضافه شوند.
88+
89+
---
90+
91+
**تاریخ:** 2025
92+
**وضعیت:** آماده برای Integration
93+
**نسخه:** v1.0

src/Blazor.Demo/wwwroot/css/app.css

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,6 @@ html, body {
296296
padding: 4px;
297297
border: 1px solid var(--border-color);
298298
box-shadow: var(--shadow-glow);
299-
min-height: 500px;
300299
overflow: hidden;
301300
margin-bottom: 24px;
302301
transition: all 0.3s ease;

src/Component/Core/Features/FullScreenToggle.razor

Lines changed: 104 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@
4040
originalBodyPosition: null,
4141
originalBodyWidth: null,
4242
originalBodyHeight: null,
43+
originalCardStyle: null,
44+
originalCardBodyStyle: null,
45+
originalRowStyle: null,
46+
originalColStyle: null,
47+
originalParent: null,
48+
originalNextSibling: null,
4349
scrollPosition: 0,
4450
isFullScreen: false
4551
};
@@ -50,7 +56,10 @@
5056
5157
if (!container || state.isFullScreen) return;
5258
59+
// Store original styles and DOM position
5360
state.originalContainerStyle = container.getAttribute('style') || '';
61+
state.originalParent = container.parentNode;
62+
state.originalNextSibling = container.nextSibling;
5463
state.originalBodyOverflow = document.body.style.overflow;
5564
state.originalBodyPosition = document.body.style.position;
5665
state.originalBodyWidth = document.body.style.width;
@@ -59,16 +68,56 @@
5968
6069
const backgroundColor = isDarkTheme ? '#36363e' : '#ffffff';
6170
71+
// Move container to body to escape parent constraints
72+
document.body.appendChild(container);
73+
74+
// Apply fullscreen styles
6275
container.classList.add('fullscreen-active');
6376
container.style.backgroundColor = backgroundColor;
64-
77+
container.style.position = 'fixed';
78+
container.style.top = '0';
79+
container.style.left = '0';
80+
container.style.width = '100vw';
81+
container.style.height = '100vh';
82+
container.style.zIndex = '9999';
83+
container.style.margin = '0';
84+
container.style.padding = '0';
85+
container.style.border = 'none';
86+
container.style.borderRadius = '0';
87+
container.style.boxShadow = 'none';
88+
89+
// Lock body scroll
6590
document.body.style.overflow = 'hidden';
6691
document.body.style.position = 'fixed';
6792
document.body.style.width = '100%';
6893
document.body.style.height = '100%';
94+
document.body.style.top = '0';
95+
document.body.style.left = '0';
6996
document.body.classList.add('fullscreen-mode');
7097
document.documentElement.classList.add('fullscreen-active');
7198
99+
// Move JsonPathDisplay modal to body if it exists
100+
const pathModal = document.querySelector('.path-modal-overlay');
101+
if (pathModal && pathModal.parentNode !== document.body) {
102+
if (!pathModal._originalParent) {
103+
pathModal._originalParent = pathModal.parentNode;
104+
pathModal._originalNextSibling = pathModal.nextSibling;
105+
}
106+
document.body.appendChild(pathModal);
107+
console.log('✅ Moved existing JsonPathDisplay modal to body for fullscreen compatibility');
108+
}
109+
110+
// Move JsonStatistics modal to body if it exists
111+
const statsModal = document.querySelector('.stats-modal-overlay');
112+
if (statsModal && statsModal.parentNode !== document.body) {
113+
if (!statsModal._originalParent) {
114+
statsModal._originalParent = statsModal.parentNode;
115+
statsModal._originalNextSibling = statsModal.nextSibling;
116+
}
117+
document.body.appendChild(statsModal);
118+
console.log('✅ Moved existing JsonStatistics modal to body for fullscreen compatibility');
119+
}
120+
72121
state.isFullScreen = true;
73122
console.log('✅ Entered FullScreen Mode');
74123
};
@@ -79,35 +128,88 @@
79128
80129
if (!container || !state.isFullScreen) return;
81130
131+
// Remove fullscreen class
82132
container.classList.remove('fullscreen-active');
83133
84-
if (state.originalContainerStyle !== null) {
134+
// Restore container styles
135+
if (state.originalContainerStyle !== null && state.originalContainerStyle !== '') {
85136
container.setAttribute('style', state.originalContainerStyle);
137+
} else {
138+
container.removeAttribute('style');
86139
}
87140
141+
// Move container back to original position
142+
if (state.originalParent) {
143+
if (state.originalNextSibling) {
144+
state.originalParent.insertBefore(container, state.originalNextSibling);
145+
} else {
146+
state.originalParent.appendChild(container);
147+
}
148+
}
149+
150+
// Restore body styles
88151
if (state.originalBodyOverflow !== null) {
89152
document.body.style.overflow = state.originalBodyOverflow;
153+
} else {
154+
document.body.style.overflow = '';
90155
}
91156
if (state.originalBodyPosition !== null) {
92157
document.body.style.position = state.originalBodyPosition;
158+
} else {
159+
document.body.style.position = '';
93160
}
94161
if (state.originalBodyWidth !== null) {
95162
document.body.style.width = state.originalBodyWidth;
163+
} else {
164+
document.body.style.width = '';
96165
}
97166
if (state.originalBodyHeight !== null) {
98167
document.body.style.height = state.originalBodyHeight;
168+
} else {
169+
document.body.style.height = '';
99170
}
171+
document.body.style.top = '';
172+
document.body.style.left = '';
100173
101174
document.body.classList.remove('fullscreen-mode');
102175
document.documentElement.classList.remove('fullscreen-active');
103176
177+
// Restore JsonPathDisplay modal to original position if it was moved to body
178+
const pathModal = document.querySelector('.path-modal-overlay');
179+
if (pathModal && pathModal._originalParent) {
180+
if (pathModal._originalNextSibling) {
181+
pathModal._originalParent.insertBefore(pathModal, pathModal._originalNextSibling);
182+
} else {
183+
pathModal._originalParent.appendChild(pathModal);
184+
}
185+
pathModal._originalParent = null;
186+
pathModal._originalNextSibling = null;
187+
console.log('✅ Restored JsonPathDisplay modal to original position after exiting fullscreen');
188+
}
189+
190+
// Restore JsonStatistics modal to original position if it was moved to body
191+
const statsModal = document.querySelector('.stats-modal-overlay');
192+
if (statsModal && statsModal._originalParent) {
193+
if (statsModal._originalNextSibling) {
194+
statsModal._originalParent.insertBefore(statsModal, statsModal._originalNextSibling);
195+
} else {
196+
statsModal._originalParent.appendChild(statsModal);
197+
}
198+
statsModal._originalParent = null;
199+
statsModal._originalNextSibling = null;
200+
console.log('✅ Restored JsonStatistics modal to original position after exiting fullscreen');
201+
}
202+
104203
window.scrollTo(0, state.scrollPosition);
105204
205+
// Reset state
106206
state.originalContainerStyle = null;
107207
state.originalBodyOverflow = null;
108208
state.originalBodyPosition = null;
109209
state.originalBodyWidth = null;
110210
state.originalBodyHeight = null;
211+
state.originalParent = null;
212+
state.originalNextSibling = null;
111213
state.scrollPosition = 0;
112214
state.isFullScreen = false;
113215

0 commit comments

Comments
 (0)