feat(ui): Add DevTools button for mobile debugging
Add Eruda DevTools integration accessible from hamburger menu on mobile devices. - Add DevTools menu item with mobileOnly flag - Load Eruda dynamically from CDN when clicked - Filter menu items based on device type 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -21,7 +21,8 @@ export const menuSections = [
|
|||||||
{ to: '/reports/telegram', icon: 'pi pi-telegram', label: 'Telegram Bot' },
|
{ to: '/reports/telegram', icon: 'pi pi-telegram', label: 'Telegram Bot' },
|
||||||
{ to: '/reports/cache-stats', icon: 'pi pi-chart-bar', label: 'Statistici Cache' },
|
{ to: '/reports/cache-stats', icon: 'pi pi-chart-bar', label: 'Statistici Cache' },
|
||||||
{ to: '/data-entry/ocr-metrics', icon: 'pi pi-eye', label: 'Statistici OCR' },
|
{ to: '/data-entry/ocr-metrics', icon: 'pi pi-eye', label: 'Statistici OCR' },
|
||||||
{ to: '/reports/server-logs', icon: 'pi pi-server', label: 'Server Logs' }
|
{ to: '/reports/server-logs', icon: 'pi pi-server', label: 'Server Logs' },
|
||||||
|
{ action: 'devtools', icon: 'pi pi-cog', label: 'DevTools', mobileOnly: true }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -18,11 +18,13 @@
|
|||||||
<h3 class="menu-title">{{ section.title }}</h3>
|
<h3 class="menu-title">{{ section.title }}</h3>
|
||||||
<ul class="menu-list">
|
<ul class="menu-list">
|
||||||
<li
|
<li
|
||||||
v-for="item in section.items"
|
v-for="item in getFilteredItems(section.items)"
|
||||||
:key="item.to"
|
:key="item.to || item.action"
|
||||||
class="menu-item"
|
class="menu-item"
|
||||||
>
|
>
|
||||||
|
<!-- Router link for navigation -->
|
||||||
<router-link
|
<router-link
|
||||||
|
v-if="item.to"
|
||||||
:to="item.to"
|
:to="item.to"
|
||||||
class="menu-link"
|
class="menu-link"
|
||||||
:class="{ active: isRouteActive(item.to) }"
|
:class="{ active: isRouteActive(item.to) }"
|
||||||
@@ -32,6 +34,16 @@
|
|||||||
<span>{{ item.label }}</span>
|
<span>{{ item.label }}</span>
|
||||||
<span v-if="item.badge" class="menu-badge">{{ item.badge }}</span>
|
<span v-if="item.badge" class="menu-badge">{{ item.badge }}</span>
|
||||||
</router-link>
|
</router-link>
|
||||||
|
<!-- Action link for DevTools etc -->
|
||||||
|
<a
|
||||||
|
v-else-if="item.action"
|
||||||
|
href="#"
|
||||||
|
class="menu-link"
|
||||||
|
@click.prevent="handleAction(item.action)"
|
||||||
|
>
|
||||||
|
<i :class="['menu-icon', item.icon]"></i>
|
||||||
|
<span>{{ item.label }}</span>
|
||||||
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@@ -58,6 +70,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { useRoute } from "vue-router";
|
import { useRoute } from "vue-router";
|
||||||
|
import { ref, onMounted } from "vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "SlideMenu",
|
name: "SlideMenu",
|
||||||
@@ -68,7 +81,7 @@ export default {
|
|||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
// Menu items configuration
|
// Menu items configuration
|
||||||
// Format: [{ title: 'Section', items: [{ to: '/path', icon: 'pi pi-icon', label: 'Label', badge: null }] }]
|
// Format: [{ title: 'Section', items: [{ to: '/path', icon: 'pi pi-icon', label: 'Label', badge: null, action: null, mobileOnly: false }] }]
|
||||||
menuItems: {
|
menuItems: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => [],
|
default: () => [],
|
||||||
@@ -83,6 +96,19 @@ export default {
|
|||||||
setup(props, { emit }) {
|
setup(props, { emit }) {
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
|
||||||
|
// Mobile detection
|
||||||
|
const isMobile = ref(false);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
isMobile.value = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Filter items based on mobileOnly flag
|
||||||
|
const getFilteredItems = (items) => {
|
||||||
|
if (!items) return [];
|
||||||
|
return items.filter(item => !item.mobileOnly || isMobile.value);
|
||||||
|
};
|
||||||
|
|
||||||
const isRouteActive = (path) => {
|
const isRouteActive = (path) => {
|
||||||
return route.path === path;
|
return route.path === path;
|
||||||
};
|
};
|
||||||
@@ -92,9 +118,30 @@ export default {
|
|||||||
emit("close");
|
emit("close");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleAction = (action) => {
|
||||||
|
if (action === 'devtools') {
|
||||||
|
loadEruda();
|
||||||
|
}
|
||||||
|
emit('close');
|
||||||
|
};
|
||||||
|
|
||||||
|
const loadEruda = () => {
|
||||||
|
if (window.eruda) {
|
||||||
|
window.eruda.show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const script = document.createElement('script');
|
||||||
|
script.src = '//cdn.jsdelivr.net/npm/eruda';
|
||||||
|
document.body.appendChild(script);
|
||||||
|
script.onload = () => window.eruda.init();
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
isMobile,
|
||||||
|
getFilteredItems,
|
||||||
isRouteActive,
|
isRouteActive,
|
||||||
handleLogout,
|
handleLogout,
|
||||||
|
handleAction,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user