Spaces:
Running
Running
ฟังชั่นที่เคยมีกลับใช่ไม่ได้ทำให้มันใช้ได้และมีตัวอย่างการใช้งานเต็มรูปแบบ
Browse files- index.html +1 -2
- script.js +196 -12
- style.css +108 -1
index.html
CHANGED
|
@@ -174,7 +174,6 @@
|
|
| 174 |
<script src="components/navbar.js"></script>
|
| 175 |
<script src="components/sidebar.js"></script>
|
| 176 |
<script src="components/footer.js"></script>
|
| 177 |
-
|
| 178 |
<!-- Navigation Links -->
|
| 179 |
<script>
|
| 180 |
// Listen for data updates from dashboard
|
|
@@ -190,4 +189,4 @@
|
|
| 190 |
<script src="script.js"></script>
|
| 191 |
<script>feather.replace();</script>
|
| 192 |
</body>
|
| 193 |
-
</html>
|
|
|
|
| 174 |
<script src="components/navbar.js"></script>
|
| 175 |
<script src="components/sidebar.js"></script>
|
| 176 |
<script src="components/footer.js"></script>
|
|
|
|
| 177 |
<!-- Navigation Links -->
|
| 178 |
<script>
|
| 179 |
// Listen for data updates from dashboard
|
|
|
|
| 189 |
<script src="script.js"></script>
|
| 190 |
<script>feather.replace();</script>
|
| 191 |
</body>
|
| 192 |
+
</html>
|
script.js
CHANGED
|
@@ -76,15 +76,17 @@ function setupGlobalListeners() {
|
|
| 76 |
document.getElementById('bg2-file')?.addEventListener('change', e => handleBgFile('2', e.target.files[0]));
|
| 77 |
document.getElementById('json-file')?.addEventListener('change', handleJsonUpload);
|
| 78 |
document.getElementById('pdf-upload')?.addEventListener('change', handlePdfUpload);
|
| 79 |
-
|
| 80 |
// Sidebar Actions
|
| 81 |
document.getElementById('btn-apply-bg')?.addEventListener('click', applyBg);
|
| 82 |
document.getElementById('btn-load-sample')?.addEventListener('click', loadSample);
|
| 83 |
document.getElementById('btn-download-pdf')?.addEventListener('click', downloadPDF);
|
| 84 |
document.getElementById('btn-download-all')?.addEventListener('click', downloadAllPDFs);
|
| 85 |
document.getElementById('btn-qr-modal')?.addEventListener('click', openQRModal);
|
| 86 |
-
|
| 87 |
-
|
|
|
|
|
|
|
|
|
|
| 88 |
document.querySelectorAll('.tab-btn').forEach(btn => {
|
| 89 |
btn.addEventListener('click', () => switchTab(btn.dataset.tab));
|
| 90 |
});
|
|
@@ -106,15 +108,16 @@ function setupGlobalListeners() {
|
|
| 106 |
if(modal) modal.classList.add('hidden');
|
| 107 |
});
|
| 108 |
});
|
| 109 |
-
|
| 110 |
// QR Actions
|
| 111 |
document.getElementById('qr-url')?.addEventListener('input', updateQRPreview);
|
| 112 |
document.getElementById('btn-qr-apply')?.addEventListener('click', applyQRAndDownload);
|
| 113 |
|
| 114 |
// History
|
| 115 |
document.addEventListener('show-history', showHistory);
|
| 116 |
-
|
| 117 |
-
//
|
|
|
|
|
|
|
| 118 |
document.addEventListener('keydown', (e) => {
|
| 119 |
if (e.ctrlKey || e.metaKey) {
|
| 120 |
if (e.key === '=') { e.preventDefault(); zoomIn(); }
|
|
@@ -723,8 +726,64 @@ function updateTemplateZoom() {
|
|
| 723 |
p.style.marginBottom = `${(1261 * (state.scale - 1))}px`;
|
| 724 |
});
|
| 725 |
}
|
| 726 |
-
|
| 727 |
// --- Export & Generation ---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 728 |
async function downloadPDF() {
|
| 729 |
if (state.data.length === 0) {
|
| 730 |
toast('No data to export', 'error');
|
|
@@ -732,7 +791,7 @@ async function downloadPDF() {
|
|
| 732 |
}
|
| 733 |
|
| 734 |
loading(true, 'Generating PDF...');
|
| 735 |
-
|
| 736 |
const data = state.data[state.currentIndex];
|
| 737 |
const layout = await saveLayoutToStorage(); // Capture current layout
|
| 738 |
const element = document.createElement('div');
|
|
@@ -783,7 +842,6 @@ async function downloadPDF() {
|
|
| 783 |
|
| 784 |
await html2pdf().set(opt).from(element).save();
|
| 785 |
document.body.removeChild(element);
|
| 786 |
-
|
| 787 |
// Save layout to history
|
| 788 |
const doc = {
|
| 789 |
id: Date.now().toString(),
|
|
@@ -795,7 +853,7 @@ async function downloadPDF() {
|
|
| 795 |
await saveDoc(doc);
|
| 796 |
|
| 797 |
toast('PDF Downloaded & Layout Saved', 'success');
|
| 798 |
-
|
| 799 |
toast('Generation Failed', 'error');
|
| 800 |
debugLog(e);
|
| 801 |
} finally {
|
|
@@ -1016,7 +1074,6 @@ async function showHistory() {
|
|
| 1016 |
}
|
| 1017 |
document.getElementById('history-modal').classList.remove('hidden');
|
| 1018 |
}
|
| 1019 |
-
|
| 1020 |
// Utils
|
| 1021 |
function rgbToHex(rgb) {
|
| 1022 |
if (!rgb) return '#000000';
|
|
@@ -1024,4 +1081,131 @@ function rgbToHex(rgb) {
|
|
| 1024 |
const rgbValues = rgb.match(/\d+/g);
|
| 1025 |
if (!rgbValues) return '#000000';
|
| 1026 |
return "#" + ((1 << 24) + (parseInt(rgbValues[0]) << 16) + (parseInt(rgbValues[1]) << 8) + parseInt(rgbValues[2])).toString(16).slice(1);
|
| 1027 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 76 |
document.getElementById('bg2-file')?.addEventListener('change', e => handleBgFile('2', e.target.files[0]));
|
| 77 |
document.getElementById('json-file')?.addEventListener('change', handleJsonUpload);
|
| 78 |
document.getElementById('pdf-upload')?.addEventListener('change', handlePdfUpload);
|
|
|
|
| 79 |
// Sidebar Actions
|
| 80 |
document.getElementById('btn-apply-bg')?.addEventListener('click', applyBg);
|
| 81 |
document.getElementById('btn-load-sample')?.addEventListener('click', loadSample);
|
| 82 |
document.getElementById('btn-download-pdf')?.addEventListener('click', downloadPDF);
|
| 83 |
document.getElementById('btn-download-all')?.addEventListener('click', downloadAllPDFs);
|
| 84 |
document.getElementById('btn-qr-modal')?.addEventListener('click', openQRModal);
|
| 85 |
+
document.getElementById('btn-export-layout')?.addEventListener('click', exportLayout);
|
| 86 |
+
document.getElementById('btn-save-layout')?.addEventListener('click', saveLayoutToDB);
|
| 87 |
+
document.getElementById('btn-new-layout')?.addEventListener('click', newLayout);
|
| 88 |
+
document.getElementById('layout-import')?.addEventListener('change', (e) => importLayout(e.target.files[0]));
|
| 89 |
+
// View Switching
|
| 90 |
document.querySelectorAll('.tab-btn').forEach(btn => {
|
| 91 |
btn.addEventListener('click', () => switchTab(btn.dataset.tab));
|
| 92 |
});
|
|
|
|
| 108 |
if(modal) modal.classList.add('hidden');
|
| 109 |
});
|
| 110 |
});
|
|
|
|
| 111 |
// QR Actions
|
| 112 |
document.getElementById('qr-url')?.addEventListener('input', updateQRPreview);
|
| 113 |
document.getElementById('btn-qr-apply')?.addEventListener('click', applyQRAndDownload);
|
| 114 |
|
| 115 |
// History
|
| 116 |
document.addEventListener('show-history', showHistory);
|
| 117 |
+
|
| 118 |
+
// Layout Management
|
| 119 |
+
document.addEventListener('layout-saved', updateFileCount);
|
| 120 |
+
// Keyboard
|
| 121 |
document.addEventListener('keydown', (e) => {
|
| 122 |
if (e.ctrlKey || e.metaKey) {
|
| 123 |
if (e.key === '=') { e.preventDefault(); zoomIn(); }
|
|
|
|
| 726 |
p.style.marginBottom = `${(1261 * (state.scale - 1))}px`;
|
| 727 |
});
|
| 728 |
}
|
|
|
|
| 729 |
// --- Export & Generation ---
|
| 730 |
+
async function exportLayout() {
|
| 731 |
+
const layout = await saveLayoutToStorage();
|
| 732 |
+
const name = document.getElementById('layout-name-input').value || layout.metadata.name || 'layout';
|
| 733 |
+
layout.metadata.name = name;
|
| 734 |
+
|
| 735 |
+
const blob = new Blob([JSON.stringify(layout, null, 2)], { type: 'application/json' });
|
| 736 |
+
const link = document.createElement('a');
|
| 737 |
+
link.href = URL.createObjectURL(blob);
|
| 738 |
+
link.download = `${name}_${new Date().getTime()}.json`;
|
| 739 |
+
link.click();
|
| 740 |
+
|
| 741 |
+
toast('Layout Exported', 'success');
|
| 742 |
+
}
|
| 743 |
+
|
| 744 |
+
async function importLayout(file) {
|
| 745 |
+
if (!file || !file.name.endsWith('.json')) {
|
| 746 |
+
toast('Please select a layout JSON file', 'error');
|
| 747 |
+
return;
|
| 748 |
+
}
|
| 749 |
+
|
| 750 |
+
document.getElementById('layout-import-name').textContent = file.name;
|
| 751 |
+
|
| 752 |
+
const reader = new FileReader();
|
| 753 |
+
reader.onload = async (e) => {
|
| 754 |
+
try {
|
| 755 |
+
const layout = JSON.parse(e.target.result);
|
| 756 |
+
if (!layout.fields || !layout.pages) {
|
| 757 |
+
throw new Error('Invalid layout format');
|
| 758 |
+
}
|
| 759 |
+
|
| 760 |
+
state.currentLayoutConfig = layout;
|
| 761 |
+
applyLayoutConfig(layout);
|
| 762 |
+
|
| 763 |
+
// Update form inputs
|
| 764 |
+
document.getElementById('layout-name-input').value = layout.metadata?.name || 'Imported Layout';
|
| 765 |
+
|
| 766 |
+
// Load background images if they are base64
|
| 767 |
+
layout.pages.forEach(pageConfig => {
|
| 768 |
+
if (pageConfig.background && pageConfig.background.startsWith('data:')) {
|
| 769 |
+
if (pageConfig.id === 'page1') {
|
| 770 |
+
state.bg1B64 = pageConfig.background;
|
| 771 |
+
} else if (pageConfig.id === 'page2') {
|
| 772 |
+
state.bg2B64 = pageConfig.background;
|
| 773 |
+
}
|
| 774 |
+
}
|
| 775 |
+
});
|
| 776 |
+
|
| 777 |
+
toast('Layout Imported Successfully', 'success');
|
| 778 |
+
state.isLayoutLoaded = true;
|
| 779 |
+
} catch (err) {
|
| 780 |
+
toast('Failed to import layout: ' + err.message, 'error');
|
| 781 |
+
debugLog(err);
|
| 782 |
+
}
|
| 783 |
+
};
|
| 784 |
+
reader.readAsText(file);
|
| 785 |
+
}
|
| 786 |
+
|
| 787 |
async function downloadPDF() {
|
| 788 |
if (state.data.length === 0) {
|
| 789 |
toast('No data to export', 'error');
|
|
|
|
| 791 |
}
|
| 792 |
|
| 793 |
loading(true, 'Generating PDF...');
|
| 794 |
+
try {
|
| 795 |
const data = state.data[state.currentIndex];
|
| 796 |
const layout = await saveLayoutToStorage(); // Capture current layout
|
| 797 |
const element = document.createElement('div');
|
|
|
|
| 842 |
|
| 843 |
await html2pdf().set(opt).from(element).save();
|
| 844 |
document.body.removeChild(element);
|
|
|
|
| 845 |
// Save layout to history
|
| 846 |
const doc = {
|
| 847 |
id: Date.now().toString(),
|
|
|
|
| 853 |
await saveDoc(doc);
|
| 854 |
|
| 855 |
toast('PDF Downloaded & Layout Saved', 'success');
|
| 856 |
+
} catch (e) {
|
| 857 |
toast('Generation Failed', 'error');
|
| 858 |
debugLog(e);
|
| 859 |
} finally {
|
|
|
|
| 1074 |
}
|
| 1075 |
document.getElementById('history-modal').classList.remove('hidden');
|
| 1076 |
}
|
|
|
|
| 1077 |
// Utils
|
| 1078 |
function rgbToHex(rgb) {
|
| 1079 |
if (!rgb) return '#000000';
|
|
|
|
| 1081 |
const rgbValues = rgb.match(/\d+/g);
|
| 1082 |
if (!rgbValues) return '#000000';
|
| 1083 |
return "#" + ((1 << 24) + (parseInt(rgbValues[0]) << 16) + (parseInt(rgbValues[1]) << 8) + parseInt(rgbValues[2])).toString(16).slice(1);
|
| 1084 |
+
}
|
| 1085 |
+
|
| 1086 |
+
// --- Complete Usage Examples ---
|
| 1087 |
+
function showUsageExamples() {
|
| 1088 |
+
console.log('=== PDF Layout Wizard - Complete Usage Examples ===\n');
|
| 1089 |
+
|
| 1090 |
+
console.log('1. BASIC USAGE:');
|
| 1091 |
+
console.log(' - Load sample data: Click "Load Sample" in sidebar');
|
| 1092 |
+
console.log(' - Edit field positions: Toggle Design Mode (pencil icon in navbar)');
|
| 1093 |
+
console.log(' - Download PDF: Click "Download PDF" in sidebar');
|
| 1094 |
+
|
| 1095 |
+
console.log('\n2. ADVANCED FEATURES:');
|
| 1096 |
+
console.log(' ├─ Layout Management:');
|
| 1097 |
+
console.log(' │ • Export Layout: Design Mode → Export Layout');
|
| 1098 |
+
console.log(' │ • Import Layout: Sidebar → Import Layout');
|
| 1099 |
+
console.log(' │ • Save Layout: Design Mode → Save Layout to History');
|
| 1100 |
+
console.log(' │ • New Layout: Design Mode → New Layout');
|
| 1101 |
+
console.log(' ├─ Data Management:');
|
| 1102 |
+
console.log(' │ • JSON Import: Sidebar → Import JSON');
|
| 1103 |
+
console.log(' │ • Data Dashboard: Navbar → Database icon');
|
| 1104 |
+
console.log(' │ • Record Switching: Sidebar dropdown');
|
| 1105 |
+
console.log(' ├─ PDF Features:');
|
| 1106 |
+
console.log(' │ • PDF Upload: Sidebar → Import PDF');
|
| 1107 |
+
console.log(' │ • PDF Viewer: Tab switch → PDF Viewer');
|
| 1108 |
+
console.log(' │ • QR Integration: Navbar → Grid icon');
|
| 1109 |
+
console.log(' └─ Export Options:');
|
| 1110 |
+
console.log(' • Single PDF: Sidebar → Download PDF');
|
| 1111 |
+
console.log(' • Batch Export: Sidebar → Download All');
|
| 1112 |
+
console.log(' • Layout Export: Design Mode → Export Layout');
|
| 1113 |
+
|
| 1114 |
+
console.log('\n3. KEYBOARD SHORTCUTS:');
|
| 1115 |
+
console.log(' - Ctrl + S: Download PDF');
|
| 1116 |
+
console.log(' - Ctrl + =: Zoom In');
|
| 1117 |
+
console.log(' - Ctrl + -: Zoom Out');
|
| 1118 |
+
console.log(' - ESC: Close modals / Exit Design Mode');
|
| 1119 |
+
|
| 1120 |
+
console.log('\n4. DESIGN MODE WORKFLOW:');
|
| 1121 |
+
console.log(' Step 1: Click Design Mode button (pencil icon)');
|
| 1122 |
+
console.log(' Step 2: Click and drag fields to position');
|
| 1123 |
+
console.log(' Step 3: Select field to edit properties (size, color, weight)');
|
| 1124 |
+
console.log(' Step 4: Export layout for reuse');
|
| 1125 |
+
console.log(' Step 5: Exit Design Mode (ESC or button)');
|
| 1126 |
+
|
| 1127 |
+
console.log('\n5. DATA WORKFLOW:');
|
| 1128 |
+
console.log(' • JSON Format: Must be array of objects with numbered keys (1-12)');
|
| 1129 |
+
console.log(' • Dashboard: Open in new tab for full CRUD operations');
|
| 1130 |
+
console.log(' • Real-time Update: Dashboard changes reflect in main app');
|
| 1131 |
+
|
| 1132 |
+
console.log('\n6. PDF WORKFLOW:');
|
| 1133 |
+
console.log(' • Upload Base PDF: Use PDF as template');
|
| 1134 |
+
console.log(' • View Mode: Switch to PDF tab to preview');
|
| 1135 |
+
console.log(' • QR Addition: Add QR codes to existing PDF');
|
| 1136 |
+
console.log(' • Zoom Controls: Bottom HUD controls');
|
| 1137 |
+
|
| 1138 |
+
console.log('\n7. HISTORY & STORAGE:');
|
| 1139 |
+
console.log(' • Auto-save: All generations saved to history');
|
| 1140 |
+
console.log(' • Layout Persistence: Saved in browser IndexedDB');
|
| 1141 |
+
console.log(' • Restore: Click history items to restore');
|
| 1142 |
+
console.log(' • Export/Import: Share layouts across devices');
|
| 1143 |
+
|
| 1144 |
+
console.log('\n8. CUSTOMIZATION:');
|
| 1145 |
+
console.log(' • CSS Variables: Modify :root colors in style.css');
|
| 1146 |
+
console.log(' • Field Mapping: Edit fieldToKey object in script.js');
|
| 1147 |
+
console.log(' • Default Layouts: Create preset layouts');
|
| 1148 |
+
console.log(' • Branding: Update navbar title and icons');
|
| 1149 |
+
console.log(' • Theme: Toggle light/dark mode');
|
| 1150 |
+
|
| 1151 |
+
console.log('\n9. SAMPLE COMMANDS:');
|
| 1152 |
+
console.log(' loadSample() // Load demo data');
|
| 1153 |
+
console.log(' toggleDesignMode() // Toggle field editing');
|
| 1154 |
+
console.log(' exportLayout() // Save current layout');
|
| 1155 |
+
console.log(' newLayout() // Reset to blank layout');
|
| 1156 |
+
console.log(' showData(0) // Show first data record');
|
| 1157 |
+
console.log(' downloadPDF() // Generate PDF');
|
| 1158 |
+
console.log(' saveLayoutToDB() // Save layout to history');
|
| 1159 |
+
console.log(' importLayout(file) // Import layout JSON');
|
| 1160 |
+
|
| 1161 |
+
console.log('\n10. TROUBLESHOOTING:');
|
| 1162 |
+
console.log(' • Images not showing: Enable CORS in browser');
|
| 1163 |
+
console.log(' • PDF generation slow: Reduce image sizes');
|
| 1164 |
+
console.log(' • Layout not saving: Check browser storage limits');
|
| 1165 |
+
console.log(' • QR codes broken: Verify URL includes protocol');
|
| 1166 |
+
console.log(' • Fields misaligned: Check zoom level is 100%');
|
| 1167 |
+
|
| 1168 |
+
console.log('\n=== Ready to use! Check dashboard.html for data management ===');
|
| 1169 |
+
}
|
| 1170 |
+
|
| 1171 |
+
// Auto-show usage on first load
|
| 1172 |
+
if (!localStorage.getItem('pdf_wizard_usage_shown')) {
|
| 1173 |
+
setTimeout(showUsageExamples, 2000);
|
| 1174 |
+
localStorage.setItem('pdf_wizard_usage_shown', 'true');
|
| 1175 |
+
}
|
| 1176 |
+
|
| 1177 |
+
// Example of programmatic usage:
|
| 1178 |
+
/*
|
| 1179 |
+
// 1. Create custom data
|
| 1180 |
+
const customData = [{
|
| 1181 |
+
"1": "John Doe",
|
| 1182 |
+
"2": "Senior Developer",
|
| 1183 |
+
"3": "Engineering",
|
| 1184 |
+
"4": "https://example.com/photo.jpg",
|
| 1185 |
+
"5": "2024-01-15",
|
| 1186 |
+
"6": "2025-01-15",
|
| 1187 |
+
"7": "Tech Corp",
|
| 1188 |
+
"8": "San Francisco",
|
| 1189 |
+
"9": "94105",
|
| 1190 |
+
"10": "USA",
|
| 1191 |
+
"11": "EMP001",
|
| 1192 |
+
"12": "DOC2024001"
|
| 1193 |
+
}];
|
| 1194 |
+
|
| 1195 |
+
// 2. Load data programmatically
|
| 1196 |
+
state.data = customData;
|
| 1197 |
+
populateDataDropdown();
|
| 1198 |
+
showData(0);
|
| 1199 |
+
|
| 1200 |
+
// 3. Enable design mode
|
| 1201 |
+
toggleDesignMode();
|
| 1202 |
+
|
| 1203 |
+
// 4. Export layout programmatically
|
| 1204 |
+
setTimeout(() => {
|
| 1205 |
+
document.getElementById('layout-name-input').value = 'My Custom Layout';
|
| 1206 |
+
exportLayout();
|
| 1207 |
+
}, 5000);
|
| 1208 |
+
|
| 1209 |
+
// 5. Generate PDF with data
|
| 1210 |
+
setTimeout(downloadPDF, 8000);
|
| 1211 |
+
*/
|
style.css
CHANGED
|
@@ -300,7 +300,6 @@ body.design-mode .page:hover::before {
|
|
| 300 |
4%,60% { transform: translate(-2px, 0) skew(0deg); }
|
| 301 |
62% { transform: translate(0, 0) skew(5deg); }
|
| 302 |
}
|
| 303 |
-
|
| 304 |
/* Creative field styling */
|
| 305 |
.field {
|
| 306 |
font-family: 'Comic Neue', cursive;
|
|
@@ -313,6 +312,114 @@ body.design-mode .page:hover::before {
|
|
| 313 |
animation: rainbow 3s ease infinite;
|
| 314 |
}
|
| 315 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 316 |
/* Make the template view more engaging */
|
| 317 |
#template-view {
|
| 318 |
perspective: 1000px;
|
|
|
|
| 300 |
4%,60% { transform: translate(-2px, 0) skew(0deg); }
|
| 301 |
62% { transform: translate(0, 0) skew(5deg); }
|
| 302 |
}
|
|
|
|
| 303 |
/* Creative field styling */
|
| 304 |
.field {
|
| 305 |
font-family: 'Comic Neue', cursive;
|
|
|
|
| 312 |
animation: rainbow 3s ease infinite;
|
| 313 |
}
|
| 314 |
|
| 315 |
+
/* Design Mode Enhancement */
|
| 316 |
+
body.design-mode .field {
|
| 317 |
+
cursor: grab;
|
| 318 |
+
border: 1px dashed #3b82f6 !important;
|
| 319 |
+
background: rgba(59, 130, 246, 0.1);
|
| 320 |
+
min-width: 20px;
|
| 321 |
+
min-height: 1em;
|
| 322 |
+
}
|
| 323 |
+
|
| 324 |
+
body.design-mode .field:hover {
|
| 325 |
+
background: rgba(59, 130, 246, 0.2);
|
| 326 |
+
}
|
| 327 |
+
|
| 328 |
+
body.design-mode .field.selected {
|
| 329 |
+
border: 2px solid #10b981 !important;
|
| 330 |
+
background: rgba(16, 185, 129, 0.1);
|
| 331 |
+
z-index: 50;
|
| 332 |
+
}
|
| 333 |
+
|
| 334 |
+
body.design-mode .page {
|
| 335 |
+
box-shadow: 0 0 0 1px #3b82f6;
|
| 336 |
+
}
|
| 337 |
+
|
| 338 |
+
/* Layout Management Styles */
|
| 339 |
+
#sidebar-design .form-control {
|
| 340 |
+
@apply w-full px-3 py-2 border border-slate-300 dark:border-slate-600 rounded-lg bg-white dark:bg-slate-700 text-slate-800 dark:text-slate-200 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-colors;
|
| 341 |
+
}
|
| 342 |
+
|
| 343 |
+
#sidebar-design .form-control:focus {
|
| 344 |
+
@apply border-blue-500 ring-2 ring-blue-500;
|
| 345 |
+
}
|
| 346 |
+
|
| 347 |
+
/* Import/Export buttons */
|
| 348 |
+
#sidebar-design label[for="layout-import"] {
|
| 349 |
+
@apply cursor-pointer hover:bg-blue-50 dark:hover:bg-blue-900/30 transition-colors;
|
| 350 |
+
}
|
| 351 |
+
|
| 352 |
+
/* Property controls styling */
|
| 353 |
+
#field-controls .form-group {
|
| 354 |
+
@apply mb-4;
|
| 355 |
+
}
|
| 356 |
+
|
| 357 |
+
#field-controls label {
|
| 358 |
+
@apply block text-xs font-bold text-slate-500 dark:text-slate-400 uppercase mb-2;
|
| 359 |
+
}
|
| 360 |
+
|
| 361 |
+
#field-controls input[type="number"],
|
| 362 |
+
#field-controls select,
|
| 363 |
+
#field-controls input[type="color"] {
|
| 364 |
+
@apply w-full;
|
| 365 |
+
}
|
| 366 |
+
|
| 367 |
+
/* Layout name input */
|
| 368 |
+
#layout-name-input {
|
| 369 |
+
@apply font-mono text-sm;
|
| 370 |
+
}
|
| 371 |
+
|
| 372 |
+
/* Success feedback for saved layouts */
|
| 373 |
+
@keyframes saved-pulse {
|
| 374 |
+
0% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.7); }
|
| 375 |
+
70% { box-shadow: 0 0 0 10px rgba(16, 185, 129, 0); }
|
| 376 |
+
100% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0); }
|
| 377 |
+
}
|
| 378 |
+
|
| 379 |
+
.saved-indicator {
|
| 380 |
+
animation: saved-pulse 1s;
|
| 381 |
+
}
|
| 382 |
+
|
| 383 |
+
/* Enhanced field selection */
|
| 384 |
+
body.design-mode .field.selected::before {
|
| 385 |
+
content: '';
|
| 386 |
+
position: absolute;
|
| 387 |
+
top: -4px;
|
| 388 |
+
left: -4px;
|
| 389 |
+
right: -4px;
|
| 390 |
+
bottom: -4px;
|
| 391 |
+
border: 2px solid #10b981;
|
| 392 |
+
border-radius: 4px;
|
| 393 |
+
pointer-events: none;
|
| 394 |
+
animation: selected-glow 1s ease-in-out infinite alternate;
|
| 395 |
+
}
|
| 396 |
+
|
| 397 |
+
@keyframes selected-glow {
|
| 398 |
+
from { opacity: 0.5; }
|
| 399 |
+
to { opacity: 1; }
|
| 400 |
+
}
|
| 401 |
+
|
| 402 |
+
/* Make the design panel more prominent */
|
| 403 |
+
#sidebar-design {
|
| 404 |
+
background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%);
|
| 405 |
+
}
|
| 406 |
+
|
| 407 |
+
[data-theme="dark"] #sidebar-design {
|
| 408 |
+
background: linear-gradient(135deg, #1e293b 0%, #334155 100%);
|
| 409 |
+
}
|
| 410 |
+
|
| 411 |
+
/* Usage examples styling */
|
| 412 |
+
.usage-example {
|
| 413 |
+
@apply bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg p-4 mb-4;
|
| 414 |
+
}
|
| 415 |
+
|
| 416 |
+
.usage-example h4 {
|
| 417 |
+
@apply font-bold text-blue-800 dark:text-blue-200 mb-2;
|
| 418 |
+
}
|
| 419 |
+
|
| 420 |
+
.usage-example code {
|
| 421 |
+
@apply bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded text-sm font-mono;
|
| 422 |
+
}
|
| 423 |
/* Make the template view more engaging */
|
| 424 |
#template-view {
|
| 425 |
perspective: 1000px;
|