initial: bootstrap from BukidBountyApp base
This commit is contained in:
227
resources/js/Pages/Core/Fragments/TopHeader.vue
Normal file
227
resources/js/Pages/Core/Fragments/TopHeader.vue
Normal file
@@ -0,0 +1,227 @@
|
||||
<script setup>
|
||||
import { onMounted, onUnmounted, h, ref, watch, nextTick } from 'vue'
|
||||
import { useUIStore } from '../../../stores/ui'
|
||||
import { useUserStore } from '../../../stores/user'
|
||||
import { useUserNotes } from '../../../composables/useUserNotes'
|
||||
import { useModal } from '../../../composables/Core/useModal'
|
||||
|
||||
import SystemBroadcast from '../../../Components/SystemBroadcast.vue'
|
||||
|
||||
const uiStore = useUIStore()
|
||||
const userStore = useUserStore()
|
||||
const { notes, fetchNotes, dismissNotes, hasNotes } = useUserNotes()
|
||||
const modal = useModal()
|
||||
|
||||
const headerRef = ref(null)
|
||||
let resizeObserver = null
|
||||
|
||||
const updateHeaderHeight = () => {
|
||||
if (headerRef.value) {
|
||||
const height = headerRef.value.offsetHeight
|
||||
document.documentElement.style.setProperty('--header-height', `${height}px`)
|
||||
}
|
||||
}
|
||||
|
||||
const goBack = () => {
|
||||
window.history.back()
|
||||
}
|
||||
|
||||
const reloadPage = () => {
|
||||
window.location.reload()
|
||||
}
|
||||
|
||||
const openAccountSettings = () => {
|
||||
if (window.$navigateHelper) {
|
||||
window.$navigateHelper({ page: 'AccountSettings' })
|
||||
} else {
|
||||
console.warn('Global $navigate function not found.')
|
||||
}
|
||||
}
|
||||
|
||||
const openNotesModal = () => {
|
||||
if (!hasNotes()) return
|
||||
|
||||
modal.continueCancelModal({
|
||||
title: 'Notes',
|
||||
body: h('div', {
|
||||
style: 'white-space: pre-wrap; font-size: 16px; line-height: 1.5; color: #333;'
|
||||
}, notes.value),
|
||||
continueText: 'Dismiss Note',
|
||||
cancelText: 'Close',
|
||||
continueClass: 'btn btn-danger w-50 py-2 rounded-3 shadow-sm fw-bold',
|
||||
cancelClass: 'btn btn-light w-50 py-2 rounded-3 border fw-bold text-muted',
|
||||
onContinue: async () => {
|
||||
const success = await dismissNotes()
|
||||
if (success) {
|
||||
await fetchNotes()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (userStore.isLoggedIn) {
|
||||
fetchNotes()
|
||||
}
|
||||
updateHeaderHeight()
|
||||
|
||||
// Create a ResizeObserver to handle height changes (e.g., SystemBroadcast showing/hiding)
|
||||
if (window.ResizeObserver && headerRef.value) {
|
||||
resizeObserver = new ResizeObserver(() => {
|
||||
updateHeaderHeight()
|
||||
})
|
||||
resizeObserver.observe(headerRef.value)
|
||||
}
|
||||
|
||||
// Fallback: update on window resize
|
||||
window.addEventListener('resize', updateHeaderHeight)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
if (resizeObserver) {
|
||||
resizeObserver.disconnect()
|
||||
}
|
||||
window.removeEventListener('resize', updateHeaderHeight)
|
||||
})
|
||||
|
||||
// Update height when notes status changes
|
||||
watch(() => hasNotes(), () => {
|
||||
nextTick(() => updateHeaderHeight())
|
||||
})
|
||||
|
||||
// Update height when page title changes (might wrap)
|
||||
watch(() => uiStore.pageTitle, () => {
|
||||
nextTick(() => updateHeaderHeight())
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="header is-fixed" id="maintopbarheader" ref="headerRef">
|
||||
<SystemBroadcast />
|
||||
<div class="tf-container">
|
||||
<div class="tf-statusbar d-flex justify-content-center align-items-center">
|
||||
<a href="javascript:void(0);" class="back-btn" @click="goBack" id="backbutton-top">
|
||||
<i class="fas fa-chevron-left"></i>
|
||||
</a>
|
||||
<h3 id="topbar-title" @click="reloadPage" class="header-title">{{ uiStore.pageTitle }}</h3>
|
||||
<div class="action-right-group">
|
||||
<a
|
||||
v-if="hasNotes()"
|
||||
href="javascript:void(0);"
|
||||
class="action-right-btn notes-btn"
|
||||
@click="openNotesModal"
|
||||
id="btn-notes-top"
|
||||
title="You have notes"
|
||||
>
|
||||
<i class="fas fa-copy"></i>
|
||||
<span class="notes-badge"></span>
|
||||
</a>
|
||||
<a href="javascript:void(0);" class="action-right-btn" @click="openAccountSettings" id="btn-popup-up">
|
||||
<i class="fas fa-sliders-h"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<style scoped>
|
||||
.header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 100%;
|
||||
max-width: var(--layout-max-width, 1440px);
|
||||
z-index: 9999;
|
||||
background-color: rgba(255, 255, 255, 0.85);
|
||||
backdrop-filter: blur(15px);
|
||||
-webkit-backdrop-filter: blur(15px);
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.08);
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
:global(body.is-full-width) .header {
|
||||
max-width: none !important;
|
||||
}
|
||||
|
||||
:global(.dark-mode) .header {
|
||||
background-color: var(--header-bg);
|
||||
border-bottom-color: var(--border-color);
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.header-title {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: #1e1e1e;
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
:global(.dark-mode) .header-title {
|
||||
color: #e0e0e0;
|
||||
}
|
||||
|
||||
.tf-statusbar {
|
||||
height: 56px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.back-btn {
|
||||
position: absolute;
|
||||
left: 16px;
|
||||
color: #1e1e1e;
|
||||
font-size: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.action-right-group {
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.action-right-btn {
|
||||
color: #1e1e1e;
|
||||
font-size: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.notes-btn {
|
||||
color: #f2c71c;
|
||||
}
|
||||
|
||||
.notes-badge {
|
||||
position: absolute;
|
||||
top: -2px;
|
||||
right: -4px;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background-color: #ea3434;
|
||||
border-radius: 50%;
|
||||
border: 1.5px solid #fff;
|
||||
}
|
||||
|
||||
:global(.dark-mode) .back-btn,
|
||||
:global(.dark-mode) .action-right-btn {
|
||||
color: #e0e0e0;
|
||||
}
|
||||
|
||||
:global(.dark-mode) .notes-btn {
|
||||
color: #f2c71c;
|
||||
}
|
||||
|
||||
:global(.dark-mode) .notes-badge {
|
||||
border-color: rgba(28, 30, 34, 0.85);
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user