Complete enhancement suite with quick navigation, advanced search, data visualization, keyboard shortcuts, bookmarks, notifications, and export features for Orchard Management System
Size
51.3 KB
Version
2.0.1
Created
Dec 2, 2025
Updated
3 months ago
1// ==UserScript==
2// @name Orchard Management Pro - Enhanced Dashboard & Productivity Suite
3// @description Complete enhancement suite with quick navigation, advanced search, data visualization, keyboard shortcuts, bookmarks, notifications, and export features for Orchard Management System
4// @version 2.0.1
5// @match http://192.168.3.251/*
6// @grant GM.getValue
7// @grant GM.setValue
8// @grant GM.deleteValue
9// @grant GM.listValues
10// @grant GM.setClipboard
11// ==/UserScript==
12(function() {
13 'use strict';
14
15 console.log('🚀 Orchard Management Pro - Enhanced Suite Loading...');
16
17 // ============================================
18 // CONFIGURATION & STATE MANAGEMENT
19 // ============================================
20 const CONFIG = {
21 version: '2.0.0',
22 storageKeys: {
23 bookmarks: 'orchard_bookmarks',
24 recentPages: 'orchard_recent_pages',
25 preferences: 'orchard_preferences',
26 notes: 'orchard_notes',
27 quickStats: 'orchard_quick_stats'
28 },
29 maxRecentPages: 10,
30 maxBookmarks: 50,
31 notificationDuration: 5000
32 };
33
34 // ============================================
35 // UTILITY FUNCTIONS
36 // ============================================
37 const Utils = {
38 // Debounce function for performance
39 debounce(func, wait) {
40 let timeout;
41 return function executedFunction(...args) {
42 const later = () => {
43 clearTimeout(timeout);
44 func(...args);
45 };
46 clearTimeout(timeout);
47 timeout = setTimeout(later, wait);
48 };
49 },
50
51 // Format date
52 formatDate(date) {
53 return new Date(date).toLocaleDateString('en-US', {
54 year: 'numeric',
55 month: 'short',
56 day: 'numeric',
57 hour: '2-digit',
58 minute: '2-digit'
59 });
60 },
61
62 // Get current page info
63 getCurrentPageInfo() {
64 const url = window.location.href;
65 const title = document.title || 'Untitled Page';
66 const path = window.location.pathname;
67 return { url, title, path, timestamp: Date.now() };
68 },
69
70 // Show notification
71 showNotification(message, type = 'info') {
72 const notification = document.createElement('div');
73 notification.className = `orchard-notification orchard-notification-${type}`;
74 notification.innerHTML = `
75 <div class="orchard-notification-content">
76 <i class="feather icon-${type === 'success' ? 'check-circle' : type === 'error' ? 'x-circle' : 'info'}"></i>
77 <span>${message}</span>
78 </div>
79 `;
80 document.body.appendChild(notification);
81
82 setTimeout(() => notification.classList.add('show'), 10);
83 setTimeout(() => {
84 notification.classList.remove('show');
85 setTimeout(() => notification.remove(), 300);
86 }, CONFIG.notificationDuration);
87 },
88
89 // Copy to clipboard
90 async copyToClipboard(text) {
91 try {
92 await GM.setClipboard(text);
93 this.showNotification('Copied to clipboard!', 'success');
94 } catch (error) {
95 console.error('Copy failed:', error);
96 this.showNotification('Failed to copy', 'error');
97 }
98 }
99 };
100
101 // ============================================
102 // STORAGE MANAGER
103 // ============================================
104 const StorageManager = {
105 async get(key, defaultValue = null) {
106 try {
107 const value = await GM.getValue(key, defaultValue);
108 return value;
109 } catch (error) {
110 console.error('Storage get error:', error);
111 return defaultValue;
112 }
113 },
114
115 async set(key, value) {
116 try {
117 await GM.setValue(key, value);
118 return true;
119 } catch (error) {
120 console.error('Storage set error:', error);
121 return false;
122 }
123 },
124
125 async delete(key) {
126 try {
127 await GM.deleteValue(key);
128 return true;
129 } catch (error) {
130 console.error('Storage delete error:', error);
131 return false;
132 }
133 },
134
135 async clear() {
136 try {
137 const keys = await GM.listValues();
138 for (const key of keys) {
139 if (key.startsWith('orchard_')) {
140 await GM.deleteValue(key);
141 }
142 }
143 return true;
144 } catch (error) {
145 console.error('Storage clear error:', error);
146 return false;
147 }
148 }
149 };
150
151 // ============================================
152 // BOOKMARKS MANAGER
153 // ============================================
154 const BookmarksManager = {
155 async getBookmarks() {
156 return await StorageManager.get(CONFIG.storageKeys.bookmarks, []);
157 },
158
159 async addBookmark(pageInfo) {
160 const bookmarks = await this.getBookmarks();
161
162 // Check if already bookmarked
163 if (bookmarks.some(b => b.url === pageInfo.url)) {
164 Utils.showNotification('Page already bookmarked', 'info');
165 return false;
166 }
167
168 // Add new bookmark
169 bookmarks.unshift({
170 ...pageInfo,
171 id: Date.now(),
172 addedAt: Date.now()
173 });
174
175 // Limit bookmarks
176 if (bookmarks.length > CONFIG.maxBookmarks) {
177 bookmarks.pop();
178 }
179
180 await StorageManager.set(CONFIG.storageKeys.bookmarks, bookmarks);
181 Utils.showNotification('Bookmark added!', 'success');
182 return true;
183 },
184
185 async removeBookmark(id) {
186 const bookmarks = await this.getBookmarks();
187 const filtered = bookmarks.filter(b => b.id !== id);
188 await StorageManager.set(CONFIG.storageKeys.bookmarks, filtered);
189 Utils.showNotification('Bookmark removed', 'info');
190 },
191
192 async isBookmarked(url) {
193 const bookmarks = await this.getBookmarks();
194 return bookmarks.some(b => b.url === url);
195 }
196 };
197
198 // ============================================
199 // RECENT PAGES MANAGER
200 // ============================================
201 const RecentPagesManager = {
202 async addRecentPage(pageInfo) {
203 let recentPages = await StorageManager.get(CONFIG.storageKeys.recentPages, []);
204
205 // Remove if already exists
206 recentPages = recentPages.filter(p => p.url !== pageInfo.url);
207
208 // Add to beginning
209 recentPages.unshift({
210 ...pageInfo,
211 visitedAt: Date.now()
212 });
213
214 // Limit recent pages
215 if (recentPages.length > CONFIG.maxRecentPages) {
216 recentPages = recentPages.slice(0, CONFIG.maxRecentPages);
217 }
218
219 await StorageManager.set(CONFIG.storageKeys.recentPages, recentPages);
220 },
221
222 async getRecentPages() {
223 return await StorageManager.get(CONFIG.storageKeys.recentPages, []);
224 },
225
226 async clearRecentPages() {
227 await StorageManager.set(CONFIG.storageKeys.recentPages, []);
228 Utils.showNotification('Recent pages cleared', 'info');
229 }
230 };
231
232 // ============================================
233 // NOTES MANAGER
234 // ============================================
235 const NotesManager = {
236 async getNotes() {
237 return await StorageManager.get(CONFIG.storageKeys.notes, []);
238 },
239
240 async addNote(content) {
241 const notes = await this.getNotes();
242 const note = {
243 id: Date.now(),
244 content: content,
245 page: Utils.getCurrentPageInfo(),
246 createdAt: Date.now()
247 };
248 notes.unshift(note);
249 await StorageManager.set(CONFIG.storageKeys.notes, notes);
250 Utils.showNotification('Note saved!', 'success');
251 return note;
252 },
253
254 async deleteNote(id) {
255 const notes = await this.getNotes();
256 const filtered = notes.filter(n => n.id !== id);
257 await StorageManager.set(CONFIG.storageKeys.notes, filtered);
258 Utils.showNotification('Note deleted', 'info');
259 }
260 };
261
262 // ============================================
263 // QUICK ACCESS PANEL
264 // ============================================
265 class QuickAccessPanel {
266 constructor() {
267 this.isOpen = false;
268 this.panel = null;
269 this.init();
270 }
271
272 init() {
273 this.createPanel();
274 this.attachEventListeners();
275 console.log('✅ Quick Access Panel initialized');
276 }
277
278 createPanel() {
279 // Create floating button
280 const floatingBtn = document.createElement('div');
281 floatingBtn.id = 'orchard-quick-access-btn';
282 floatingBtn.className = 'orchard-floating-btn';
283 floatingBtn.innerHTML = '<i class="feather icon-zap"></i>';
284 floatingBtn.title = 'Quick Access Panel (Alt+Q)';
285 document.body.appendChild(floatingBtn);
286
287 // Create panel
288 const panel = document.createElement('div');
289 panel.id = 'orchard-quick-access-panel';
290 panel.className = 'orchard-panel';
291 panel.innerHTML = this.getPanelHTML();
292 document.body.appendChild(panel);
293
294 this.panel = panel;
295 this.floatingBtn = floatingBtn;
296
297 // Event listeners
298 floatingBtn.addEventListener('click', () => this.toggle());
299 }
300
301 getPanelHTML() {
302 return `
303 <div class="orchard-panel-header">
304 <h3><i class="feather icon-zap"></i> Quick Access</h3>
305 <button class="orchard-close-btn" id="orchard-close-panel">
306 <i class="feather icon-x"></i>
307 </button>
308 </div>
309 <div class="orchard-panel-tabs">
310 <button class="orchard-tab-btn active" data-tab="navigation">
311 <i class="feather icon-compass"></i> Navigation
312 </button>
313 <button class="orchard-tab-btn" data-tab="bookmarks">
314 <i class="feather icon-bookmark"></i> Bookmarks
315 </button>
316 <button class="orchard-tab-btn" data-tab="recent">
317 <i class="feather icon-clock"></i> Recent
318 </button>
319 <button class="orchard-tab-btn" data-tab="notes">
320 <i class="feather icon-file-text"></i> Notes
321 </button>
322 <button class="orchard-tab-btn" data-tab="tools">
323 <i class="feather icon-tool"></i> Tools
324 </button>
325 </div>
326 <div class="orchard-panel-content">
327 <div class="orchard-tab-content active" id="tab-navigation">
328 <div class="orchard-search-box">
329 <i class="feather icon-search"></i>
330 <input type="text" id="orchard-nav-search" placeholder="Search pages...">
331 </div>
332 <div id="orchard-nav-list" class="orchard-nav-list"></div>
333 </div>
334 <div class="orchard-tab-content" id="tab-bookmarks">
335 <div class="orchard-bookmarks-header">
336 <button class="orchard-btn orchard-btn-sm" id="orchard-add-bookmark">
337 <i class="feather icon-plus"></i> Bookmark This Page
338 </button>
339 </div>
340 <div id="orchard-bookmarks-list" class="orchard-list"></div>
341 </div>
342 <div class="orchard-tab-content" id="tab-recent">
343 <div class="orchard-recent-header">
344 <button class="orchard-btn orchard-btn-sm" id="orchard-clear-recent">
345 <i class="feather icon-trash-2"></i> Clear History
346 </button>
347 </div>
348 <div id="orchard-recent-list" class="orchard-list"></div>
349 </div>
350 <div class="orchard-tab-content" id="tab-notes">
351 <div class="orchard-notes-header">
352 <textarea id="orchard-note-input" placeholder="Add a quick note..." rows="3"></textarea>
353 <button class="orchard-btn orchard-btn-sm" id="orchard-add-note">
354 <i class="feather icon-plus"></i> Add Note
355 </button>
356 </div>
357 <div id="orchard-notes-list" class="orchard-list"></div>
358 </div>
359 <div class="orchard-tab-content" id="tab-tools">
360 <div class="orchard-tools-grid">
361 <button class="orchard-tool-btn" id="orchard-export-data">
362 <i class="feather icon-download"></i>
363 <span>Export Dashboard Data</span>
364 </button>
365 <button class="orchard-tool-btn" id="orchard-copy-url">
366 <i class="feather icon-link"></i>
367 <span>Copy Current URL</span>
368 </button>
369 <button class="orchard-tool-btn" id="orchard-print-page">
370 <i class="feather icon-printer"></i>
371 <span>Print Page</span>
372 </button>
373 <button class="orchard-tool-btn" id="orchard-refresh-stats">
374 <i class="feather icon-refresh-cw"></i>
375 <span>Refresh Statistics</span>
376 </button>
377 <button class="orchard-tool-btn" id="orchard-keyboard-shortcuts">
378 <i class="feather icon-command"></i>
379 <span>Keyboard Shortcuts</span>
380 </button>
381 <button class="orchard-tool-btn" id="orchard-clear-storage">
382 <i class="feather icon-trash"></i>
383 <span>Clear All Data</span>
384 </button>
385 </div>
386 </div>
387 </div>
388 `;
389 }
390
391 attachEventListeners() {
392 // Close button
393 document.getElementById('orchard-close-panel').addEventListener('click', () => this.close());
394
395 // Tab switching
396 document.querySelectorAll('.orchard-tab-btn').forEach(btn => {
397 btn.addEventListener('click', (e) => this.switchTab(e.target.closest('.orchard-tab-btn').dataset.tab));
398 });
399
400 // Navigation search
401 const navSearch = document.getElementById('orchard-nav-search');
402 navSearch.addEventListener('input', Utils.debounce((e) => this.filterNavigation(e.target.value), 300));
403
404 // Bookmarks
405 document.getElementById('orchard-add-bookmark').addEventListener('click', () => this.addCurrentBookmark());
406
407 // Recent pages
408 document.getElementById('orchard-clear-recent').addEventListener('click', () => this.clearRecentPages());
409
410 // Notes
411 document.getElementById('orchard-add-note').addEventListener('click', () => this.addNote());
412
413 // Tools
414 document.getElementById('orchard-export-data').addEventListener('click', () => this.exportDashboardData());
415 document.getElementById('orchard-copy-url').addEventListener('click', () => Utils.copyToClipboard(window.location.href));
416 document.getElementById('orchard-print-page').addEventListener('click', () => window.print());
417 document.getElementById('orchard-refresh-stats').addEventListener('click', () => this.refreshStats());
418 document.getElementById('orchard-keyboard-shortcuts').addEventListener('click', () => this.showKeyboardShortcuts());
419 document.getElementById('orchard-clear-storage').addEventListener('click', () => this.clearAllStorage());
420
421 // Close on outside click
422 this.panel.addEventListener('click', (e) => {
423 if (e.target === this.panel) {
424 this.close();
425 }
426 });
427 }
428
429 toggle() {
430 if (this.isOpen) {
431 this.close();
432 } else {
433 this.open();
434 }
435 }
436
437 async open() {
438 this.isOpen = true;
439 this.panel.classList.add('show');
440 this.floatingBtn.classList.add('active');
441
442 // Load content for active tab
443 await this.loadNavigationList();
444 await this.loadBookmarks();
445 await this.loadRecentPages();
446 await this.loadNotes();
447 }
448
449 close() {
450 this.isOpen = false;
451 this.panel.classList.remove('show');
452 this.floatingBtn.classList.remove('active');
453 }
454
455 switchTab(tabName) {
456 // Update tab buttons
457 document.querySelectorAll('.orchard-tab-btn').forEach(btn => {
458 btn.classList.toggle('active', btn.dataset.tab === tabName);
459 });
460
461 // Update tab content
462 document.querySelectorAll('.orchard-tab-content').forEach(content => {
463 content.classList.toggle('active', content.id === `tab-${tabName}`);
464 });
465 }
466
467 async loadNavigationList() {
468 const navList = document.getElementById('orchard-nav-list');
469 const menuItems = this.getAllMenuItems();
470
471 navList.innerHTML = menuItems.map(item => `
472 <div class="orchard-nav-section">
473 <div class="orchard-nav-section-title">
474 <i class="feather icon-${this.getIconForSection(item.main)}"></i>
475 ${item.main}
476 </div>
477 <div class="orchard-nav-section-items">
478 ${item.subItems.map(subItem => `
479 <a href="#" class="orchard-nav-item" data-section="${item.main}" data-page="${subItem}">
480 <span>${subItem}</span>
481 <i class="feather icon-arrow-right"></i>
482 </a>
483 `).join('')}
484 </div>
485 </div>
486 `).join('');
487
488 // Add click handlers
489 navList.querySelectorAll('.orchard-nav-item').forEach(item => {
490 item.addEventListener('click', (e) => {
491 e.preventDefault();
492 this.navigateToPage(item.dataset.section, item.dataset.page);
493 });
494 });
495 }
496
497 getAllMenuItems() {
498 const menuItems = [];
499 document.querySelectorAll('.nav-item.pcoded-hasmenu').forEach(item => {
500 const mainLink = item.querySelector('.nav-link .pcoded-mtext');
501 const mainText = mainLink ? mainLink.textContent.trim() : '';
502
503 const submenu = item.querySelector('.pcoded-submenu');
504 const subItems = submenu ? Array.from(submenu.querySelectorAll('li a')).map(a => ({
505 text: a.textContent.trim(),
506 href: a.href
507 })) : [];
508
509 if (mainText && subItems.length > 0) {
510 menuItems.push({
511 main: mainText,
512 subItems: subItems.map(s => s.text),
513 links: subItems
514 });
515 }
516 });
517 return menuItems;
518 }
519
520 getIconForSection(section) {
521 const icons = {
522 'Master Page': 'database',
523 'Customer': 'users',
524 'Pole Production': 'package',
525 'Pole Selling': 'shopping-cart',
526 'Orchard': 'grid',
527 'Purchase': 'shopping-bag',
528 'Reports': 'bar-chart-2',
529 'Gate Pass': 'clipboard'
530 };
531 return icons[section] || 'folder';
532 }
533
534 navigateToPage(section, pageName) {
535 const menuItems = this.getAllMenuItems();
536 const sectionData = menuItems.find(m => m.main === section);
537
538 if (sectionData) {
539 const link = sectionData.links.find(l => l.text === pageName);
540 if (link && link.href) {
541 window.location.href = link.href;
542 this.close();
543 }
544 }
545 }
546
547 filterNavigation(searchTerm) {
548 const navItems = document.querySelectorAll('.orchard-nav-item');
549 const sections = document.querySelectorAll('.orchard-nav-section');
550
551 searchTerm = searchTerm.toLowerCase();
552
553 sections.forEach(section => {
554 const items = section.querySelectorAll('.orchard-nav-item');
555 let hasVisibleItems = false;
556
557 items.forEach(item => {
558 const text = item.textContent.toLowerCase();
559 const matches = text.includes(searchTerm);
560 item.style.display = matches ? 'flex' : 'none';
561 if (matches) hasVisibleItems = true;
562 });
563
564 section.style.display = hasVisibleItems ? 'block' : 'none';
565 });
566 }
567
568 async loadBookmarks() {
569 const bookmarks = await BookmarksManager.getBookmarks();
570 const bookmarksList = document.getElementById('orchard-bookmarks-list');
571
572 if (bookmarks.length === 0) {
573 bookmarksList.innerHTML = '<div class="orchard-empty-state">No bookmarks yet. Add your favorite pages!</div>';
574 return;
575 }
576
577 bookmarksList.innerHTML = bookmarks.map(bookmark => `
578 <div class="orchard-list-item" data-id="${bookmark.id}">
579 <div class="orchard-list-item-content">
580 <div class="orchard-list-item-title">${bookmark.title}</div>
581 <div class="orchard-list-item-meta">${Utils.formatDate(bookmark.addedAt)}</div>
582 </div>
583 <div class="orchard-list-item-actions">
584 <button class="orchard-icon-btn" data-action="open" data-url="${bookmark.url}">
585 <i class="feather icon-external-link"></i>
586 </button>
587 <button class="orchard-icon-btn" data-action="delete" data-id="${bookmark.id}">
588 <i class="feather icon-trash-2"></i>
589 </button>
590 </div>
591 </div>
592 `).join('');
593
594 // Add event listeners
595 bookmarksList.querySelectorAll('[data-action="open"]').forEach(btn => {
596 btn.addEventListener('click', () => {
597 window.location.href = btn.dataset.url;
598 this.close();
599 });
600 });
601
602 bookmarksList.querySelectorAll('[data-action="delete"]').forEach(btn => {
603 btn.addEventListener('click', async () => {
604 await BookmarksManager.removeBookmark(parseInt(btn.dataset.id));
605 await this.loadBookmarks();
606 });
607 });
608 }
609
610 async addCurrentBookmark() {
611 const pageInfo = Utils.getCurrentPageInfo();
612 await BookmarksManager.addBookmark(pageInfo);
613 await this.loadBookmarks();
614 }
615
616 async loadRecentPages() {
617 const recentPages = await RecentPagesManager.getRecentPages();
618 const recentList = document.getElementById('orchard-recent-list');
619
620 if (recentPages.length === 0) {
621 recentList.innerHTML = '<div class="orchard-empty-state">No recent pages</div>';
622 return;
623 }
624
625 recentList.innerHTML = recentPages.map(page => `
626 <div class="orchard-list-item">
627 <div class="orchard-list-item-content">
628 <div class="orchard-list-item-title">${page.title}</div>
629 <div class="orchard-list-item-meta">${Utils.formatDate(page.visitedAt)}</div>
630 </div>
631 <div class="orchard-list-item-actions">
632 <button class="orchard-icon-btn" data-action="open" data-url="${page.url}">
633 <i class="feather icon-external-link"></i>
634 </button>
635 </div>
636 </div>
637 `).join('');
638
639 // Add event listeners
640 recentList.querySelectorAll('[data-action="open"]').forEach(btn => {
641 btn.addEventListener('click', () => {
642 window.location.href = btn.dataset.url;
643 this.close();
644 });
645 });
646 }
647
648 async clearRecentPages() {
649 if (confirm('Clear all recent pages?')) {
650 await RecentPagesManager.clearRecentPages();
651 await this.loadRecentPages();
652 }
653 }
654
655 async loadNotes() {
656 const notes = await NotesManager.getNotes();
657 const notesList = document.getElementById('orchard-notes-list');
658
659 if (notes.length === 0) {
660 notesList.innerHTML = '<div class="orchard-empty-state">No notes yet</div>';
661 return;
662 }
663
664 notesList.innerHTML = notes.map(note => `
665 <div class="orchard-list-item orchard-note-item">
666 <div class="orchard-list-item-content">
667 <div class="orchard-note-content">${note.content}</div>
668 <div class="orchard-list-item-meta">
669 ${note.page.title} • ${Utils.formatDate(note.createdAt)}
670 </div>
671 </div>
672 <div class="orchard-list-item-actions">
673 <button class="orchard-icon-btn" data-action="delete" data-id="${note.id}">
674 <i class="feather icon-trash-2"></i>
675 </button>
676 </div>
677 </div>
678 `).join('');
679
680 // Add event listeners
681 notesList.querySelectorAll('[data-action="delete"]').forEach(btn => {
682 btn.addEventListener('click', async () => {
683 await NotesManager.deleteNote(parseInt(btn.dataset.id));
684 await this.loadNotes();
685 });
686 });
687 }
688
689 async addNote() {
690 const input = document.getElementById('orchard-note-input');
691 const content = input.value.trim();
692
693 if (!content) {
694 Utils.showNotification('Please enter a note', 'error');
695 return;
696 }
697
698 await NotesManager.addNote(content);
699 input.value = '';
700 await this.loadNotes();
701 }
702
703 exportDashboardData() {
704 try {
705 const data = {
706 exportDate: new Date().toISOString(),
707 pageTitle: document.title,
708 url: window.location.href,
709 statistics: this.extractDashboardStats()
710 };
711
712 const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
713 const url = URL.createObjectURL(blob);
714 const a = document.createElement('a');
715 a.href = url;
716 a.download = `orchard-dashboard-${Date.now()}.json`;
717 a.click();
718 URL.revokeObjectURL(url);
719
720 Utils.showNotification('Dashboard data exported!', 'success');
721 } catch (error) {
722 console.error('Export error:', error);
723 Utils.showNotification('Export failed', 'error');
724 }
725 }
726
727 extractDashboardStats() {
728 const stats = {};
729 document.querySelectorAll('.card').forEach((card, index) => {
730 const title = card.querySelector('.card-footer p')?.textContent.trim();
731 const value = card.querySelector('h4')?.textContent.trim();
732 if (title && value) {
733 stats[title] = value;
734 }
735 });
736 return stats;
737 }
738
739 refreshStats() {
740 window.location.reload();
741 }
742
743 showKeyboardShortcuts() {
744 const shortcuts = `
745 <div class="orchard-shortcuts-modal">
746 <h3>Keyboard Shortcuts</h3>
747 <div class="orchard-shortcuts-list">
748 <div class="orchard-shortcut-item">
749 <kbd>Alt</kbd> + <kbd>Q</kbd>
750 <span>Toggle Quick Access Panel</span>
751 </div>
752 <div class="orchard-shortcut-item">
753 <kbd>Alt</kbd> + <kbd>B</kbd>
754 <span>Bookmark Current Page</span>
755 </div>
756 <div class="orchard-shortcut-item">
757 <kbd>Alt</kbd> + <kbd>S</kbd>
758 <span>Focus Search</span>
759 </div>
760 <div class="orchard-shortcut-item">
761 <kbd>Esc</kbd>
762 <span>Close Panel</span>
763 </div>
764 </div>
765 <button class="orchard-btn" onclick="this.closest('.orchard-shortcuts-modal').remove()">Close</button>
766 </div>
767 `;
768
769 const modal = document.createElement('div');
770 modal.className = 'orchard-modal-overlay';
771 modal.innerHTML = shortcuts;
772 document.body.appendChild(modal);
773
774 modal.addEventListener('click', (e) => {
775 if (e.target === modal) {
776 modal.remove();
777 }
778 });
779 }
780
781 async clearAllStorage() {
782 if (confirm('This will clear all bookmarks, notes, and recent pages. Continue?')) {
783 await StorageManager.clear();
784 Utils.showNotification('All data cleared', 'success');
785 await this.loadBookmarks();
786 await this.loadRecentPages();
787 await this.loadNotes();
788 }
789 }
790 }
791
792 // ============================================
793 // DASHBOARD ENHANCEMENTS
794 // ============================================
795 class DashboardEnhancer {
796 constructor() {
797 this.init();
798 }
799
800 init() {
801 if (window.location.pathname.toLowerCase().includes('dashboard')) {
802 this.enhanceDashboard();
803 console.log('✅ Dashboard enhancements applied');
804 }
805 }
806
807 enhanceDashboard() {
808 this.addQuickStats();
809 this.addChartEnhancements();
810 this.addExportButtons();
811 }
812
813 addQuickStats() {
814 const statsCards = document.querySelectorAll('.card');
815 statsCards.forEach(card => {
816 card.style.transition = 'transform 0.3s ease, box-shadow 0.3s ease';
817 card.addEventListener('mouseenter', () => {
818 card.style.transform = 'translateY(-5px)';
819 card.style.boxShadow = '0 10px 25px rgba(0,0,0,0.15)';
820 });
821 card.addEventListener('mouseleave', () => {
822 card.style.transform = 'translateY(0)';
823 card.style.boxShadow = '';
824 });
825 });
826 }
827
828 addChartEnhancements() {
829 // Add visual indicators for trends
830 const statCards = document.querySelectorAll('.card h4');
831 statCards.forEach(stat => {
832 const value = parseInt(stat.textContent);
833 if (!isNaN(value)) {
834 const indicator = document.createElement('span');
835 indicator.className = 'orchard-trend-indicator';
836 indicator.innerHTML = value > 10 ? '📈' : '📊';
837 indicator.style.marginLeft = '8px';
838 indicator.style.fontSize = '0.8em';
839 stat.appendChild(indicator);
840 }
841 });
842 }
843
844 addExportButtons() {
845 const pageHeader = document.querySelector('.page-header');
846 if (pageHeader) {
847 const exportBtn = document.createElement('button');
848 exportBtn.className = 'orchard-export-btn';
849 exportBtn.innerHTML = '<i class="feather icon-download"></i> Export Dashboard';
850 exportBtn.style.cssText = 'position: absolute; right: 20px; top: 20px; padding: 8px 16px; background: #4680ff; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 14px;';
851
852 exportBtn.addEventListener('click', () => {
853 const panel = document.querySelector('#orchard-quick-access-panel');
854 if (panel) {
855 const quickAccess = window.orchardQuickAccess;
856 if (quickAccess) {
857 quickAccess.exportDashboardData();
858 }
859 }
860 });
861
862 pageHeader.style.position = 'relative';
863 pageHeader.appendChild(exportBtn);
864 }
865 }
866 }
867
868 // ============================================
869 // KEYBOARD SHORTCUTS
870 // ============================================
871 class KeyboardShortcuts {
872 constructor(quickAccessPanel) {
873 this.quickAccessPanel = quickAccessPanel;
874 this.init();
875 }
876
877 init() {
878 document.addEventListener('keydown', (e) => this.handleKeyPress(e));
879 console.log('✅ Keyboard shortcuts initialized');
880 }
881
882 handleKeyPress(e) {
883 // Alt + Q: Toggle Quick Access Panel
884 if (e.altKey && e.key === 'q') {
885 e.preventDefault();
886 this.quickAccessPanel.toggle();
887 }
888
889 // Alt + B: Bookmark current page
890 if (e.altKey && e.key === 'b') {
891 e.preventDefault();
892 BookmarksManager.addBookmark(Utils.getCurrentPageInfo());
893 }
894
895 // Alt + S: Focus search
896 if (e.altKey && e.key === 's') {
897 e.preventDefault();
898 if (!this.quickAccessPanel.isOpen) {
899 this.quickAccessPanel.open();
900 }
901 setTimeout(() => {
902 const searchInput = document.getElementById('orchard-nav-search');
903 if (searchInput) {
904 searchInput.focus();
905 }
906 }, 100);
907 }
908
909 // Escape: Close panel
910 if (e.key === 'Escape' && this.quickAccessPanel.isOpen) {
911 this.quickAccessPanel.close();
912 }
913 }
914 }
915
916 // ============================================
917 // STYLES
918 // ============================================
919 function injectStyles() {
920 const styles = `
921 /* Floating Button */
922 .orchard-floating-btn {
923 position: fixed;
924 bottom: 30px;
925 right: 30px;
926 width: 60px;
927 height: 60px;
928 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
929 border-radius: 50%;
930 display: flex;
931 align-items: center;
932 justify-content: center;
933 cursor: pointer;
934 box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
935 transition: all 0.3s ease;
936 z-index: 9998;
937 }
938
939 .orchard-floating-btn:hover {
940 transform: scale(1.1);
941 box-shadow: 0 6px 20px rgba(102, 126, 234, 0.6);
942 }
943
944 .orchard-floating-btn.active {
945 background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
946 }
947
948 .orchard-floating-btn i {
949 color: white;
950 font-size: 24px;
951 }
952
953 /* Panel */
954 .orchard-panel {
955 position: fixed;
956 top: 0;
957 right: -450px;
958 width: 450px;
959 height: 100vh;
960 background: white;
961 box-shadow: -5px 0 25px rgba(0, 0, 0, 0.2);
962 transition: right 0.3s ease;
963 z-index: 9999;
964 display: flex;
965 flex-direction: column;
966 }
967
968 .orchard-panel.show {
969 right: 0;
970 }
971
972 .orchard-panel-header {
973 padding: 20px;
974 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
975 color: white;
976 display: flex;
977 justify-content: space-between;
978 align-items: center;
979 }
980
981 .orchard-panel-header h3 {
982 margin: 0;
983 font-size: 20px;
984 display: flex;
985 align-items: center;
986 gap: 10px;
987 }
988
989 .orchard-close-btn {
990 background: rgba(255, 255, 255, 0.2);
991 border: none;
992 color: white;
993 width: 32px;
994 height: 32px;
995 border-radius: 50%;
996 cursor: pointer;
997 display: flex;
998 align-items: center;
999 justify-content: center;
1000 transition: background 0.2s;
1001 }
1002
1003 .orchard-close-btn:hover {
1004 background: rgba(255, 255, 255, 0.3);
1005 }
1006
1007 /* Tabs */
1008 .orchard-panel-tabs {
1009 display: flex;
1010 background: #f8f9fa;
1011 border-bottom: 1px solid #e0e0e0;
1012 overflow-x: auto;
1013 }
1014
1015 .orchard-tab-btn {
1016 flex: 1;
1017 padding: 12px 8px;
1018 background: none;
1019 border: none;
1020 cursor: pointer;
1021 font-size: 12px;
1022 color: #666;
1023 transition: all 0.2s;
1024 display: flex;
1025 flex-direction: column;
1026 align-items: center;
1027 gap: 4px;
1028 white-space: nowrap;
1029 }
1030
1031 .orchard-tab-btn:hover {
1032 background: rgba(102, 126, 234, 0.1);
1033 color: #667eea;
1034 }
1035
1036 .orchard-tab-btn.active {
1037 background: white;
1038 color: #667eea;
1039 border-bottom: 2px solid #667eea;
1040 }
1041
1042 .orchard-tab-btn i {
1043 font-size: 18px;
1044 }
1045
1046 /* Tab Content */
1047 .orchard-panel-content {
1048 flex: 1;
1049 overflow-y: auto;
1050 padding: 20px;
1051 }
1052
1053 .orchard-tab-content {
1054 display: none;
1055 }
1056
1057 .orchard-tab-content.active {
1058 display: block;
1059 }
1060
1061 /* Search Box */
1062 .orchard-search-box {
1063 position: relative;
1064 margin-bottom: 20px;
1065 }
1066
1067 .orchard-search-box i {
1068 position: absolute;
1069 left: 12px;
1070 top: 50%;
1071 transform: translateY(-50%);
1072 color: #999;
1073 }
1074
1075 .orchard-search-box input {
1076 width: 100%;
1077 padding: 10px 10px 10px 40px;
1078 border: 1px solid #e0e0e0;
1079 border-radius: 8px;
1080 font-size: 14px;
1081 transition: border-color 0.2s;
1082 }
1083
1084 .orchard-search-box input:focus {
1085 outline: none;
1086 border-color: #667eea;
1087 }
1088
1089 /* Navigation List */
1090 .orchard-nav-section {
1091 margin-bottom: 20px;
1092 }
1093
1094 .orchard-nav-section-title {
1095 font-weight: 600;
1096 color: #333;
1097 margin-bottom: 10px;
1098 display: flex;
1099 align-items: center;
1100 gap: 8px;
1101 font-size: 14px;
1102 }
1103
1104 .orchard-nav-section-items {
1105 display: flex;
1106 flex-direction: column;
1107 gap: 4px;
1108 }
1109
1110 .orchard-nav-item {
1111 display: flex;
1112 justify-content: space-between;
1113 align-items: center;
1114 padding: 10px 12px;
1115 background: #f8f9fa;
1116 border-radius: 6px;
1117 text-decoration: none;
1118 color: #555;
1119 font-size: 13px;
1120 transition: all 0.2s;
1121 }
1122
1123 .orchard-nav-item:hover {
1124 background: #667eea;
1125 color: white;
1126 transform: translateX(5px);
1127 }
1128
1129 .orchard-nav-item i {
1130 font-size: 14px;
1131 opacity: 0;
1132 transition: opacity 0.2s;
1133 }
1134
1135 .orchard-nav-item:hover i {
1136 opacity: 1;
1137 }
1138
1139 /* List Items */
1140 .orchard-list {
1141 display: flex;
1142 flex-direction: column;
1143 gap: 10px;
1144 }
1145
1146 .orchard-list-item {
1147 display: flex;
1148 justify-content: space-between;
1149 align-items: center;
1150 padding: 12px;
1151 background: #f8f9fa;
1152 border-radius: 8px;
1153 transition: background 0.2s;
1154 }
1155
1156 .orchard-list-item:hover {
1157 background: #e9ecef;
1158 }
1159
1160 .orchard-list-item-content {
1161 flex: 1;
1162 }
1163
1164 .orchard-list-item-title {
1165 font-weight: 500;
1166 color: #333;
1167 font-size: 14px;
1168 margin-bottom: 4px;
1169 }
1170
1171 .orchard-list-item-meta {
1172 font-size: 12px;
1173 color: #999;
1174 }
1175
1176 .orchard-list-item-actions {
1177 display: flex;
1178 gap: 8px;
1179 }
1180
1181 .orchard-icon-btn {
1182 background: none;
1183 border: none;
1184 color: #666;
1185 cursor: pointer;
1186 padding: 6px;
1187 border-radius: 4px;
1188 transition: all 0.2s;
1189 }
1190
1191 .orchard-icon-btn:hover {
1192 background: rgba(102, 126, 234, 0.1);
1193 color: #667eea;
1194 }
1195
1196 /* Buttons */
1197 .orchard-btn {
1198 padding: 10px 16px;
1199 background: #667eea;
1200 color: white;
1201 border: none;
1202 border-radius: 6px;
1203 cursor: pointer;
1204 font-size: 14px;
1205 transition: background 0.2s;
1206 display: flex;
1207 align-items: center;
1208 gap: 8px;
1209 }
1210
1211 .orchard-btn:hover {
1212 background: #5568d3;
1213 }
1214
1215 .orchard-btn-sm {
1216 padding: 8px 12px;
1217 font-size: 13px;
1218 }
1219
1220 /* Headers */
1221 .orchard-bookmarks-header,
1222 .orchard-recent-header,
1223 .orchard-notes-header {
1224 margin-bottom: 15px;
1225 }
1226
1227 /* Notes */
1228 .orchard-notes-header textarea {
1229 width: 100%;
1230 padding: 10px;
1231 border: 1px solid #e0e0e0;
1232 border-radius: 6px;
1233 font-size: 14px;
1234 margin-bottom: 10px;
1235 resize: vertical;
1236 font-family: inherit;
1237 }
1238
1239 .orchard-notes-header textarea:focus {
1240 outline: none;
1241 border-color: #667eea;
1242 }
1243
1244 .orchard-note-item {
1245 flex-direction: column;
1246 align-items: flex-start;
1247 }
1248
1249 .orchard-note-content {
1250 color: #333;
1251 font-size: 14px;
1252 line-height: 1.5;
1253 margin-bottom: 8px;
1254 white-space: pre-wrap;
1255 }
1256
1257 /* Tools Grid */
1258 .orchard-tools-grid {
1259 display: grid;
1260 grid-template-columns: repeat(2, 1fr);
1261 gap: 12px;
1262 }
1263
1264 .orchard-tool-btn {
1265 padding: 20px;
1266 background: #f8f9fa;
1267 border: 1px solid #e0e0e0;
1268 border-radius: 8px;
1269 cursor: pointer;
1270 transition: all 0.2s;
1271 display: flex;
1272 flex-direction: column;
1273 align-items: center;
1274 gap: 10px;
1275 text-align: center;
1276 }
1277
1278 .orchard-tool-btn:hover {
1279 background: #667eea;
1280 color: white;
1281 border-color: #667eea;
1282 transform: translateY(-2px);
1283 box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
1284 }
1285
1286 .orchard-tool-btn i {
1287 font-size: 24px;
1288 }
1289
1290 .orchard-tool-btn span {
1291 font-size: 13px;
1292 font-weight: 500;
1293 }
1294
1295 /* Empty State */
1296 .orchard-empty-state {
1297 text-align: center;
1298 padding: 40px 20px;
1299 color: #999;
1300 font-size: 14px;
1301 }
1302
1303 /* Notifications */
1304 .orchard-notification {
1305 position: fixed;
1306 top: 20px;
1307 right: 20px;
1308 background: white;
1309 padding: 16px 20px;
1310 border-radius: 8px;
1311 box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
1312 z-index: 10000;
1313 transform: translateX(400px);
1314 transition: transform 0.3s ease;
1315 }
1316
1317 .orchard-notification.show {
1318 transform: translateX(0);
1319 }
1320
1321 .orchard-notification-content {
1322 display: flex;
1323 align-items: center;
1324 gap: 12px;
1325 }
1326
1327 .orchard-notification-content i {
1328 font-size: 20px;
1329 }
1330
1331 .orchard-notification-success {
1332 border-left: 4px solid #28a745;
1333 }
1334
1335 .orchard-notification-success i {
1336 color: #28a745;
1337 }
1338
1339 .orchard-notification-error {
1340 border-left: 4px solid #dc3545;
1341 }
1342
1343 .orchard-notification-error i {
1344 color: #dc3545;
1345 }
1346
1347 .orchard-notification-info {
1348 border-left: 4px solid #17a2b8;
1349 }
1350
1351 .orchard-notification-info i {
1352 color: #17a2b8;
1353 }
1354
1355 /* Modal */
1356 .orchard-modal-overlay {
1357 position: fixed;
1358 top: 0;
1359 left: 0;
1360 right: 0;
1361 bottom: 0;
1362 background: rgba(0, 0, 0, 0.5);
1363 display: flex;
1364 align-items: center;
1365 justify-content: center;
1366 z-index: 10001;
1367 }
1368
1369 .orchard-shortcuts-modal {
1370 background: white;
1371 padding: 30px;
1372 border-radius: 12px;
1373 max-width: 500px;
1374 width: 90%;
1375 }
1376
1377 .orchard-shortcuts-modal h3 {
1378 margin: 0 0 20px 0;
1379 color: #333;
1380 }
1381
1382 .orchard-shortcuts-list {
1383 display: flex;
1384 flex-direction: column;
1385 gap: 15px;
1386 margin-bottom: 20px;
1387 }
1388
1389 .orchard-shortcut-item {
1390 display: flex;
1391 justify-content: space-between;
1392 align-items: center;
1393 padding: 12px;
1394 background: #f8f9fa;
1395 border-radius: 6px;
1396 }
1397
1398 .orchard-shortcut-item kbd {
1399 background: #333;
1400 color: white;
1401 padding: 4px 8px;
1402 border-radius: 4px;
1403 font-size: 12px;
1404 font-family: monospace;
1405 margin: 0 2px;
1406 }
1407
1408 .orchard-shortcut-item span {
1409 color: #666;
1410 font-size: 14px;
1411 }
1412
1413 /* Scrollbar */
1414 .orchard-panel-content::-webkit-scrollbar {
1415 width: 6px;
1416 }
1417
1418 .orchard-panel-content::-webkit-scrollbar-track {
1419 background: #f1f1f1;
1420 }
1421
1422 .orchard-panel-content::-webkit-scrollbar-thumb {
1423 background: #888;
1424 border-radius: 3px;
1425 }
1426
1427 .orchard-panel-content::-webkit-scrollbar-thumb:hover {
1428 background: #555;
1429 }
1430
1431 /* Responsive */
1432 @media (max-width: 768px) {
1433 .orchard-panel {
1434 width: 100%;
1435 right: -100%;
1436 }
1437
1438 .orchard-tools-grid {
1439 grid-template-columns: 1fr;
1440 }
1441 }
1442 `;
1443
1444 const styleElement = document.createElement('style');
1445 styleElement.textContent = styles;
1446 document.head.appendChild(styleElement);
1447 }
1448
1449 // ============================================
1450 // INITIALIZATION
1451 // ============================================
1452 async function init() {
1453 console.log('🎯 Initializing Orchard Management Pro...');
1454
1455 // Wait for DOM to be ready
1456 if (document.readyState === 'loading') {
1457 document.addEventListener('DOMContentLoaded', init);
1458 return;
1459 }
1460
1461 // Inject styles
1462 injectStyles();
1463
1464 // Track current page visit
1465 await RecentPagesManager.addRecentPage(Utils.getCurrentPageInfo());
1466
1467 // Initialize components
1468 const quickAccessPanel = new QuickAccessPanel();
1469 window.orchardQuickAccess = quickAccessPanel; // Make it globally accessible
1470
1471 const dashboardEnhancer = new DashboardEnhancer();
1472 const keyboardShortcuts = new KeyboardShortcuts(quickAccessPanel);
1473
1474 console.log('✅ Orchard Management Pro initialized successfully!');
1475 console.log('💡 Press Alt+Q to open Quick Access Panel');
1476 }
1477
1478 // Start the extension
1479 init();
1480
1481})();