feat(unified-mobile-material-design): Complete US-119 - Actualizare claude-learn-frontend.md cu pattern-uri noi
Implemented by Ralph autonomous loop. Iteration: 7 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -157,3 +157,115 @@ const onFilesSelected = async (event) => {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
**Applied in**: `src/modules/data-entry/components/bulk/BulkUploadZone.vue`
|
**Applied in**: `src/modules/data-entry/components/bulk/BulkUploadZone.vue`
|
||||||
|
|
||||||
|
## P: Mobile Material Design Component Architecture
|
||||||
|
@2026-01-12 #mobile #material-design #vue #architecture | explicit:high
|
||||||
|
Unified mobile UI using shared MD3-inspired components. All mobile pages MUST use MobileTopBar for header and MobileBottomNav for persistent navigation. Components are in `src/shared/components/mobile/`.
|
||||||
|
```vue
|
||||||
|
<template>
|
||||||
|
<div class="mobile-page">
|
||||||
|
<MobileTopBar
|
||||||
|
:title="pageTitle"
|
||||||
|
:show-back="hasBackNavigation"
|
||||||
|
:show-menu="!hasBackNavigation"
|
||||||
|
:actions="headerActions"
|
||||||
|
@back-click="goBack"
|
||||||
|
@action-click="handleAction"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<main class="mobile-content">
|
||||||
|
<!-- Page content with padding for fixed bars -->
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<MobileBottomNav :items="navItems" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import MobileTopBar from '@shared/components/mobile/MobileTopBar.vue'
|
||||||
|
import MobileBottomNav from '@shared/components/mobile/MobileBottomNav.vue'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.mobile-content {
|
||||||
|
padding-top: 56px; /* MobileTopBar height */
|
||||||
|
padding-bottom: 56px; /* MobileBottomNav height */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
```
|
||||||
|
|
||||||
|
## P: Bottom Sheet Filter Pattern
|
||||||
|
@2026-01-12 #mobile #material-design #filters #bottom-sheet | explicit:high
|
||||||
|
On mobile, filters MUST be placed in a BottomSheet component instead of inline. BottomSheet slides up from bottom with drag-to-close gesture. Use a filter icon in MobileTopBar actions to toggle.
|
||||||
|
```vue
|
||||||
|
<template>
|
||||||
|
<MobileTopBar
|
||||||
|
title="Lista"
|
||||||
|
:actions="[{ icon: 'pi pi-filter', label: 'Filtre', active: hasActiveFilters }]"
|
||||||
|
@action-click="handleAction"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<BottomSheet v-model="isFilterOpen">
|
||||||
|
<div class="filter-content">
|
||||||
|
<h3>Filtre</h3>
|
||||||
|
<Dropdown v-model="selectedStatus" :options="statusOptions" />
|
||||||
|
<Calendar v-model="dateRange" selectionMode="range" />
|
||||||
|
<div class="filter-actions">
|
||||||
|
<Button label="Resetează" severity="secondary" @click="resetFilters" />
|
||||||
|
<Button label="Aplică" @click="applyFilters" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</BottomSheet>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import BottomSheet from '@shared/components/mobile/BottomSheet.vue'
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
## P: Mobile Selection Mode Flow
|
||||||
|
@2026-01-12 #mobile #material-design #selection #batch-actions | explicit:high
|
||||||
|
When items are selected on mobile, batch actions appear in MobileSelectionFooter (bottom), NOT in the header. The footer slides up when `selectedItems.length > 0`. Actions array defines available operations per context.
|
||||||
|
```vue
|
||||||
|
<template>
|
||||||
|
<!-- List with selection -->
|
||||||
|
<div v-for="item in items" :key="item.id" @click="toggleSelection(item)">
|
||||||
|
<Checkbox v-model="selectedItems" :value="item.id" />
|
||||||
|
{{ item.name }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Selection footer - appears when items selected -->
|
||||||
|
<MobileSelectionFooter
|
||||||
|
:visible="selectedItems.length > 0 && isMobile"
|
||||||
|
:actions="selectionActions"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import MobileSelectionFooter from '@shared/components/mobile/MobileSelectionFooter.vue'
|
||||||
|
|
||||||
|
const selectionActions = [
|
||||||
|
{ label: 'Șterge', icon: 'pi pi-trash', severity: 'danger', handler: handleDelete },
|
||||||
|
{ label: 'Export', icon: 'pi pi-download', severity: 'secondary', handler: handleExport }
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
## G: Nu duplica delete button în header și footer pe mobil
|
||||||
|
@2026-01-12 #mobile #material-design #ux #selection | explicit:high
|
||||||
|
**P**: Butonul de ștergere apărea în două locuri pe mobil: în bulk-actions-bar (header tabel) ȘI în mobile-selection-bottom-bar (footer), creând confuzie UX.
|
||||||
|
**C**: Desktop și mobile foloseau același cod pentru bulk actions, dar pe mobil acțiunile trebuie să fie DOAR în footer pentru ergonomie touch.
|
||||||
|
**S**: Afișează bulk-actions-bar DOAR când `!isMobile`. Pe mobil, toate acțiunile de selecție apar exclusiv în MobileSelectionFooter:
|
||||||
|
```vue
|
||||||
|
<!-- Desktop: header actions -->
|
||||||
|
<div v-if="selectedItems.length > 0 && !isMobile" class="bulk-actions-bar">
|
||||||
|
<Button icon="pi pi-trash" label="Șterge" @click="handleDelete" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Mobile: footer actions (MobileSelectionFooter handles visibility) -->
|
||||||
|
<MobileSelectionFooter
|
||||||
|
:visible="selectedItems.length > 0 && isMobile"
|
||||||
|
:actions="mobileSelectionActions"
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
**Applied in**: `src/modules/data-entry/views/ReceiptsListView.vue`
|
||||||
|
|||||||
@@ -333,8 +333,8 @@
|
|||||||
"Gotcha: Nu duplica delete button în header și footer",
|
"Gotcha: Nu duplica delete button în header și footer",
|
||||||
"Format corect cu @date și tags #mobile #material-design"
|
"Format corect cu @date și tags #mobile #material-design"
|
||||||
],
|
],
|
||||||
"passes": false,
|
"passes": true,
|
||||||
"notes": ""
|
"notes": "Completed in iteration 7"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -562,3 +562,9 @@ Mon Jan 12 09:44:54 AM UTC 2026
|
|||||||
[2026-01-12 11:19:23] Working on story: US-117
|
[2026-01-12 11:19:23] Working on story: US-117
|
||||||
[2026-01-12 11:19:23] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_6_US-117.log)
|
[2026-01-12 11:19:23] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_6_US-117.log)
|
||||||
[2026-01-12 11:20:26] SUCCESS: Story US-117 passed!
|
[2026-01-12 11:20:26] SUCCESS: Story US-117 passed!
|
||||||
|
[2026-01-12 11:20:26] Changes committed
|
||||||
|
[2026-01-12 11:20:26] Progress: 19/20 stories completed
|
||||||
|
[2026-01-12 11:20:28] === Iteration 7/50 ===
|
||||||
|
[2026-01-12 11:20:28] Working on story: US-119
|
||||||
|
[2026-01-12 11:20:28] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_7_US-119.log)
|
||||||
|
[2026-01-12 11:21:35] SUCCESS: Story US-119 passed!
|
||||||
|
|||||||
Reference in New Issue
Block a user