vida
This commit is contained in:
parent
25270f4772
commit
efed275353
Binary file not shown.
@ -368,8 +368,27 @@
|
||||
<div class="clr-col-12">
|
||||
<h5>Customer Details:</h5>
|
||||
<p><strong>Name:</strong> {{ rowSelected.name }}</p>
|
||||
<p><strong>Phone:</strong> {{ rowSelected.phone }}</p>
|
||||
<p><strong>Active:</strong> {{ rowSelected.active }}</p>
|
||||
<p><strong>Visa Entry Type:</strong> {{ rowSelected.visa_entry_typename }}</p>
|
||||
<p><strong>Visa Duration:</strong> {{ rowSelected.visa_durationname }}</p>
|
||||
<p><strong>Visa Processing:</strong> {{ rowSelected.visa_processingname }}</p>
|
||||
<p><strong>Travel Start Date:</strong> {{ rowSelected.travel_start_date }}</p>
|
||||
<p><strong>Travel End Date:</strong> {{ rowSelected.travel_end_date }}</p>
|
||||
<p><strong>Passport Number:</strong> {{ rowSelected.passport_number }}</p>
|
||||
<p><strong>Passport Issue Date:</strong> {{ rowSelected.passport_issue_date }}</p>
|
||||
<p><strong>Passport Expiry Date:</strong> {{ rowSelected.passport_expiry_date }}</p>
|
||||
<p><strong>Email:</strong> {{ rowSelected.email }}</p>
|
||||
<p><strong>Phone Number:</strong> {{ rowSelected.phone_number }}</p>
|
||||
<p><strong>Birth Place:</strong> {{ rowSelected.birth_place }}</p>
|
||||
<p><strong>Date of Birth:</strong> {{ rowSelected.date_of_birth }}</p>
|
||||
<p><strong>Gender:</strong> {{ rowSelected.gendername }}</p>
|
||||
<p><strong>Profession:</strong> {{ rowSelected.profession }}</p>
|
||||
<p><strong>Visa Cost:</strong> {{ rowSelected.visa_cost }}</p>
|
||||
<p><strong>Referrer:</strong> {{ rowSelected.referrername }}</p>
|
||||
<p><strong>Nationality:</strong> {{ rowSelected.nationalityname }}</p>
|
||||
<p><strong>Supplier:</strong> {{ rowSelected.suppliername }}</p>
|
||||
<p><strong>Agent:</strong> {{ rowSelected.agentname }}</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -114,6 +114,24 @@ export class EditstepperComponent implements OnInit {
|
||||
agent: [null],
|
||||
|
||||
});
|
||||
|
||||
|
||||
this.getallvisa_entry_type();
|
||||
|
||||
this.getallvisa_duration();
|
||||
|
||||
this.getallvisa_processing();
|
||||
|
||||
this.getallgender();
|
||||
|
||||
this.getallreferrer();
|
||||
|
||||
this.getallnationality();
|
||||
|
||||
this.getallsupplier();
|
||||
|
||||
this.getallagent();
|
||||
|
||||
}
|
||||
|
||||
// Change to Horizontal Layout
|
||||
@ -207,6 +225,8 @@ export class EditstepperComponent implements OnInit {
|
||||
this.toastr.error("Not Added");
|
||||
}
|
||||
});
|
||||
this.rowSelected = this.entryForm.value;
|
||||
|
||||
setTimeout(() => {
|
||||
this.ngOnInit();
|
||||
}, 500);
|
||||
@ -330,11 +350,51 @@ export class EditstepperComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
updategender(gender: string): void {
|
||||
this.entryForm.get('gender').setValue(gender);
|
||||
}
|
||||
|
||||
updategenderEdit(gender: string): void { this.rowSelected.gender = gender }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
rsModaldescription = false;
|
||||
goToReplaceStringdescription(row) {
|
||||
this.rowSelected = row; this.rsModaldescription = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
selectvisa_entry_type;
|
||||
getallvisa_entry_type() {
|
||||
this.mainService.getAllvisa_entry_type().subscribe(data => {
|
||||
this.selectvisa_entry_type = data;
|
||||
console.log(data);
|
||||
}, (error) => { console.log(error); });
|
||||
}
|
||||
|
||||
selectvisa_duration;
|
||||
getallvisa_duration() {
|
||||
this.mainService.getAllvisa_duration().subscribe(data => {
|
||||
this.selectvisa_duration = data;
|
||||
console.log(data);
|
||||
}, (error) => { console.log(error); });
|
||||
}
|
||||
|
||||
selectvisa_processing;
|
||||
getallvisa_processing() {
|
||||
this.mainService.getAllvisa_processing().subscribe(data => {
|
||||
this.selectvisa_processing = data;
|
||||
console.log('visa processing ', data);
|
||||
}, (error) => { console.log(error); });
|
||||
}
|
||||
|
||||
isValidemail(email: string): boolean {
|
||||
const emailPattern = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
|
||||
return emailPattern.test(email);
|
||||
@ -349,13 +409,14 @@ export class EditstepperComponent implements OnInit {
|
||||
|
||||
|
||||
|
||||
updategender(gender: string): void {
|
||||
this.entryForm.get('gender').setValue(gender);
|
||||
selectgender;
|
||||
getallgender() {
|
||||
this.mainService.getAllgender().subscribe(data => {
|
||||
this.selectgender = data;
|
||||
console.log(data);
|
||||
}, (error) => { console.log(error); });
|
||||
}
|
||||
|
||||
updategenderEdit(gender: string): void { this.rowSelected.gender = gender }
|
||||
|
||||
|
||||
|
||||
|
||||
//currency field start
|
||||
@ -366,4 +427,37 @@ export class EditstepperComponent implements OnInit {
|
||||
this.rowSelected.visa_cost = this.rowSelected.visa_cost?.replace(/,/g, '');
|
||||
}
|
||||
//currency field end
|
||||
|
||||
selectreferrer;
|
||||
getallreferrer() {
|
||||
this.mainService.getAllreferrer().subscribe(data => {
|
||||
this.selectreferrer = data;
|
||||
console.log(data);
|
||||
}, (error) => { console.log(error); });
|
||||
}
|
||||
|
||||
selectnationality;
|
||||
getallnationality() {
|
||||
this.mainService.getAllnationality().subscribe(data => {
|
||||
this.selectnationality = data;
|
||||
console.log(data);
|
||||
}, (error) => { console.log(error); });
|
||||
}
|
||||
|
||||
selectsupplier;
|
||||
getallsupplier() {
|
||||
this.mainService.getAllsupplier().subscribe(data => {
|
||||
this.selectsupplier = data;
|
||||
console.log(data);
|
||||
}, (error) => { console.log(error); });
|
||||
}
|
||||
|
||||
selectagent;
|
||||
getallagent() {
|
||||
this.mainService.getAllagent().subscribe(data => {
|
||||
this.selectagent = data;
|
||||
console.log(data);
|
||||
}, (error) => { console.log(error); });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -19,9 +19,6 @@
|
||||
<clr-icon shape="plus"></clr-icon>ADD
|
||||
</button>
|
||||
|
||||
<button id="add" class="btn btn-primary" (click)="gotositebuilder()">
|
||||
<clr-icon shape="plus"></clr-icon>SiteBuilder
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<ng-container *ngIf="!isCardview"> <!-- GET ALL --> <clr-datagrid [clrDgLoading]="loading"
|
||||
|
||||
@ -197,49 +197,6 @@ export class Visa_applicationComponent implements OnInit {
|
||||
onUpdate(id) {
|
||||
this.modalEdit = false;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//console.log("in update");
|
||||
console.log("id " + id);
|
||||
console.log(this.rowSelected);
|
||||
@ -255,48 +212,6 @@ export class Visa_applicationComponent implements OnInit {
|
||||
}, 500);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}, (error) => {
|
||||
console.log(error);
|
||||
if (error.status >= 200 && error.status <= 299) {
|
||||
@ -463,9 +378,6 @@ export class Visa_applicationComponent implements OnInit {
|
||||
// updateaction
|
||||
|
||||
|
||||
gotositebuilder() {
|
||||
this.router.navigate(["/cns-portal/SiteBuilder"]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@ import { environment } from 'src/environments/environment';
|
||||
})
|
||||
export class SiteTreeservice {
|
||||
private baseURL = "SiteTree/SiteTree";
|
||||
private dlfbaseURL = environment.builderUrl+"/entityBuilder";
|
||||
private dlfbaseURL = environment.builderUrl + "/entityBuilder";
|
||||
private nodeURL = environment.nodeUrl;
|
||||
|
||||
|
||||
@ -52,7 +52,7 @@ export class SiteTreeservice {
|
||||
}
|
||||
|
||||
createHtmlPages(data: any, projId: number): Observable<any> {
|
||||
return this.apiRequest.post(`sureops/createFile?projId=` + projId, data);
|
||||
return this.apiRequest.post(`sureops/deploy?projId=` + projId, data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
@ -49,6 +49,8 @@
|
||||
|
||||
|
||||
<!-- 🔁 Regenerate Button at top of wireframe page -->
|
||||
<!-- part 2 code -->
|
||||
<!--
|
||||
<div style="text-align: right; margin: 10px 0;">
|
||||
<button (click)="regenerateAllModifiedSections()"
|
||||
style="background: orange; color: white; border: none; padding: 8px 14px; border-radius: 4px; cursor: pointer;">
|
||||
@ -73,11 +75,121 @@
|
||||
<button (click)="copyToClipboard(pageName)">📋</button>
|
||||
<button (click)="downloadHtml(pageName)">⬇️</button>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<!-- ✅ Render whole page in one block -->
|
||||
<div class="canvas-section">
|
||||
<!-- <div class="canvas-section">
|
||||
<div [innerHTML]="pageSections[pageName]['FullPage']"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
|
||||
<!-- part 3 -->
|
||||
<!-- 🔁 Regenerate + Save Buttons -->
|
||||
<div style="display: flex; justify-content: space-between; margin-bottom: 10px;">
|
||||
<div>
|
||||
<button (click)="regenerateAllModifiedSections()" style="background: orange; color: white; border: none; padding: 8px 14px; border-radius: 4px; cursor: pointer;">
|
||||
♻️ Regenerate Modified
|
||||
</button>
|
||||
<button (click)="uploadHtmlFiles(37388)" style="background: green; color: white; border: none; padding: 8px 14px; border-radius: 4px; cursor: pointer;">
|
||||
💾 Save All HTML Files
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<!-- Global Style Controls -->
|
||||
<select [(ngModel)]="liveStyles.fontSize">
|
||||
<option value="">Font Size</option>
|
||||
<option *ngFor="let size of ['12px', '14px', '16px', '18px', '20px', '24px', '28px']" [value]="size">{{ size }}</option>
|
||||
</select>
|
||||
|
||||
<select [(ngModel)]="liveStyles.fontWeight">
|
||||
<option value="">Font Weight</option>
|
||||
<option *ngFor="let weight of ['normal', 'bold', 'lighter']" [value]="weight">{{ weight }}</option>
|
||||
</select>
|
||||
|
||||
<select [(ngModel)]="liveStyles.textAlign">
|
||||
<option value="">Align</option>
|
||||
<option value="left">Left</option>
|
||||
<option value="center">Center</option>
|
||||
<option value="right">Right</option>
|
||||
</select>
|
||||
|
||||
<input type="color" [(ngModel)]="liveStyles.color" title="Text Color" />
|
||||
<input type="color" [(ngModel)]="liveStyles.background" title="Background Color" />
|
||||
|
||||
<button (click)="applyStyleToSelection()" style="background: #555; color: white; padding: 6px 10px; border-radius: 4px;">🎨 Apply Style</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Navbar Link Manager -->
|
||||
<!-- <div *ngIf="selectedNavbarPage" class="navbar-link-manager">
|
||||
<h3>🔗 Navbar Link Manager ({{ selectedNavbarPage }})</h3>
|
||||
|
||||
<ul>
|
||||
<li *ngFor="let link of navbarLinks[selectedNavbarPage]; let i = index">
|
||||
<input [(ngModel)]="link.label" placeholder="Link Label" />
|
||||
<select [(ngModel)]="link.href">
|
||||
<option *ngFor="let page of availablePages" [value]="page.href">{{ page.label }}</option>
|
||||
</select>
|
||||
<button (click)="removeLink(selectedNavbarPage, i)">❌</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<button (click)="addLink(selectedNavbarPage)">➕ Add Link</button>
|
||||
<button (click)="applyNavbarChanges(selectedNavbarPage)">✅ Apply Changes</button>
|
||||
</div> -->
|
||||
|
||||
|
||||
<!-- 🔗 Navbar Link Editor Modal -->
|
||||
<div *ngIf="selectedNavbarPage" class="navbar-popup-overlay">
|
||||
<div class="navbar-popup-content">
|
||||
<h3>🔗 Navbar Link Manager ({{ selectedNavbarPage }})</h3>
|
||||
|
||||
<ul>
|
||||
<li *ngFor="let link of navbarLinks[selectedNavbarPage]; let i = index">
|
||||
<input [(ngModel)]="link.label" placeholder="Link Label" />
|
||||
<select [(ngModel)]="link.href">
|
||||
<option *ngFor="let page of availablePages" [value]="page.href">{{ page.label }}</option>
|
||||
</select>
|
||||
<button (click)="removeLink(selectedNavbarPage, i)">❌</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div style="margin-top: 10px;">
|
||||
<button (click)="addLink(selectedNavbarPage)">➕ Add Link</button>
|
||||
<button (click)="applyNavbarChanges(selectedNavbarPage)">✅ Apply</button>
|
||||
<button (click)="selectedNavbarPage = null">❌ Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- ✅ Pages List -->
|
||||
<div class="canvas-wrapper">
|
||||
<div class="canvas-page" *ngFor="let pageName of pageRenderOrder">
|
||||
<div class="canvas-header">
|
||||
<button (click)="regenerateWireframe(pageName)">♻️</button>
|
||||
<h3 (click)="selectNavbar(pageName)" style="cursor: pointer;">
|
||||
{{ pageName }} <span title="Edit Navbar">🧭</span>
|
||||
</h3>
|
||||
|
||||
<div class="canvas-actions">
|
||||
<button (click)="copyToClipboard(pageName)">📋</button>
|
||||
<button (click)="downloadHtml(pageName)">⬇️</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ✅ Render and Edit Section -->
|
||||
<div class="canvas-section">
|
||||
<div [innerHTML]="pageSections[pageName]?.FullPage"
|
||||
|
||||
contenteditable="true"
|
||||
class="editable-html"
|
||||
(blur)="onEdit(pageName, $event)">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -64,3 +64,29 @@
|
||||
border-radius: 6px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
|
||||
.editable-html:focus {
|
||||
outline: 2px solid #007bff;
|
||||
background: #fcfcfc;
|
||||
}
|
||||
.navbar-popup-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0,0,0,0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.navbar-popup-content {
|
||||
background: white;
|
||||
padding: 20px;
|
||||
width: 500px;
|
||||
max-width: 90%;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
@ -5,24 +5,31 @@ import { ActivatedRoute } from '@angular/router';
|
||||
import { SiteTreeservice } from '../SiteBuilderGrid/SiteTree.service';
|
||||
import { COMMON_CSS } from './common-css';
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
import * as sha256 from 'crypto-js/sha256';
|
||||
import SHA256 from 'crypto-js/sha256';
|
||||
import { trigger, transition, style, animate, state } from '@angular/animations';
|
||||
// Make sure path is correct
|
||||
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-wireframe-renderer',
|
||||
templateUrl: './wireframe-renderer.component.html',
|
||||
styleUrls: ['./wireframe-renderer.component.scss']
|
||||
styleUrls: ['./wireframe-renderer.component.scss'],
|
||||
})
|
||||
|
||||
|
||||
export class WireframeRendererComponent implements OnInit {
|
||||
@Input() node: any;
|
||||
@Input() title: string = '';
|
||||
commonCss: string = COMMON_CSS;
|
||||
|
||||
|
||||
|
||||
jsonInput = '';
|
||||
initialPrompt = '';
|
||||
|
||||
id: number;
|
||||
allPagePrompts: Record<string, Record<string, string>> = {};
|
||||
initialGeneratedPrompts: Record<string, Record<string, string>> = {};
|
||||
promptHashCache: Record<string, string> = {};
|
||||
pageSections: Record<string, { FullPage: SafeHtml }> = {};
|
||||
|
||||
|
||||
constructor(
|
||||
@ -30,9 +37,6 @@ export class WireframeRendererComponent implements OnInit {
|
||||
private route: ActivatedRoute,
|
||||
private sanitizer: DomSanitizer,
|
||||
private toastr: ToastrService,
|
||||
|
||||
|
||||
|
||||
) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
@ -42,6 +46,7 @@ export class WireframeRendererComponent implements OnInit {
|
||||
|
||||
this.fetchTreeById(this.id);
|
||||
}
|
||||
|
||||
// wireframe-renderer.component.ts (add this helper method)
|
||||
getKeys(obj: any): string[] {
|
||||
return Object.keys(obj || {});
|
||||
@ -78,14 +83,9 @@ export class WireframeRendererComponent implements OnInit {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// all prompt in one map
|
||||
|
||||
allPagePrompts: Record<string, Record<string, string>> = {};
|
||||
initialGeneratedPrompts: Record<string, Record<string, string>> = {};
|
||||
|
||||
|
||||
// Recursively walk the tree and generate prompts for each section
|
||||
|
||||
// Step 2
|
||||
async generatePromptsForAllSections(treeJsonString: string) {
|
||||
try {
|
||||
@ -98,14 +98,14 @@ export class WireframeRendererComponent implements OnInit {
|
||||
}
|
||||
|
||||
// Step 3
|
||||
async processPages(treeJson: any) {
|
||||
pageRenderOrder: string[] = []; // 🚀 New array to hold correct page order
|
||||
|
||||
async processPages(treeJson: any) {
|
||||
console.log('tree is : ', treeJson)
|
||||
for (const [pageName, sections] of Object.entries(treeJson)) {
|
||||
|
||||
this.pageRenderOrder.push(pageName); // ✅ Track the order of pages
|
||||
// child page prompt map
|
||||
const sectionPrompts: Record<string, string> = {};
|
||||
|
||||
if (sections['Children']) {
|
||||
// 👇 Recursively handle child pages
|
||||
console.log(' child is : ', sections['Children'])
|
||||
@ -113,7 +113,6 @@ export class WireframeRendererComponent implements OnInit {
|
||||
await this.processPages(sections['Children']); // ✅ Fix: recursive + awaited
|
||||
|
||||
}
|
||||
|
||||
// Loop other sections
|
||||
for (const [sectionName, sectionDescription] of Object.entries(sections)) {
|
||||
|
||||
@ -123,9 +122,6 @@ export class WireframeRendererComponent implements OnInit {
|
||||
|
||||
const prompt = await this.generatePromptFromSection(sectionName, sectionDescription); // ✅ await
|
||||
sectionPrompts[sectionName] = prompt;
|
||||
|
||||
// console.log( sectionName, ': ', prompt)
|
||||
|
||||
}
|
||||
|
||||
// 🧠 Store all prompts for that page
|
||||
@ -133,7 +129,6 @@ export class WireframeRendererComponent implements OnInit {
|
||||
this.initialGeneratedPrompts[pageName] = JSON.parse(JSON.stringify(sectionPrompts)); // Deep clone
|
||||
|
||||
}
|
||||
|
||||
console.log('✅ FINAL PROMPT MAP:', this.allPagePrompts);
|
||||
|
||||
await this.processAllPagesLiveUpdate()
|
||||
@ -174,124 +169,120 @@ HTML Only. No CSS.
|
||||
✅ Use placeholders for image/icon blocks where appropriate (e.g., <div style="width:100px;height:30px;background:#ccc;"></div>)`;
|
||||
|
||||
|
||||
// Step 4
|
||||
|
||||
async generatePromptFromSection(
|
||||
sectionName: string,
|
||||
sectionDescription: string,
|
||||
headerId: number = 35,
|
||||
operationType: string = 'template 1',
|
||||
operationType: string = 'template 1'
|
||||
): Promise<string> {
|
||||
return new Promise((resolve) => {
|
||||
// const fieldType = sectionName.toLowerCase().replace(/\s+/g, '').replace(/section$/, '').trim();
|
||||
const fieldType = sectionName
|
||||
.toLowerCase()
|
||||
.replace(/section$/i, '') // remove trailing 'section'
|
||||
.replace(/\s{2,}/g, ' ') // multiple spaces to single space
|
||||
.trim(); // trim leading/trailing spaces
|
||||
const fieldType = sectionName.toLowerCase().replace(/section$/i, '').trim();
|
||||
|
||||
this.siteTreeService.getDlf(headerId, operationType, fieldType).subscribe({
|
||||
next: async (res) => {
|
||||
try {
|
||||
const jsonBlock = res?.javacode;
|
||||
if (!jsonBlock) return resolve('{}');
|
||||
|
||||
// console.log( fieldType , ' json is : ', jsonBlock)
|
||||
const baseJson = typeof jsonBlock === 'string' ? JSON.parse(jsonBlock) : jsonBlock;
|
||||
const baseJsonString = JSON.stringify(baseJson, null, 2);
|
||||
|
||||
if (jsonBlock) {
|
||||
const parsedJson = typeof jsonBlock === 'string' ? JSON.parse(jsonBlock) : jsonBlock;
|
||||
const enhancedPrompt = `
|
||||
🎯 Enhance the content of this section using the following context.
|
||||
|
||||
// const updatedJson = this.replaceContentRecursively(parsedJson, sectionDescription);
|
||||
const finalJsonString = JSON.stringify(parsedJson, null, 2);
|
||||
// 🧠 Build prompt to LLM with section info + json + full page prompt
|
||||
const enhancedPrompt = `
|
||||
📘 You are an intelligent layout enhancer.
|
||||
🧠 Instructions:
|
||||
- You are given an existing JSON structure for a UI section.
|
||||
- Your job is to update ONLY the content-related fields like "text", "title", "label", "description", and "placeholder".
|
||||
- You must NOT change the structure, hierarchy, tags, keys, class names, or styling values.
|
||||
- You must NOT add or remove any keys or elements.
|
||||
- You must return ONLY the updated JSON structure in valid format.
|
||||
|
||||
Your task is to update and fill in the values of a given UI section JSON based on the following information:
|
||||
📄 Page Prompt:
|
||||
"${this.initialPrompt}"
|
||||
|
||||
- Page-level prompt: "${this.initialPrompt || ''}"
|
||||
- Section name: "${sectionName}"
|
||||
- Section description: "${sectionDescription}"
|
||||
📦 Section Name:
|
||||
"${sectionName}"
|
||||
|
||||
You must only update relevant values like "title", "text", "description", "label", "placeholder", etc.
|
||||
📘 Section Description:
|
||||
"${sectionDescription}"
|
||||
|
||||
⚠️ DO NOT change the structure. Only update content values.
|
||||
📌 Existing JSON (modify this only):
|
||||
${baseJsonString}
|
||||
|
||||
JSON:
|
||||
${finalJsonString}
|
||||
🚫 Do NOT include:
|
||||
- Any explanation, commentary, or markdown
|
||||
- Any prefix like "Here is the updated JSON"
|
||||
- Any new elements that were not already present
|
||||
|
||||
✅ Return only the updated JSON. Do not return any explanation.
|
||||
`;
|
||||
✅ Output Requirement:
|
||||
Only return the updated JSON structure — nothing else.
|
||||
`;
|
||||
|
||||
// console.log('enhanced query ', enhancedPrompt);
|
||||
|
||||
// const finalJson = await this.calLlm(enhancedPrompt);
|
||||
resolve(finalJsonString);
|
||||
} else {
|
||||
resolve('{}');
|
||||
const hash = sha256(enhancedPrompt).toString();
|
||||
|
||||
if (this.promptHashCache[hash]) {
|
||||
return resolve(this.promptHashCache[hash]);
|
||||
}
|
||||
|
||||
// const enhanced = await this.callLlm(enhancedPrompt);
|
||||
// this.promptHashCache[hash] = enhanced;
|
||||
|
||||
resolve(baseJsonString);
|
||||
} catch (err) {
|
||||
console.error('❌ JSON parse error:', err);
|
||||
resolve('{}');
|
||||
}
|
||||
},
|
||||
error: (err) => {
|
||||
console.error('❌ API error:', err);
|
||||
resolve('{}');
|
||||
}
|
||||
error: () => resolve('{}')
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
cachedPromptHashes: Record<string, Record<string, string>> = {};
|
||||
sectionHtmls: Record<string, Record<string, string>> = {};
|
||||
|
||||
// Step 1 - Generate SHA-256 Hash
|
||||
|
||||
getPromptHash(prompt: string): string {
|
||||
return SHA256(prompt).toString();
|
||||
}
|
||||
|
||||
|
||||
// Step 2 - Enhance per section with Hash Check + LLM call in Parallel
|
||||
|
||||
async processAllPagesLiveUpdate() {
|
||||
const htmlGenerationTasks: Promise<void>[] = [];
|
||||
|
||||
for (const [pageName, sectionMap] of Object.entries(this.allPagePrompts)) {
|
||||
htmlGenerationTasks.push(this.processPageSections(pageName, sectionMap));
|
||||
}
|
||||
|
||||
await Promise.all(htmlGenerationTasks);
|
||||
}
|
||||
|
||||
async processPageSections(pageName: string, sectionMap: Record<string, string>) {
|
||||
const sectionHtmls: string[] = [];
|
||||
|
||||
const htmlTasks = Object.entries(sectionMap).map(async ([sectionName, jsonPrompt]) => {
|
||||
const html = await this.generateJson({ sectionType: sectionName, jsonStructure: jsonPrompt });
|
||||
sectionHtmls.push(html);
|
||||
});
|
||||
|
||||
await Promise.all(htmlTasks);
|
||||
|
||||
const finalHtml = `<style>${COMMON_CSS}</style>\n${sectionHtmls.join('\n')}`;
|
||||
const safeHtml = this.sanitizer.bypassSecurityTrustHtml(finalHtml);
|
||||
|
||||
this.pageSections[pageName] = { FullPage: safeHtml };
|
||||
}
|
||||
|
||||
// replaceContentRecursively(obj: any, replacement: string): any {
|
||||
// if (Array.isArray(obj)) {
|
||||
// return obj.map(item => this.replaceContentRecursively(item, replacement));
|
||||
// } else if (typeof obj === 'object' && obj !== null) {
|
||||
// const updated = {};
|
||||
// for (const [key, value] of Object.entries(obj)) {
|
||||
// // Replace specific fields if they are strings
|
||||
// if (['description', 'text', 'label', 'title', 'subtext'].includes(key.toLowerCase()) && typeof value === 'string') {
|
||||
// updated[key] = replacement;
|
||||
// } else {
|
||||
// updated[key] = this.replaceContentRecursively(value, replacement);
|
||||
// }
|
||||
// }
|
||||
// return updated;
|
||||
// }
|
||||
// return obj;
|
||||
// }
|
||||
|
||||
|
||||
pageHtmlMap: Record<string, string> = {};
|
||||
generatedPages: { name: string, html: string }[] = [];
|
||||
|
||||
pageSections: Record<string, { FullPage: SafeHtml }> = {}; // final UI map
|
||||
|
||||
// Step 5 - generate html code via java Api through prompt
|
||||
async processAllPagesLiveUpdate() {
|
||||
for (const [pageName, sectionMap] of Object.entries(this.allPagePrompts)) {
|
||||
const sectionHtmls: string[] = [];
|
||||
|
||||
for (const [sectionName, promptText] of Object.entries(sectionMap)) {
|
||||
console.log(`🚀 Generating HTML for: ${pageName} > ${sectionName}`);
|
||||
|
||||
const response = await this.generateJson({ sectionType: sectionName, jsonStructure: promptText });
|
||||
const html = response || '⚠️ No response received.';
|
||||
|
||||
sectionHtmls.push(html);
|
||||
}
|
||||
|
||||
// ✅ Inject common CSS once per page
|
||||
const htmlWithCss = `
|
||||
<style>${COMMON_CSS}</style>
|
||||
${sectionHtmls.join('\n')}`;
|
||||
|
||||
// ✅ Bypass Angular sanitizer
|
||||
const safeHtml: SafeHtml = this.sanitizer.bypassSecurityTrustHtml(htmlWithCss);
|
||||
|
||||
this.pageSections[pageName] = { FullPage: safeHtml };
|
||||
}
|
||||
}
|
||||
|
||||
// Step 6
|
||||
async generateJson(data: { jsonStructure: any, sectionType: string }): Promise<string> {
|
||||
return new Promise((resolve) => {
|
||||
@ -310,7 +301,7 @@ ${finalJsonString}
|
||||
|
||||
this.siteTreeService.generateHtml(payload).subscribe({
|
||||
next: (res) => {
|
||||
console.log('✅ Response from HTML API:', res);
|
||||
console.log('✅ Response from HTML API ', payload.sectionType, ' : ', res);
|
||||
if (res && res.msg) {
|
||||
resolve(res.msg);
|
||||
} else {
|
||||
@ -318,12 +309,12 @@ ${finalJsonString}
|
||||
}
|
||||
},
|
||||
error: (err) => {
|
||||
console.error('❌ HTML API Error:', err);
|
||||
console.error(payload.sectionType, '❌ HTML API Error:', err);
|
||||
resolve('⚠️ HTML API call failed.');
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('❌ JSON parsing error before sending to API:', err);
|
||||
console.error(data.sectionType, '❌ JSON parsing error before sending to API:', err);
|
||||
resolve('⚠️ Invalid JSON structure.');
|
||||
}
|
||||
});
|
||||
@ -469,7 +460,7 @@ ${finalJsonString}
|
||||
|
||||
|
||||
// // Step 6
|
||||
async calLlm(data): Promise<string> {
|
||||
async callLlm(data): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
console.log('call Llm Start ')
|
||||
const payload = {
|
||||
@ -492,6 +483,337 @@ ${finalJsonString}
|
||||
});
|
||||
}
|
||||
|
||||
activeEditTarget: string | null = null;
|
||||
liveStyles = {
|
||||
background: '',
|
||||
color: '',
|
||||
fontSize: '',
|
||||
padding: '',
|
||||
margin: '',
|
||||
fontWeight: '',
|
||||
textAlign: '',
|
||||
};
|
||||
|
||||
selectEditable(pageName: string) {
|
||||
this.activeEditTarget = pageName;
|
||||
}
|
||||
|
||||
applyLiveStyles() {
|
||||
const target = document.querySelector(`[data-target='${this.activeEditTarget}']`) as HTMLElement;
|
||||
if (target) {
|
||||
Object.keys(this.liveStyles).forEach((prop) => {
|
||||
if (this.liveStyles[prop]) {
|
||||
target.style[prop] = this.liveStyles[prop];
|
||||
}
|
||||
});
|
||||
}
|
||||
this.toastr.success(`🎨 Style updated for: ${this.activeEditTarget}`);
|
||||
}
|
||||
|
||||
// 🔁 Track raw edits
|
||||
rawEdits: Record<string, string> = {};
|
||||
|
||||
|
||||
|
||||
selectedElementSelector = '';
|
||||
styleMap: Record<string, any> = {
|
||||
'hero-header': { 'background': '#fdfdfd', 'text-align': 'center' },
|
||||
'btn-filled': { 'background': '#000', 'color': '#fff' },
|
||||
'hero-heading': { 'font-size': '36px', 'font-weight': 'bold' },
|
||||
// Add all classes you want to allow editing
|
||||
};
|
||||
|
||||
getAllCssSelectors(): string[] {
|
||||
return Object.keys(this.styleMap);
|
||||
}
|
||||
|
||||
|
||||
applyCssFromMap() {
|
||||
this.updateLiveStyles();
|
||||
}
|
||||
|
||||
updateLiveStyles() {
|
||||
const styleSheetId = 'dynamic-css-style';
|
||||
let styleEl = document.getElementById(styleSheetId) as HTMLStyleElement;
|
||||
|
||||
if (!styleEl) {
|
||||
styleEl = document.createElement('style');
|
||||
styleEl.id = styleSheetId;
|
||||
document.head.appendChild(styleEl);
|
||||
}
|
||||
|
||||
let css = '';
|
||||
for (const selector in this.styleMap) {
|
||||
css += `.${selector} {`;
|
||||
for (const prop in this.styleMap[selector]) {
|
||||
css += `${prop}: ${this.styleMap[selector][prop]};`;
|
||||
}
|
||||
css += '}';
|
||||
}
|
||||
|
||||
styleEl.innerHTML = css;
|
||||
}
|
||||
|
||||
onEdit(pageName: string, event: any) {
|
||||
const newHtml = event.target.innerHTML;
|
||||
this.pageSections[pageName]['FullPage'] = this.sanitizer.bypassSecurityTrustHtml(newHtml);
|
||||
}
|
||||
|
||||
applyStyleToSelection() {
|
||||
const selection = window.getSelection();
|
||||
if (!selection || selection.rangeCount === 0) return;
|
||||
|
||||
const range = selection.getRangeAt(0);
|
||||
const selectedText = range.extractContents();
|
||||
|
||||
const span = document.createElement('span');
|
||||
|
||||
// Apply styles
|
||||
if (this.liveStyles.color) span.style.color = this.liveStyles.color;
|
||||
if (this.liveStyles.background) span.style.backgroundColor = this.liveStyles.background;
|
||||
if (this.liveStyles.fontSize) span.style.fontSize = this.liveStyles.fontSize;
|
||||
if (this.liveStyles.fontWeight) span.style.fontWeight = this.liveStyles.fontWeight;
|
||||
if (this.liveStyles.textAlign) span.style.textAlign = this.liveStyles.textAlign;
|
||||
span.appendChild(selectedText);
|
||||
|
||||
range.insertNode(span);
|
||||
selection.removeAllRanges();
|
||||
}
|
||||
|
||||
// new today 25 april
|
||||
// New Variables
|
||||
selectedNavbarPage: string = '';
|
||||
navbarLinks: Record<string, { label: string, href: string }[]> = {};
|
||||
availablePages: { label: string, href: string }[] = [];
|
||||
|
||||
// Select Navbar Section
|
||||
selectNavbar(pageName: string) {
|
||||
const html = this.pageSections[pageName]['FullPage']?.toString() || '';
|
||||
|
||||
if (html.includes('class="nav-1"') || html.includes('navbar')) {
|
||||
this.selectedNavbarPage = pageName;
|
||||
this.extractNavbarLinks(pageName, html);
|
||||
} else {
|
||||
alert('No Navbar found on this page.');
|
||||
}
|
||||
}
|
||||
|
||||
// Extract links from navbar HTML
|
||||
extractNavbarLinks(pageName: string, html: string) {
|
||||
const tempDiv = document.createElement('div');
|
||||
tempDiv.innerHTML = html;
|
||||
|
||||
const navLinks = Array.from(tempDiv.querySelectorAll('.nav-1 li a'));
|
||||
this.navbarLinks[pageName] = navLinks.map(link => ({
|
||||
label: link.textContent?.trim() || '',
|
||||
href: link.getAttribute('href') || '#'
|
||||
}));
|
||||
|
||||
// Also prepare available pages list
|
||||
this.availablePages = Object.keys(this.pageSections).map(p => ({
|
||||
label: p,
|
||||
href: `${p.replace(/\s+/g, '-').toLowerCase()}.html`
|
||||
}));
|
||||
}
|
||||
|
||||
// Add new link
|
||||
addLink(pageName: string) {
|
||||
this.navbarLinks[pageName].push({ label: '', href: '#' });
|
||||
}
|
||||
|
||||
// Remove a link
|
||||
removeLink(pageName: string, index: number) {
|
||||
this.navbarLinks[pageName].splice(index, 1);
|
||||
}
|
||||
|
||||
// Apply Changes to navbar
|
||||
applyNavbarChanges(pageName: string) {
|
||||
const links = this.navbarLinks[pageName] || [];
|
||||
|
||||
const html = this.pageSections[pageName]?.FullPage?.toString() || '';
|
||||
if (!html) return;
|
||||
|
||||
// Build new <ul class="nav-1"> from links
|
||||
const ulHtml = `<ul class="nav-1">` + links.map(link => {
|
||||
return `<li><a href="${link.href}">${link.label}</a></li>`;
|
||||
}).join('') + `</ul>`;
|
||||
|
||||
// Replace all instances of <ul class="nav-1">...</ul>
|
||||
const updatedHtml = html.replace(/<ul class="nav-1"([\s\S]*?)<\/ul>/g, ulHtml);
|
||||
console.log(' new html ', updatedHtml);
|
||||
|
||||
const safe = this.sanitizer.bypassSecurityTrustHtml(updatedHtml);
|
||||
this.pageSections[pageName] = { FullPage: safe };
|
||||
|
||||
this.toastr.success('✅ Navbar updated for all nav-1 instances!');
|
||||
}
|
||||
|
||||
// applyNavbarChanges(pageName: string) {
|
||||
// const links = this.navbarLinks[pageName] || [];
|
||||
// const htmlContent = this.pageSections[pageName]?.FullPage?.toString() || '';
|
||||
|
||||
// if (!htmlContent) return;
|
||||
|
||||
// // Create a temporary container to parse and manipulate the HTML
|
||||
// const wrapper = document.createElement('div');
|
||||
// wrapper.innerHTML = htmlContent;
|
||||
|
||||
// // Find all navbar UL elements
|
||||
// const navMenus = wrapper.querySelectorAll('ul.nav-1');
|
||||
|
||||
// if (navMenus.length === 0) {
|
||||
// console.warn('No navigation menus found with class "nav-1"');
|
||||
// return;
|
||||
// }
|
||||
|
||||
// // Update each navigation menu found
|
||||
// navMenus.forEach(ul => {
|
||||
// // step 1 clear the old vals in html
|
||||
// ul.innerHTML = '';
|
||||
|
||||
// // creating a new one and appending
|
||||
// links.forEach(link => {
|
||||
// const listItem = document.createElement('li');
|
||||
// const anchor = document.createElement('a');
|
||||
|
||||
// // Set attributes safely using setAttribute
|
||||
// anchor.setAttribute('href', link.href);
|
||||
// anchor.textContent = link.label;
|
||||
|
||||
// listItem.appendChild(anchor);
|
||||
// ul.appendChild(listItem);
|
||||
// });
|
||||
// });
|
||||
|
||||
// // Get the updated HTML content
|
||||
// const updatedHtml = wrapper.innerHTML;
|
||||
|
||||
// // Sanitize and update the page content
|
||||
// const safeHtml = this.sanitizer.bypassSecurityTrustHtml(updatedHtml);
|
||||
// this.pageSections[pageName] = { FullPage: safeHtml };
|
||||
|
||||
// this.toastr.success('✅ Navbar updated for all nav-1 instances!');
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// // Step 4
|
||||
// async generatePromptFromSection(
|
||||
// sectionName: string,
|
||||
// sectionDescription: string,
|
||||
// headerId: number = 35,
|
||||
// operationType: string = 'template 1',
|
||||
// ): Promise<string> {
|
||||
// return new Promise((resolve) => {
|
||||
// // const fieldType = sectionName.toLowerCase().replace(/\s+/g, '').replace(/section$/, '').trim();
|
||||
// const fieldType = sectionName
|
||||
// .toLowerCase()
|
||||
// .replace(/section$/i, '') // remove trailing 'section'
|
||||
// .replace(/\s{2,}/g, ' ') // multiple spaces to single space
|
||||
// .trim(); // trim leading/trailing spaces
|
||||
|
||||
// this.siteTreeService.getDlf(headerId, operationType, fieldType).subscribe({
|
||||
// next: async (res) => {
|
||||
// try {
|
||||
// const jsonBlock = res?.javacode;
|
||||
// if (!jsonBlock) {
|
||||
// resolve('{}');
|
||||
// return;
|
||||
// }
|
||||
|
||||
// // console.log( fieldType , ' json is : ', jsonBlock)
|
||||
|
||||
// const parsedJson = typeof jsonBlock === 'string' ? JSON.parse(jsonBlock) : jsonBlock;
|
||||
|
||||
// // const updatedJson = this.replaceContentRecursively(parsedJson, sectionDescription);
|
||||
// const formattedJson = JSON.stringify(parsedJson, null, 2);
|
||||
// // 🧠 Build prompt to LLM with section info + json + full page prompt
|
||||
// // // 🧠 LLM enhancement: Content update without changing structure
|
||||
// const smartPrompt = `
|
||||
// 🔁 Enhance this JSON content while keeping the structure exactly same.
|
||||
|
||||
// Section Name: ${sectionName}
|
||||
// Section Description: ${sectionDescription}
|
||||
// Full Page Prompt: ${this.initialPrompt || ''}
|
||||
|
||||
// ✅ Replace or fill only content fields like: "title", "description", "text", "label", "placeholder", "heading", etc.
|
||||
// ❌ Do NOT change or restructure keys, nesting, or CSS class names.
|
||||
// ❌ Do NOT remove or add new blocks unless it's strictly a content array (like testimonials or FAQs).
|
||||
|
||||
// JSON Input:
|
||||
// ${formattedJson}
|
||||
|
||||
// ⬇️ Return only the updated JSON with better content.
|
||||
// `;
|
||||
|
||||
|
||||
// // console.log('enhanced query ', smartPrompt);
|
||||
|
||||
// // // const finalJson = await this.calLlm(enhancedPrompt);
|
||||
// // resolve(formattedJson);
|
||||
|
||||
// const enhancedJson = await this.calLlm(smartPrompt);
|
||||
|
||||
// // Return directly the enhanced JSON
|
||||
// resolve(enhancedJson || formattedJson);
|
||||
|
||||
// } catch (err) {
|
||||
// console.error('❌ JSON parse error:', err);
|
||||
// resolve('{}');
|
||||
// }
|
||||
// },
|
||||
// error: (err) => {
|
||||
// console.error('❌ API error:', err);
|
||||
// resolve('{}');
|
||||
// }
|
||||
// });
|
||||
// });
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// // Step 5 - generate html code via java Api through prompt
|
||||
// async processAllPagesLiveUpdate() {
|
||||
// for (const [pageName, sectionMap] of Object.entries(this.allPagePrompts)) {
|
||||
// const sectionHtmls: string[] = [];
|
||||
|
||||
// for (const [sectionName, promptText] of Object.entries(sectionMap)) {
|
||||
// console.log(`🚀 Generating HTML for: ${pageName} > ${sectionName}`);
|
||||
|
||||
// const response = await this.generateJson({ sectionType: sectionName, jsonStructure: promptText });
|
||||
// const html = response || '⚠️ No response received.';
|
||||
|
||||
// sectionHtmls.push(html);
|
||||
// }
|
||||
|
||||
// // ✅ Inject common CSS once per page
|
||||
// const htmlWithCss = `
|
||||
// <style>${COMMON_CSS}</style>
|
||||
// ${sectionHtmls.join('\n')}`;
|
||||
|
||||
// // ✅ Bypass Angular sanitizer
|
||||
// const safeHtml: SafeHtml = this.sanitizer.bypassSecurityTrustHtml(htmlWithCss);
|
||||
|
||||
// this.pageSections[pageName] = { FullPage: safeHtml };
|
||||
// }
|
||||
// }
|
||||
// replaceContentRecursively(obj: any, replacement: string): any {
|
||||
// if (Array.isArray(obj)) {
|
||||
// return obj.map(item => this.replaceContentRecursively(item, replacement));
|
||||
// } else if (typeof obj === 'object' && obj !== null) {
|
||||
// const updated = {};
|
||||
// for (const [key, value] of Object.entries(obj)) {
|
||||
// // Replace specific fields if they are strings
|
||||
// if (['description', 'text', 'label', 'title', 'subtext'].includes(key.toLowerCase()) && typeof value === 'string') {
|
||||
// updated[key] = replacement;
|
||||
// } else {
|
||||
// updated[key] = this.replaceContentRecursively(value, replacement);
|
||||
// }
|
||||
// }
|
||||
// return updated;
|
||||
// }
|
||||
// return obj;
|
||||
// }
|
||||
|
||||
// // Step 4
|
||||
// generatePromptFromSection(
|
||||
|
||||
@ -110,11 +110,10 @@
|
||||
|
||||
|
||||
<!-- Popup Dialog -->
|
||||
<div *ngIf="showPopup"
|
||||
<!-- <div *ngIf="showPopup"
|
||||
style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.6); display: flex; align-items: center; justify-content: center; z-index: 1000;">
|
||||
<div style="background: white; padding: 20px; width: 500px; border-radius: 8px; position: relative;">
|
||||
|
||||
<!-- CLOSE BUTTON -->
|
||||
<button (click)="showPopup = false"
|
||||
style="position: absolute; top: 10px; right: 10px; background: #ff4d4f; border: none; color: white; border-radius: 50%; width: 30px; height: 30px; font-size: 18px; cursor: pointer;">
|
||||
×
|
||||
@ -130,4 +129,39 @@
|
||||
Generate
|
||||
</button>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
|
||||
<!-- Popup Dialog with improved z-index and animations -->
|
||||
<div *ngIf="showPopup" [@fadeIn] class="modal-overlay"
|
||||
style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.75); display: flex; align-items: center; justify-content: center; z-index: 1000;">
|
||||
<div class="chart-box" [@slideIn]
|
||||
style="width: 600px; max-height: none; padding: 24px; box-shadow: 0 8px 24px rgba(0,0,0,0.25); border-radius: 8px; border: none; transform-origin: center; background-color: snow">
|
||||
|
||||
<!-- Close button -->
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px;">
|
||||
<h3 style="margin: 0; color: #333; font-weight: 500;">Generate Site Structure</h3>
|
||||
<button (click)="showPopup = false" [@pulseOnHover]
|
||||
style="background: transparent; border: none; color: #666; font-size: 24px; cursor: pointer; padding: 4px; height: 36px; width: 36px; border-radius: 50%; transition: all 0.2s ease; display: flex; align-items: center; justify-content: center; color: #f5f5f5;">
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<p style="margin-bottom: 16px; color: #666;">Describe your website structure in plain language:</p>
|
||||
|
||||
<textarea [(ngModel)]="rawInputText" rows="8" [@focusBorder]
|
||||
class="tag-input"
|
||||
style="width: 100%; margin-bottom: 20px; font-family: inherit; resize: vertical; transition: border 0.3s ease; box-shadow: 0 2px 4px rgba(0,0,0,0.05);"></textarea>
|
||||
|
||||
<div style="display: flex; justify-content: flex-end; gap: 12px;">
|
||||
<button (click)="showPopup = false" [@buttonHover]
|
||||
style="padding: 8px 16px; background: #f5f5f5; color: #333; border: 1px solid #ddd; border-radius: 4px; cursor: pointer; transition: all 0.2s ease;">
|
||||
Cancel
|
||||
</button>
|
||||
<button (click)="generateJson()" [@buttonHover]
|
||||
style="padding: 8px 18px; background: #1976d2; color: white; border: none; border-radius: 4px; cursor: pointer; transition: all 0.2s ease; box-shadow: 0 2px 4px rgba(0,0,0,0.2);">
|
||||
Generate Structure
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -1,3 +1,146 @@
|
||||
// .controls {
|
||||
// margin-bottom: 20px;
|
||||
// }
|
||||
|
||||
// .controls textarea {
|
||||
// width: 100%;
|
||||
// height: 200px;
|
||||
// padding: 10px;
|
||||
// font-size: 14px;
|
||||
// font-family: monospace;
|
||||
// border: 1px solid #ccc;
|
||||
// border-radius: 4px;
|
||||
// resize: vertical;
|
||||
// box-sizing: border-box;
|
||||
// margin-bottom: 10px;
|
||||
// }
|
||||
|
||||
// .controls button {
|
||||
// padding: 10px 20px;
|
||||
// background-color: #1976d2;
|
||||
// color: white;
|
||||
// border: none;
|
||||
// border-radius: 4px;
|
||||
// cursor: pointer;
|
||||
// }
|
||||
|
||||
// .controls button:hover {
|
||||
// background-color: #1565c0;
|
||||
// }
|
||||
|
||||
// .toolbar {
|
||||
// display: flex;
|
||||
// gap: 10px;
|
||||
// align-items: flex-start;
|
||||
// padding: 1rem;
|
||||
// background-color: #f7f7f7;
|
||||
// }
|
||||
|
||||
// textarea {
|
||||
// width: 300px;
|
||||
// height: 120px;
|
||||
// font-family: monospace;
|
||||
// padding: 10px;
|
||||
// border-radius: 8px;
|
||||
// border: 1px solid #ccc;
|
||||
// }
|
||||
|
||||
// button {
|
||||
// padding: 10px 20px;
|
||||
// background-color: #3f51b5;
|
||||
// color: white;
|
||||
// border: none;
|
||||
// border-radius: 6px;
|
||||
// cursor: pointer;
|
||||
// transition: background-color 0.3s ease;
|
||||
// }
|
||||
|
||||
// button:hover {
|
||||
// background-color: #303f9f;
|
||||
// }
|
||||
|
||||
// mat-tab-group {
|
||||
// margin: 1rem;
|
||||
// }
|
||||
|
||||
// .tab-content {
|
||||
// padding: 1rem;
|
||||
// background-color: #fafafa;
|
||||
// border: 1px solid #ddd;
|
||||
// border-radius: 10px;
|
||||
// min-height: 400px;
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// .active-tab {
|
||||
// border-bottom: 2px solid #007bff;
|
||||
// color: #007bff;
|
||||
// }
|
||||
|
||||
// .tab-button {
|
||||
// padding: 8px 16px;
|
||||
// margin-right: 8px;
|
||||
// background: #f1f1f1;
|
||||
// border: none;
|
||||
// border-bottom: 2px solid transparent;
|
||||
// cursor: pointer;
|
||||
// color: black; /* 👈 Text color black */
|
||||
// font-weight: bold;
|
||||
// }
|
||||
|
||||
// .tab-button.active {
|
||||
// border-bottom: 2px solid #000;
|
||||
// background: #e0e0e0;
|
||||
// color: black; /* 👈 Ensure active tab also stays black */
|
||||
// }
|
||||
|
||||
|
||||
// .editor-container {
|
||||
// position: relative; /* 🔑 Important to contain absolute button */
|
||||
// max-width: 1200px;
|
||||
// margin: 0 auto;
|
||||
// font-family: 'Segoe UI', sans-serif;
|
||||
// padding: 20px;
|
||||
// background-color: #ffffff;
|
||||
// }
|
||||
|
||||
// .style-panel {
|
||||
// position: fixed;
|
||||
// top: 100px;
|
||||
// right: 20px;
|
||||
// width: 220px;
|
||||
// padding: 15px;
|
||||
// background: white;
|
||||
// border: 1px solid #ccc;
|
||||
// border-radius: 6px;
|
||||
// box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
// z-index: 9999;
|
||||
|
||||
// h4 {
|
||||
// margin-bottom: 10px;
|
||||
// }
|
||||
|
||||
// label {
|
||||
// display: block;
|
||||
// margin-bottom: 10px;
|
||||
// font-size: 13px;
|
||||
// }
|
||||
|
||||
// input {
|
||||
// width: 100%;
|
||||
// padding: 4px;
|
||||
// margin-top: 2px;
|
||||
// }
|
||||
|
||||
// button {
|
||||
// margin-right: 8px;
|
||||
// padding: 6px 12px;
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
|
||||
.controls {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
@ -104,4 +247,20 @@ mat-tab-group {
|
||||
padding: 20px;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
.modal-overlay *{
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
|
||||
:host {
|
||||
--zoom-level: 1;
|
||||
--primary-color: #2196f3;
|
||||
--spacing-unit: 8px;
|
||||
}
|
||||
|
||||
:root {
|
||||
--level: 0;
|
||||
--primary-color: #2196f3;
|
||||
--border-color: #e2e8f0;
|
||||
}
|
||||
|
||||
|
||||
@ -3,17 +3,55 @@ import { treeVisualizerService } from './tree-visualizer.service';
|
||||
import { SiteTreeservice } from './SiteBuilderGrid/SiteTree.service';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
|
||||
import { ViewChild } from '@angular/core';
|
||||
import { trigger, transition, style, animate, state } from '@angular/animations';
|
||||
// Make sure path is correct
|
||||
|
||||
@Component({
|
||||
selector: 'app-tree-visualizer',
|
||||
templateUrl: './tree-visualizer.component.html',
|
||||
styleUrls: ['./tree-visualizer.component.scss']
|
||||
styleUrls: ['./tree-visualizer.component.scss'],
|
||||
animations: [
|
||||
trigger('fadeIn', [
|
||||
transition(':enter', [
|
||||
style({ opacity: 0 }),
|
||||
animate('200ms ease-out', style({ opacity: 1 }))
|
||||
]),
|
||||
transition(':leave', [
|
||||
animate('200ms ease-in', style({ opacity: 0 }))
|
||||
])
|
||||
]),
|
||||
trigger('slideIn', [
|
||||
transition(':enter', [
|
||||
style({ transform: 'scale(0.9)', opacity: 0 }),
|
||||
animate('300ms ease-out', style({ transform: 'scale(1)', opacity: 1 }))
|
||||
]),
|
||||
transition(':leave', [
|
||||
animate('200ms ease-in', style({ transform: 'scale(0.9)', opacity: 0 }))
|
||||
])
|
||||
]),
|
||||
trigger('buttonHover', [
|
||||
state('void', style({ transform: 'translateY(0)' })),
|
||||
state('hover', style({ transform: 'translateY(-2px)', boxShadow: '0 4px 8px rgba(0,0,0,0.2)' }))
|
||||
]),
|
||||
trigger('focusBorder', [
|
||||
state('void', style({ borderColor: '#ccc' })),
|
||||
state('focus', style({ borderColor: '#1976d2', boxShadow: '0 0 0 2px rgba(25,118,210,0.2)' }))
|
||||
]),
|
||||
trigger('pulseOnHover', [
|
||||
state('void', style({ backgroundColor: 'transparent' })),
|
||||
state('hover', style({ backgroundColor: 'rgba(0,0,0,0.05)' }))
|
||||
])
|
||||
]
|
||||
|
||||
})
|
||||
export class TreeVisualizerComponent {
|
||||
|
||||
activeTab: 'sitemap' | 'wireframe' = 'sitemap';
|
||||
showPopup: boolean = false;
|
||||
openPopup() {
|
||||
this.showPopup = true;
|
||||
}
|
||||
inputJson: string = `{
|
||||
"Login": {
|
||||
"Navbar": {},
|
||||
@ -75,9 +113,7 @@ after click this icard inside we upload excel of student data, icard template, a
|
||||
this.fetchTreeById(this.id);
|
||||
}
|
||||
|
||||
openPopup() {
|
||||
this.showPopup = true;
|
||||
}
|
||||
|
||||
|
||||
convertJson() {
|
||||
try {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user