Re-create dynamic nature of the sidebar
This commit is contained in:
parent
48d44487da
commit
e5af41b703
1 changed files with 138 additions and 27 deletions
|
|
@ -1,11 +1,12 @@
|
|||
<template>
|
||||
<div id="sidebar" x-data="$store.user">
|
||||
<div id="sidebar" :class="{ collapsed: isCollapsed }">
|
||||
<div class="sidebar-header">
|
||||
<div class="logo-container">
|
||||
<img class="logo" src="/static/img/nidus-logo-256-transparent.png" />
|
||||
</div>
|
||||
</div>
|
||||
<button id="sidebarToggle" class="btn btn-sm p-0">
|
||||
|
||||
<button id="sidebarToggle" class="btn btn-sm p-0" @click="toggleSidebar">
|
||||
<i id="sidebarToggleIcon" class="bi bi-chevron-left"></i>
|
||||
</button>
|
||||
|
||||
|
|
@ -42,13 +43,14 @@
|
|||
<div class="menu-icon"><i class="bi bi-messaging"></i></div>
|
||||
<span class="menu-text ms-2">Communication</span>
|
||||
<span
|
||||
x-show="notification_counts.communication > 0"
|
||||
x-cloak
|
||||
v-show="notificationCounts.communication > 0"
|
||||
class="position-absolute translate-middle badge rounded-pill bg-primary"
|
||||
>
|
||||
<span
|
||||
x-text="notification_counts.communication > 99 ? '99+' : notification_counts.communication"
|
||||
></span>
|
||||
<span>{{
|
||||
notificationCounts.communication > 99
|
||||
? "99+"
|
||||
: notificationCounts.communication
|
||||
}}</span>
|
||||
<span class="visually-hidden">unread notifications</span>
|
||||
</span>
|
||||
</a>
|
||||
|
|
@ -85,13 +87,12 @@
|
|||
<div class="menu-icon"><i class="bi bi-review"></i></div>
|
||||
<span class="menu-text ms-2">Review</span>
|
||||
<span
|
||||
x-show="notification_counts.review > 0"
|
||||
x-cloak
|
||||
v-show="notificationCounts.review > 0"
|
||||
class="position-absolute translate-middle badge rounded-pill bg-primary"
|
||||
>
|
||||
<span
|
||||
x-text="notification_counts.review > 99 ? '99+' : notification_counts.review"
|
||||
></span>
|
||||
<span>{{
|
||||
notificationCounts.review > 99 ? "99+" : notificationCounts.review
|
||||
}}</span>
|
||||
<span class="visually-hidden">unread notifications</span>
|
||||
</span>
|
||||
</a>
|
||||
|
|
@ -122,22 +123,132 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import NavigationLink from "../common/NavigationLink.vue";
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted, onBeforeUnmount, nextTick } from "vue";
|
||||
import { Tooltip, Popover } from "bootstrap";
|
||||
|
||||
// Reactive state
|
||||
const isCollapsed = ref(false);
|
||||
const notificationCounts = reactive({
|
||||
communication: 0,
|
||||
review: 0,
|
||||
});
|
||||
|
||||
const userData = reactive({});
|
||||
|
||||
// Bootstrap tooltip instances
|
||||
let tooltipInstances = [];
|
||||
let sseUnsubscribe = null;
|
||||
|
||||
// Initialize Bootstrap components
|
||||
const initializeBootstrap = () => {
|
||||
// Initialize popovers
|
||||
const popoverElements = document.querySelectorAll(
|
||||
'[data-bs-toggle="popover"]',
|
||||
);
|
||||
popoverElements.forEach((el) => new Popover(el));
|
||||
console.log("Initialized", popoverElements.length, "popovers");
|
||||
|
||||
// Initialize tooltips
|
||||
const tooltipElements = document.querySelectorAll(
|
||||
'[data-bs-toggle="tooltip"]',
|
||||
);
|
||||
tooltipInstances = Array.from(tooltipElements).map((el) => new Tooltip(el));
|
||||
console.log("Initialized", tooltipElements.length, "tooltips");
|
||||
};
|
||||
|
||||
// Restore sidebar state from localStorage
|
||||
const restoreLocalStorage = () => {
|
||||
const expanded = localStorage.getItem("sidebar.expanded");
|
||||
if (expanded === "false") {
|
||||
isCollapsed.value = true;
|
||||
document.getElementById("content")?.classList.add("expanded");
|
||||
} else {
|
||||
isCollapsed.value = false;
|
||||
document.getElementById("content")?.classList.remove("expanded");
|
||||
localStorage.setItem("sidebar.expanded", "true");
|
||||
}
|
||||
};
|
||||
|
||||
// Toggle sidebar collapsed state
|
||||
const toggleSidebar = () => {
|
||||
isCollapsed.value = !isCollapsed.value;
|
||||
document.getElementById("content")?.classList.toggle("expanded");
|
||||
setTooltipsForSidebar();
|
||||
localStorage.setItem("sidebar.expanded", (!isCollapsed.value).toString());
|
||||
};
|
||||
|
||||
// Enable/disable tooltips based on sidebar state
|
||||
const setTooltipsForSidebar = () => {
|
||||
const sidebarTooltips = document.querySelectorAll(
|
||||
'#sidebar [data-bs-toggle="tooltip"]',
|
||||
);
|
||||
const isExpanded = document
|
||||
.getElementById("content")
|
||||
?.classList.contains("expanded");
|
||||
|
||||
sidebarTooltips.forEach((el) => {
|
||||
const tooltip = Tooltip.getOrCreateInstance(el);
|
||||
if (isExpanded) {
|
||||
tooltip.enable();
|
||||
} else {
|
||||
tooltip.disable();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Fetch user state from API
|
||||
const updateUserState = async () => {
|
||||
try {
|
||||
const response = await fetch("/api/user/self");
|
||||
const data = await response.json();
|
||||
|
||||
// Update reactive data
|
||||
Object.keys(data).forEach((key) => {
|
||||
if (key === "notification_counts") {
|
||||
Object.assign(notificationCounts, data[key]);
|
||||
} else {
|
||||
userData[key] = data[key];
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Failed to update user state:", error);
|
||||
}
|
||||
};
|
||||
|
||||
// Lifecycle hooks
|
||||
onMounted(async () => {
|
||||
restoreLocalStorage();
|
||||
|
||||
await nextTick();
|
||||
|
||||
initializeBootstrap();
|
||||
setTooltipsForSidebar();
|
||||
|
||||
// Subscribe to SSE events (assuming SSEManager is globally available)
|
||||
if (window.SSEManager) {
|
||||
sseUnsubscribe = window.SSEManager.subscribe("*", (e) => {
|
||||
if (e.type !== "heartbeat") {
|
||||
updateUserState();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Initial user state fetch
|
||||
updateUserState();
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
// Cleanup Bootstrap tooltips
|
||||
tooltipInstances.forEach((tooltip) => tooltip.dispose());
|
||||
|
||||
// Unsubscribe from SSE
|
||||
if (sseUnsubscribe) {
|
||||
sseUnsubscribe();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.sidebar {
|
||||
width: 250px;
|
||||
background-color: #2c3e50;
|
||||
color: white;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
nav {
|
||||
margin-top: 30px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
/* Add any component-specific styles here */
|
||||
</style>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue