feat(mobile-navigation-improvements): Complete US-214 - Actualizare Documentație MOBILE_PATTERNS.md
Implemented by Ralph autonomous loop. Iteration: 14 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
# ROA2WEB Mobile Patterns Library
|
# ROA2WEB Mobile Patterns Library
|
||||||
|
|
||||||
**Version:** 1.0.0
|
**Version:** 2.0.0
|
||||||
**Last Updated:** 2026-01-12
|
**Last Updated:** 2026-01-12
|
||||||
**Status:** ✅ Complete
|
**Status:** ✅ Complete
|
||||||
|
|
||||||
@@ -10,14 +10,17 @@
|
|||||||
|
|
||||||
1. [Quick Start](#quick-start)
|
1. [Quick Start](#quick-start)
|
||||||
2. [Mobile Layout Overview](#mobile-layout-overview)
|
2. [Mobile Layout Overview](#mobile-layout-overview)
|
||||||
3. [MobileTopBar](#mobiletopbar)
|
3. [Navigation Architecture](#navigation-architecture)
|
||||||
4. [MobileBottomNav](#mobilebottomnav)
|
4. [MobileTopBar](#mobiletopbar)
|
||||||
5. [MobileSelectionFooter](#mobileselectionfooter)
|
5. [MobileBottomNav](#mobilebottomnav)
|
||||||
6. [BottomSheet](#bottomsheet)
|
6. [MobileDrawerMenu](#mobiledrawermenu) *(NEW)*
|
||||||
7. [SwipeableCards](#swipeablecards)
|
7. [MobileActionBar](#mobileactionbar) *(NEW)*
|
||||||
8. [Design Tokens for Mobile](#design-tokens-for-mobile)
|
8. [MobileSelectionFooter](#mobileselectionfooter)
|
||||||
9. [Best Practices](#best-practices)
|
9. [BottomSheet](#bottomsheet)
|
||||||
10. [Troubleshooting](#troubleshooting)
|
10. [SwipeableCards](#swipeablecards)
|
||||||
|
11. [Design Tokens for Mobile](#design-tokens-for-mobile)
|
||||||
|
12. [Best Practices](#best-practices)
|
||||||
|
13. [Troubleshooting](#troubleshooting)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -35,32 +38,43 @@ Get a mobile view running in **5 minutes**:
|
|||||||
title="My View"
|
title="My View"
|
||||||
:showMenu="true"
|
:showMenu="true"
|
||||||
:actions="topBarActions"
|
:actions="topBarActions"
|
||||||
@menu-click="toggleSidebar"
|
@menu-click="showDrawer = true"
|
||||||
@action-click="handleAction"
|
@action-click="handleAction"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- 2. Main Content (with padding for fixed bars) -->
|
<!-- 2. Drawer Menu (hamburger navigation) -->
|
||||||
|
<MobileDrawerMenu
|
||||||
|
v-model="showDrawer"
|
||||||
|
:user="currentUser"
|
||||||
|
@logout="handleLogout"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 3. Main Content (with padding for fixed bars) -->
|
||||||
<main class="mobile-content">
|
<main class="mobile-content">
|
||||||
<!-- Your content here -->
|
<!-- Your content here -->
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<!-- 3. Bottom Navigation -->
|
<!-- 4. Bottom Navigation -->
|
||||||
<MobileBottomNav :items="navItems" />
|
<MobileBottomNav />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
import MobileTopBar from '@shared/components/mobile/MobileTopBar.vue'
|
import MobileTopBar from '@shared/components/mobile/MobileTopBar.vue'
|
||||||
import MobileBottomNav from '@shared/components/mobile/MobileBottomNav.vue'
|
import MobileBottomNav from '@shared/components/mobile/MobileBottomNav.vue'
|
||||||
|
import MobileDrawerMenu from '@shared/components/mobile/MobileDrawerMenu.vue'
|
||||||
|
|
||||||
|
const showDrawer = ref(false)
|
||||||
|
const currentUser = { username: 'John Doe' }
|
||||||
|
|
||||||
const topBarActions = [
|
const topBarActions = [
|
||||||
{ icon: 'pi pi-filter', label: 'Filter', tooltip: 'Filtrează' }
|
{ icon: 'pi pi-filter', label: 'Filter', tooltip: 'Filtrează' }
|
||||||
]
|
]
|
||||||
|
|
||||||
const navItems = [
|
const handleLogout = () => {
|
||||||
{ to: '/data-entry', icon: 'pi pi-receipt', label: 'Bonuri' },
|
// Handle logout
|
||||||
{ to: '/reports', icon: 'pi pi-chart-bar', label: 'Rapoarte' }
|
}
|
||||||
]
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@@ -79,6 +93,8 @@ All mobile components are located in `src/shared/components/mobile/`:
|
|||||||
```javascript
|
```javascript
|
||||||
import MobileTopBar from '@shared/components/mobile/MobileTopBar.vue'
|
import MobileTopBar from '@shared/components/mobile/MobileTopBar.vue'
|
||||||
import MobileBottomNav from '@shared/components/mobile/MobileBottomNav.vue'
|
import MobileBottomNav from '@shared/components/mobile/MobileBottomNav.vue'
|
||||||
|
import MobileDrawerMenu from '@shared/components/mobile/MobileDrawerMenu.vue'
|
||||||
|
import MobileActionBar from '@shared/components/mobile/MobileActionBar.vue'
|
||||||
import MobileSelectionFooter from '@shared/components/mobile/MobileSelectionFooter.vue'
|
import MobileSelectionFooter from '@shared/components/mobile/MobileSelectionFooter.vue'
|
||||||
import BottomSheet from '@shared/components/mobile/BottomSheet.vue'
|
import BottomSheet from '@shared/components/mobile/BottomSheet.vue'
|
||||||
import SwipeableCards from '@shared/components/mobile/SwipeableCards.vue'
|
import SwipeableCards from '@shared/components/mobile/SwipeableCards.vue'
|
||||||
@@ -107,11 +123,32 @@ import SwipeableCards from '@shared/components/mobile/SwipeableCards.vue'
|
|||||||
│ │
|
│ │
|
||||||
├─────────────────────────────────────────┤
|
├─────────────────────────────────────────┤
|
||||||
│ MobileBottomNav (56px) │
|
│ MobileBottomNav (56px) │
|
||||||
│ 🏠 📋 📊 ⚙️ │
|
│ 📋 ☁️ 📊 ⚙️ │
|
||||||
│ Home Upload Reports Settings │
|
│ Bonuri Upload Rapoarte Setări │
|
||||||
└─────────────────────────────────────────┘
|
└─────────────────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### ASCII Diagram: Drawer Menu Open
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────────────────┬──────────────────────┐
|
||||||
|
│ MobileDrawer │ ░░░░░░░░░░░░░░░░░░░░ │
|
||||||
|
│ Menu (280px) │ ░░░░░░░░░░░░░░░░░░░░ │
|
||||||
|
├──────────────────┤ ░░░ OVERLAY ░░░░░░░░ │
|
||||||
|
│ 🏢 ROA2WEB │ ░░ (tap to close) ░░ │
|
||||||
|
├──────────────────┤ ░░░░░░░░░░░░░░░░░░░░ │
|
||||||
|
│ 🏠 Dashboard │ ░░░░░░░░░░░░░░░░░░░░ │
|
||||||
|
│ 📋 Bonuri │ ░░░░░░░░░░░░░░░░░░░░ │
|
||||||
|
│ 📄 Facturi │ ░░░░░░░░░░░░░░░░░░░░ │
|
||||||
|
│ 🔢 Balanță │ ░░░░░░░░░░░░░░░░░░░░ │
|
||||||
|
│ 💰 Trezorerie │ ░░░░░░░░░░░░░░░░░░░░ │
|
||||||
|
│ ⚙️ Setări │ ░░░░░░░░░░░░░░░░░░░░ │
|
||||||
|
├──────────────────┤ ░░░░░░░░░░░░░░░░░░░░ │
|
||||||
|
│ 👤 Username │ ░░░░░░░░░░░░░░░░░░░░ │
|
||||||
|
│ 🚪 Deconectare │ ░░░░░░░░░░░░░░░░░░░░ │
|
||||||
|
└──────────────────┴──────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
### ASCII Diagram: Selection Mode Layout
|
### ASCII Diagram: Selection Mode Layout
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -135,6 +172,32 @@ import SwipeableCards from '@shared/components/mobile/SwipeableCards.vue'
|
|||||||
└─────────────────────────────────────────┘
|
└─────────────────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### ASCII Diagram: Action Bar Layout (Edit/Create Views)
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────┐
|
||||||
|
│ MobileTopBar (56px) │
|
||||||
|
│ [←] Editare Bon [⋮] │
|
||||||
|
├─────────────────────────────────────────┤
|
||||||
|
│ │
|
||||||
|
│ Form Fields... │
|
||||||
|
│ │
|
||||||
|
│ ┌─────────────────────────────┐ │
|
||||||
|
│ │ Furnizor: LIDL │ │
|
||||||
|
│ │ Total: 125.50 RON │ │
|
||||||
|
│ │ Data: 2026-01-12 │ │
|
||||||
|
│ └─────────────────────────────┘ │
|
||||||
|
│ │
|
||||||
|
├─────────────────────────────────────────┤
|
||||||
|
│ MobileActionBar (context-aware) │
|
||||||
|
│ ┌──────────┐ ┌──────────────────┐ │
|
||||||
|
│ │ Salvează │ │ Trimite aprobare │ │
|
||||||
|
│ └──────────┘ └──────────────────┘ │
|
||||||
|
├─────────────────────────────────────────┤
|
||||||
|
│ MobileBottomNav (56px) │
|
||||||
|
└─────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
### ASCII Diagram: BottomSheet Open
|
### ASCII Diagram: BottomSheet Open
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -180,6 +243,120 @@ import SwipeableCards from '@shared/components/mobile/SwipeableCards.vue'
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Navigation Architecture
|
||||||
|
|
||||||
|
### Route Map
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────┐
|
||||||
|
│ / (root) │
|
||||||
|
│ Redirects to /reports/dashboard │
|
||||||
|
└───────────────┬─────────────────────┘
|
||||||
|
│
|
||||||
|
┌───────────────────────────┼───────────────────────────┐
|
||||||
|
│ │ │
|
||||||
|
▼ ▼ ▼
|
||||||
|
┌───────────────────┐ ┌───────────────────────┐ ┌─────────────────┐
|
||||||
|
│ /data-entry │ │ /reports │ │ /settings │
|
||||||
|
│ │ │ │ │ │
|
||||||
|
│ 📋 Bonuri List │ │ 📊 dashboard │ │ ⚙️ Settings Hub │
|
||||||
|
│ 📝 Bon Create │ │ 📄 invoices │ │ (centralized │
|
||||||
|
│ ✏️ Bon Edit │ │ 💰 bank-cash │ │ settings) │
|
||||||
|
│ 📊 OCR Metrics │ │ 🔢 trial-balance │ │ │
|
||||||
|
│ │ │ 📉 maturity-analysis │ │ Links to: │
|
||||||
|
│ │ │ 📋 detailed-invoices │ │ - OCR Settings │
|
||||||
|
│ │ │ 📈 cache-stats │ │ - Cache Stats │
|
||||||
|
│ │ │ 📝 server-logs │ │ - Server Logs │
|
||||||
|
│ │ │ 📱 telegram │ │ - Telegram │
|
||||||
|
└───────────────────┘ └───────────────────────┘ └─────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### Navigation Flow: Settings Hub Pattern
|
||||||
|
|
||||||
|
The Settings Hub (`/settings`) is the centralized entry point for all administrative pages:
|
||||||
|
|
||||||
|
```
|
||||||
|
MobileBottomNav "Setări" button
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌───────────────────────────────────┐
|
||||||
|
│ Settings Hub │
|
||||||
|
│ /settings │
|
||||||
|
│ │
|
||||||
|
│ ┌─────────┐ ┌─────────┐ │
|
||||||
|
│ │ OCR │ │ Cache │ │
|
||||||
|
│ │ Setări │ │ Stats │ │
|
||||||
|
│ └────┬────┘ └────┬────┘ │
|
||||||
|
│ │ │ │
|
||||||
|
│ ┌────┴────┐ ┌────┴────┐ │
|
||||||
|
│ │ Server │ │Telegram │ │
|
||||||
|
│ │ Logs │ │ Bot │ │
|
||||||
|
│ └─────────┘ └─────────┘ │
|
||||||
|
└───────────────────────────────────┘
|
||||||
|
│
|
||||||
|
▼ (click on card)
|
||||||
|
┌───────────────────────────────────┐
|
||||||
|
│ /data-entry/ocr-metrics │
|
||||||
|
│ /reports/cache-stats │
|
||||||
|
│ /reports/server-logs │
|
||||||
|
│ /reports/telegram │
|
||||||
|
└───────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### MobileBottomNav Default Items (Updated)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Default navigation items
|
||||||
|
[
|
||||||
|
{ to: '/data-entry', icon: 'pi pi-receipt', label: 'Bonuri' },
|
||||||
|
{ icon: 'pi pi-cloud-upload', label: 'Upload' }, // Action button
|
||||||
|
{ to: '/reports/dashboard', icon: 'pi pi-chart-bar', label: 'Rapoarte' },
|
||||||
|
{ to: '/settings', icon: 'pi pi-cog', label: 'Setări' } // → Settings Hub
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### MobileDrawerMenu Navigation Links
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Drawer menu navigation items
|
||||||
|
[
|
||||||
|
{ to: '/reports/dashboard', icon: 'pi pi-home', label: 'Dashboard' },
|
||||||
|
{ to: '/data-entry', icon: 'pi pi-receipt', label: 'Bonuri' },
|
||||||
|
{ to: '/reports/invoices', icon: 'pi pi-file', label: 'Facturi' },
|
||||||
|
{ to: '/reports/trial-balance', icon: 'pi pi-calculator', label: 'Balanță' },
|
||||||
|
{ to: '/reports/bank-cash', icon: 'pi pi-money-bill', label: 'Trezorerie' },
|
||||||
|
{ to: '/settings', icon: 'pi pi-cog', label: 'Setări' }
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Dashboard Mobile Quick Links
|
||||||
|
|
||||||
|
On mobile, Dashboard shows KPI cards plus quick-link cards:
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────┐
|
||||||
|
│ MobileTopBar: Dashboard │
|
||||||
|
├─────────────────────────────────────────┤
|
||||||
|
│ │
|
||||||
|
│ ┌─────────────────────────────────┐ │
|
||||||
|
│ │ SwipeableCards (KPIs) │ │
|
||||||
|
│ │ ← Swipe → │ │
|
||||||
|
│ └─────────────────────────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ ┌─────────────┐ ┌─────────────┐ │
|
||||||
|
│ │ 📉 Analiză │ │ 📋 Facturi │ │
|
||||||
|
│ │ Scadențe → │ │ Detaliate → │ │
|
||||||
|
│ └─────────────┘ └─────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ (Quick links to dedicated pages) │
|
||||||
|
│ │
|
||||||
|
├─────────────────────────────────────────┤
|
||||||
|
│ MobileBottomNav │
|
||||||
|
└─────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## MobileTopBar
|
## MobileTopBar
|
||||||
|
|
||||||
Material Design 3 inspired top navigation bar for mobile views.
|
Material Design 3 inspired top navigation bar for mobile views.
|
||||||
@@ -310,7 +487,7 @@ interface NavItem {
|
|||||||
{ to: '/data-entry', icon: 'pi pi-receipt', label: 'Bonuri' },
|
{ to: '/data-entry', icon: 'pi pi-receipt', label: 'Bonuri' },
|
||||||
{ icon: 'pi pi-cloud-upload', label: 'Upload' }, // Action button
|
{ icon: 'pi pi-cloud-upload', label: 'Upload' }, // Action button
|
||||||
{ to: '/reports/dashboard', icon: 'pi pi-chart-bar', label: 'Rapoarte' },
|
{ to: '/reports/dashboard', icon: 'pi pi-chart-bar', label: 'Rapoarte' },
|
||||||
{ to: '/data-entry/ocr-metrics', icon: 'pi pi-cog', label: 'Setări' }
|
{ to: '/settings', icon: 'pi pi-cog', label: 'Setări' } // → Settings Hub
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -359,6 +536,282 @@ const handleNavClick = (item) => {
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## MobileDrawerMenu
|
||||||
|
|
||||||
|
Material Design 3 inspired navigation drawer that slides in from the left. Replaces the desktop sidebar on mobile devices.
|
||||||
|
|
||||||
|
### Props
|
||||||
|
|
||||||
|
| Prop | Type | Default | Description |
|
||||||
|
|------|------|---------|-------------|
|
||||||
|
| `modelValue` | Boolean | `false` | Controls visibility (v-model support) |
|
||||||
|
| `user` | Object | `null` | User object for profile display `{ username: string }` |
|
||||||
|
| `onLogout` | Function | `null` | Optional logout callback; emits `logout` event if not provided |
|
||||||
|
|
||||||
|
### Events
|
||||||
|
|
||||||
|
| Event | Payload | Description |
|
||||||
|
|-------|---------|-------------|
|
||||||
|
| `update:modelValue` | `boolean` | v-model update when visibility changes |
|
||||||
|
| `logout` | - | Emitted when logout is clicked (if no `onLogout` prop) |
|
||||||
|
|
||||||
|
### Navigation Items (Built-in)
|
||||||
|
|
||||||
|
The drawer contains the following navigation links:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
[
|
||||||
|
{ to: '/reports/dashboard', icon: 'pi pi-home', label: 'Dashboard' },
|
||||||
|
{ to: '/data-entry', icon: 'pi pi-receipt', label: 'Bonuri' },
|
||||||
|
{ to: '/reports/invoices', icon: 'pi pi-file', label: 'Facturi' },
|
||||||
|
{ to: '/reports/trial-balance', icon: 'pi pi-calculator', label: 'Balanță' },
|
||||||
|
{ to: '/reports/bank-cash', icon: 'pi pi-money-bill', label: 'Trezorerie' },
|
||||||
|
{ to: '/settings', icon: 'pi pi-cog', label: 'Setări' }
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Basic Usage
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<template>
|
||||||
|
<MobileTopBar
|
||||||
|
title="Dashboard"
|
||||||
|
:showMenu="true"
|
||||||
|
@menu-click="showDrawer = true"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<MobileDrawerMenu
|
||||||
|
v-model="showDrawer"
|
||||||
|
:user="authStore.user"
|
||||||
|
@logout="handleLogout"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import MobileDrawerMenu from '@shared/components/mobile/MobileDrawerMenu.vue'
|
||||||
|
import { useAuthStore } from '@/stores/auth'
|
||||||
|
|
||||||
|
const showDrawer = ref(false)
|
||||||
|
const authStore = useAuthStore()
|
||||||
|
|
||||||
|
const handleLogout = async () => {
|
||||||
|
await authStore.logout()
|
||||||
|
router.push('/login')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
### With Logout Callback
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<MobileDrawerMenu
|
||||||
|
v-model="showDrawer"
|
||||||
|
:user="{ username: 'John Doe' }"
|
||||||
|
:onLogout="async () => {
|
||||||
|
await api.logout()
|
||||||
|
router.push('/login')
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
| Feature | Description |
|
||||||
|
|---------|-------------|
|
||||||
|
| **Slide Animation** | Slides in from left with overlay fade |
|
||||||
|
| **Close on Tap Outside** | Tapping the overlay closes the drawer |
|
||||||
|
| **Close on Navigation** | Drawer closes automatically when a link is clicked |
|
||||||
|
| **Active State** | Current route is highlighted |
|
||||||
|
| **Profile Section** | Displays username and logout button at bottom |
|
||||||
|
| **Teleported** | Rendered to `<body>` to avoid z-index issues |
|
||||||
|
| **Dark Mode** | Full support for light/dark themes |
|
||||||
|
|
||||||
|
### CSS Classes
|
||||||
|
|
||||||
|
| Class | Description |
|
||||||
|
|-------|-------------|
|
||||||
|
| `.drawer-overlay` | Full-screen backdrop (50% black) |
|
||||||
|
| `.drawer-menu` | Main drawer container (280px, max 85vw) |
|
||||||
|
| `.drawer-header` | Header with logo |
|
||||||
|
| `.drawer-section` | Navigation links container |
|
||||||
|
| `.drawer-link` | Individual navigation link (48px min-height) |
|
||||||
|
| `.drawer-link.active` | Active route styling (blue background) |
|
||||||
|
| `.drawer-profile` | Profile section at bottom |
|
||||||
|
| `.logout-link` | Red logout button styling |
|
||||||
|
|
||||||
|
### Animation
|
||||||
|
|
||||||
|
Uses Vue `<Transition name="drawer">`:
|
||||||
|
- Overlay fades in/out
|
||||||
|
- Drawer slides from left (`translateX(-100%)` → `translateX(0)`)
|
||||||
|
- Duration: `var(--transition-normal)` (250ms)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## MobileActionBar
|
||||||
|
|
||||||
|
Context-aware bottom action bar for forms and edit views. Positions above MobileBottomNav and displays action buttons based on current state.
|
||||||
|
|
||||||
|
### Props
|
||||||
|
|
||||||
|
| Prop | Type | Default | Description |
|
||||||
|
|------|------|---------|-------------|
|
||||||
|
| `visible` | Boolean | `false` | Controls visibility (triggers slide-up animation) |
|
||||||
|
| `actions` | Array | `[]` | Array of action buttons to display |
|
||||||
|
|
||||||
|
### Action Object Structure
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface ActionBarAction {
|
||||||
|
label: string // Button text (e.g., 'Salvează')
|
||||||
|
icon: string // PrimeIcons class (e.g., 'pi pi-save')
|
||||||
|
severity?: string // PrimeVue severity ('primary', 'secondary', 'danger', etc.)
|
||||||
|
handler: () => void // Click handler function
|
||||||
|
disabled?: boolean // Disable the button
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Layout Behavior
|
||||||
|
|
||||||
|
| Actions Count | Layout |
|
||||||
|
|---------------|--------|
|
||||||
|
| 1 button | Full-width |
|
||||||
|
| 2 buttons | Side-by-side, equal width |
|
||||||
|
| 3+ buttons | Equal distribution |
|
||||||
|
|
||||||
|
### Basic Usage
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<template>
|
||||||
|
<MobileActionBar
|
||||||
|
:visible="isMobile"
|
||||||
|
:actions="formActions"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import MobileActionBar from '@shared/components/mobile/MobileActionBar.vue'
|
||||||
|
|
||||||
|
const formActions = [
|
||||||
|
{
|
||||||
|
label: 'Salvează',
|
||||||
|
icon: 'pi pi-save',
|
||||||
|
severity: 'primary',
|
||||||
|
handler: handleSave
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Anulează',
|
||||||
|
icon: 'pi pi-times',
|
||||||
|
severity: 'secondary',
|
||||||
|
handler: handleCancel
|
||||||
|
}
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Context-Aware Actions (Receipt Edit Example)
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<template>
|
||||||
|
<MobileActionBar
|
||||||
|
:visible="isMobile"
|
||||||
|
:actions="contextAwareActions"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed } from 'vue'
|
||||||
|
|
||||||
|
const receiptStatus = ref('draft') // 'draft' | 'pending' | 'approved' | 'rejected'
|
||||||
|
|
||||||
|
const contextAwareActions = computed(() => {
|
||||||
|
switch (receiptStatus.value) {
|
||||||
|
case 'draft':
|
||||||
|
return [
|
||||||
|
{ label: 'Salvează', icon: 'pi pi-save', severity: 'secondary', handler: handleSave },
|
||||||
|
{ label: 'Trimite', icon: 'pi pi-send', severity: 'primary', handler: handleSubmit }
|
||||||
|
]
|
||||||
|
case 'pending':
|
||||||
|
return [
|
||||||
|
{ label: 'Salvează', icon: 'pi pi-save', severity: 'secondary', handler: handleSave },
|
||||||
|
{ label: 'Aprobă', icon: 'pi pi-check', severity: 'success', handler: handleApprove },
|
||||||
|
{ label: 'Respinge', icon: 'pi pi-times', severity: 'danger', handler: handleReject }
|
||||||
|
]
|
||||||
|
case 'approved':
|
||||||
|
return [] // No actions for approved receipts
|
||||||
|
case 'rejected':
|
||||||
|
return [
|
||||||
|
{ label: 'Salvează', icon: 'pi pi-save', severity: 'secondary', handler: handleSave },
|
||||||
|
{ label: 'Re-trimite', icon: 'pi pi-refresh', severity: 'primary', handler: handleResubmit }
|
||||||
|
]
|
||||||
|
default:
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Hiding During Overlays
|
||||||
|
|
||||||
|
Hide the action bar when BottomSheet or other overlays are open:
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<template>
|
||||||
|
<MobileActionBar
|
||||||
|
:visible="isMobile && !isBottomSheetOpen"
|
||||||
|
:actions="formActions"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<BottomSheet v-model="isBottomSheetOpen">
|
||||||
|
<!-- Filter content -->
|
||||||
|
</BottomSheet>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
### CSS Classes
|
||||||
|
|
||||||
|
| Class | Description |
|
||||||
|
|-------|-------------|
|
||||||
|
| `.mobile-action-bar` | Base container (fixed, bottom: 56px) |
|
||||||
|
| `.action-bar-content` | Button container (max-width: 500px) |
|
||||||
|
| `.layout-single` | Single button layout (full-width) |
|
||||||
|
| `.layout-dual` | Two button layout (50% each) |
|
||||||
|
| `.layout-multi` | Three+ button layout (equal distribution) |
|
||||||
|
| `.action-bar-btn` | Individual button (48px min-height) |
|
||||||
|
|
||||||
|
### Animation
|
||||||
|
|
||||||
|
Uses Vue `<Transition name="slide-up">`:
|
||||||
|
- Slides up from below screen (`translateY(100%)` → `translateY(0)`)
|
||||||
|
- Duration: `var(--transition-normal)` (250ms)
|
||||||
|
- Fades in/out simultaneously
|
||||||
|
|
||||||
|
### Positioning
|
||||||
|
|
||||||
|
```css
|
||||||
|
.mobile-action-bar {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 56px; /* Above MobileBottomNav */
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
/* Safe area support for iPhone X+ */
|
||||||
|
bottom: calc(56px + env(safe-area-inset-bottom));
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Content Padding Adjustment
|
||||||
|
|
||||||
|
When MobileActionBar is visible, increase bottom padding:
|
||||||
|
|
||||||
|
```css
|
||||||
|
.mobile-content {
|
||||||
|
padding-bottom: 120px; /* 56px (nav) + 64px (action bar) */
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## MobileSelectionFooter
|
## MobileSelectionFooter
|
||||||
|
|
||||||
Slide-up action bar for batch operations on selected items.
|
Slide-up action bar for batch operations on selected items.
|
||||||
@@ -900,6 +1353,23 @@ Check that `data-theme` attribute is set correctly.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Changelog
|
||||||
|
|
||||||
|
### Version 2.0.0 (2026-01-12)
|
||||||
|
|
||||||
|
- **NEW**: Added `MobileDrawerMenu` component documentation
|
||||||
|
- **NEW**: Added `MobileActionBar` component documentation
|
||||||
|
- **NEW**: Added Navigation Architecture section with route maps
|
||||||
|
- **UPDATED**: MobileBottomNav default items now point to Settings Hub (`/settings`)
|
||||||
|
- **UPDATED**: ASCII diagrams with new routes and component layouts
|
||||||
|
- **UPDATED**: Quick Start section to include drawer menu integration
|
||||||
|
|
||||||
|
### Version 1.0.0 (2026-01-11)
|
||||||
|
|
||||||
|
- Initial release with MobileTopBar, MobileBottomNav, MobileSelectionFooter, BottomSheet, SwipeableCards
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
**Last Updated:** 2026-01-12
|
**Last Updated:** 2026-01-12
|
||||||
**Version:** 1.0.0
|
**Version:** 2.0.0
|
||||||
**Maintained By:** Frontend Team
|
**Maintained By:** Frontend Team
|
||||||
|
|||||||
@@ -246,8 +246,8 @@
|
|||||||
"Diagrame ASCII actualizate cu noile rute",
|
"Diagrame ASCII actualizate cu noile rute",
|
||||||
"npm run build passes (doar pentru validare că nu s-a stricat nimic)"
|
"npm run build passes (doar pentru validare că nu s-a stricat nimic)"
|
||||||
],
|
],
|
||||||
"passes": false,
|
"passes": true,
|
||||||
"notes": ""
|
"notes": "Completed in iteration 14"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,3 +82,9 @@ User Stories: 14 (US-201 to US-214)
|
|||||||
[2026-01-12 12:40:31] Working on story: US-211
|
[2026-01-12 12:40:31] Working on story: US-211
|
||||||
[2026-01-12 12:40:31] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_13_US-211.log)
|
[2026-01-12 12:40:31] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_13_US-211.log)
|
||||||
[2026-01-12 12:42:01] SUCCESS: Story US-211 passed!
|
[2026-01-12 12:42:01] SUCCESS: Story US-211 passed!
|
||||||
|
[2026-01-12 12:42:01] Changes committed
|
||||||
|
[2026-01-12 12:42:01] Progress: 13/14 stories completed
|
||||||
|
[2026-01-12 12:42:03] === Iteration 14/100 ===
|
||||||
|
[2026-01-12 12:42:03] Working on story: US-214
|
||||||
|
[2026-01-12 12:42:03] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_14_US-214.log)
|
||||||
|
[2026-01-12 12:45:42] SUCCESS: Story US-214 passed!
|
||||||
|
|||||||
Reference in New Issue
Block a user