Files
roa2web-service-auto/src/shared/components/mobile/MobileTopBar.vue
Claude Agent 94d215d6ae feat(unified-mobile-desktop-ui): Complete US-501 - Header Actions Bar Unificat - Rapoarte
Implemented by Ralph autonomous loop.
Iteration: 1

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-12 22:16:53 +00:00

219 lines
5.1 KiB
Vue

<template>
<header class="mobile-top-bar" :class="{ 'selection-active': selectionActive }">
<!-- Left section -->
<div class="top-bar-left">
<Button
v-if="showBack"
icon="pi pi-arrow-left"
text
rounded
class="top-bar-btn"
@click="$emit('back-click')"
aria-label="Înapoi"
/>
<Button
v-else-if="showMenu"
icon="pi pi-bars"
text
rounded
class="top-bar-btn"
@click="$emit('menu-click')"
aria-label="Meniu"
/>
</div>
<!-- Title section -->
<h1 class="top-bar-title">{{ title }}</h1>
<!-- Right section - actions -->
<div class="top-bar-right">
<Button
v-for="(action, index) in actions"
:key="index"
:icon="action.icon"
text
rounded
class="top-bar-btn"
:class="{ 'active': action.active }"
@click="(e) => $emit('action-click', action, e)"
:aria-label="action.label || action.icon"
v-tooltip.bottom="action.tooltip"
/>
</div>
</header>
</template>
<script setup>
import Button from 'primevue/button'
/**
* MobileTopBar - Material Design 3 inspired top navigation bar for mobile views
*
* Props:
* - title: The text displayed in the center of the bar
* - showBack: Shows back arrow button on the left
* - showMenu: Shows hamburger menu button on the left (ignored if showBack is true)
* - actions: Array of action buttons for the right side
* - selectionActive: Whether selection mode is active (changes background)
*
* Events:
* - menu-click: Emitted when menu button is clicked
* - back-click: Emitted when back button is clicked
* - action-click: Emitted when any action button is clicked, passes action object
*/
defineProps({
/**
* Title displayed in the center of the top bar
*/
title: {
type: String,
default: ''
},
/**
* Whether to show the back arrow button
*/
showBack: {
type: Boolean,
default: false
},
/**
* Whether to show the hamburger menu button
* (ignored if showBack is true)
*/
showMenu: {
type: Boolean,
default: false
},
/**
* Array of action buttons for the right side
* Each action should have: { icon: string, label?: string, tooltip?: string, active?: boolean }
*/
actions: {
type: Array,
default: () => []
},
/**
* Whether selection mode is active (changes background color)
*/
selectionActive: {
type: Boolean,
default: false
}
})
defineEmits(['menu-click', 'back-click', 'action-click'])
</script>
<style scoped>
/* ================================================
MobileTopBar Component Styles
Material Design 3 inspired mobile navigation
================================================ */
.mobile-top-bar {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 56px;
background: var(--surface-card);
border-bottom: 1px solid var(--surface-border);
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 var(--space-xs);
z-index: 1000;
box-shadow: var(--shadow-sm);
}
/* Selection mode active state */
.mobile-top-bar.selection-active {
background: var(--blue-50);
border-bottom-color: var(--blue-200);
}
/* Left and right button containers */
.top-bar-left,
.top-bar-right {
display: flex;
align-items: center;
gap: var(--space-xs);
/* Ensure minimum width for consistent layout */
min-width: 48px;
}
/* Individual action buttons */
.top-bar-btn {
width: 48px;
height: 48px;
border-radius: var(--radius-full);
color: var(--text-color);
}
/* Active state for buttons (e.g., filter active) */
.top-bar-btn.active {
color: var(--color-primary);
background: var(--blue-50);
}
/* Title in the center */
.top-bar-title {
font-size: var(--text-lg);
font-weight: var(--font-semibold);
color: var(--text-color);
margin: 0;
flex: 1;
text-align: center;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* ================================================
Dark Mode Support
================================================ */
/* Manual dark mode via data-theme attribute */
[data-theme="dark"] .mobile-top-bar {
background: var(--surface-card);
border-bottom-color: var(--surface-border);
}
[data-theme="dark"] .mobile-top-bar.selection-active {
background: var(--blue-900);
border-bottom-color: var(--blue-700);
}
[data-theme="dark"] .top-bar-btn {
color: var(--text-color);
}
[data-theme="dark"] .top-bar-btn.active {
color: var(--blue-400);
background: var(--blue-900);
}
/* Auto dark mode (when no manual theme is set) */
@media (prefers-color-scheme: dark) {
:root:not([data-theme]) .mobile-top-bar {
background: var(--surface-card);
border-bottom-color: var(--surface-border);
}
:root:not([data-theme]) .mobile-top-bar.selection-active {
background: var(--blue-900);
border-bottom-color: var(--blue-700);
}
:root:not([data-theme]) .top-bar-btn {
color: var(--text-color);
}
:root:not([data-theme]) .top-bar-btn.active {
color: var(--blue-400);
background: var(--blue-900);
}
}
</style>