Files
hackerspace-governance-in-a…/governance-site/src/components/layout/AppHeader.vue
Moheeb Zara 9c89e1883c yolo
2025-12-05 23:51:51 -07:00

181 lines
3.7 KiB
Vue

<template>
<header class="app-header">
<div class="container">
<div class="header-content">
<button
class="menu-toggle lg:d-none"
@click="navigationStore.toggleMenu()"
:aria-label="navigationStore.isMenuOpen ? 'Close menu' : 'Open menu'"
aria-controls="navigation-menu"
>
<Menu v-if="!navigationStore.isMenuOpen" :size="24" />
<X v-else :size="24" />
</button>
<router-link to="/" class="logo-link">
<h1 class="logo">{{ hackerspaceStore.hackerspace.name }}</h1>
</router-link>
<nav class="header-nav d-none lg:d-flex">
<router-link
v-for="item in mainNavItems"
:key="item.id"
:to="item.path"
class="nav-link"
:class="{ active: $route.path === item.path }"
>
{{ item.title }}
</router-link>
</nav>
<div class="header-actions">
<button
class="icon-button"
@click="toggleTheme"
aria-label="Toggle theme"
>
<Sun v-if="isDark" :size="20" />
<Moon v-else :size="20" />
</button>
<button
class="icon-button"
@click="printPage"
aria-label="Print page"
>
<Printer :size="20" />
</button>
</div>
</div>
</div>
</header>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue'
import { useRoute } from 'vue-router'
import { useNavigationStore } from '@/stores/navigation'
import { useHackerspaceStore } from '@/stores/hackerspace'
import { Menu, X, Sun, Moon, Printer } from 'lucide-vue-next'
const route = useRoute()
const navigationStore = useNavigationStore()
const hackerspaceStore = useHackerspaceStore()
const isDark = ref(false)
const mainNavItems = computed(() =>
navigationStore.navItems.slice(0, 5)
)
const toggleTheme = () => {
isDark.value = !isDark.value
document.documentElement.classList.toggle('dark-theme')
}
const printPage = () => {
window.print()
}
</script>
<style lang="scss" scoped>
.app-header {
position: sticky;
top: 0;
z-index: 100;
background-color: $color-paper;
border-bottom: 1px solid $color-border;
height: $header-height;
}
.header-content {
display: flex;
align-items: center;
justify-content: space-between;
height: $header-height;
gap: $space-4;
}
.menu-toggle {
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
border-radius: $radius-md;
transition: background-color $transition-fast;
&:hover {
background-color: $color-paper-light;
}
}
.logo-link {
text-decoration: none;
color: inherit;
&:hover {
text-decoration: none;
}
}
.logo {
font-size: $font-size-lg;
font-weight: 700;
margin: 0;
color: $color-text;
}
.header-nav {
display: flex;
align-items: center;
gap: $space-2;
flex-grow: 1;
justify-content: center;
}
.nav-link {
padding: $space-2 $space-3;
border-radius: $radius-md;
font-size: $font-size-sm;
font-weight: 500;
transition: all $transition-fast;
&:hover {
background-color: $color-paper-light;
text-decoration: none;
}
&.active {
background-color: $color-paper-light;
color: $color-accent;
}
}
.header-actions {
display: flex;
align-items: center;
gap: $space-2;
}
.icon-button {
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
border-radius: $radius-md;
transition: background-color $transition-fast;
color: $color-text-muted;
&:hover {
background-color: $color-paper-light;
color: $color-text;
}
}
@media (max-width: $breakpoint-lg) {
.header-nav {
display: none;
}
}
</style>