feat(ui) : improve mobile responsiveness — breadcrumb truncation, tabs scroll, form grids

This commit is contained in:
2026-04-04 17:25:36 +02:00
parent 7f91b30bf6
commit 5b06e2ba51
7 changed files with 89 additions and 64 deletions

View File

@@ -0,0 +1,33 @@
<template>
<div class="text-center py-12">
<div v-if="icon" class="w-16 h-16 rounded-2xl bg-base-200 grid place-items-center mx-auto mb-5">
<component :is="icon" class="w-8 h-8 text-base-content/30" aria-hidden="true" />
</div>
<h3 class="text-lg font-semibold text-base-content mb-1">{{ title }}</h3>
<p v-if="description" class="text-sm text-base-content/50 mb-6">{{ description }}</p>
<slot>
<NuxtLink v-if="actionTo" :to="actionTo" class="btn btn-primary btn-sm">
{{ actionLabel }}
</NuxtLink>
<button v-else-if="actionLabel" type="button" class="btn btn-primary btn-sm" @click="$emit('action')">
{{ actionLabel }}
</button>
</slot>
</div>
</template>
<script setup lang="ts">
import type { Component } from 'vue'
defineProps<{
title: string
description?: string
icon?: Component
actionLabel?: string
actionTo?: string
}>()
defineEmits<{
action: []
}>()
</script>

View File

@@ -1,6 +1,6 @@
<template>
<div>
<nav class="tabs tabs-bordered mb-6" role="tablist" :aria-label="ariaLabel">
<nav class="tabs tabs-bordered mb-6 overflow-x-auto flex-nowrap" role="tablist" :aria-label="ariaLabel">
<button
v-for="tab in tabs"
:key="tab.key"

View File

@@ -2,15 +2,29 @@
<nav v-if="crumbs.length > 1" class="container mx-auto px-6 pt-4" aria-label="Fil d'Ariane">
<div class="text-sm breadcrumbs py-0">
<ul>
<li v-for="(crumb, i) in crumbs" :key="i">
<NuxtLink
v-if="i < crumbs.length - 1"
:to="crumb.path"
class="text-base-content/60 hover:text-primary transition-colors"
>
<!-- First crumb (always visible) -->
<li>
<NuxtLink :to="crumbs[0].path" class="text-base-content/60 hover:text-primary transition-colors">
{{ crumbs[0].label }}
</NuxtLink>
</li>
<!-- Ellipsis on mobile when there are middle crumbs -->
<li v-if="crumbs.length > 2" class="sm:hidden">
<span class="text-base-content/40"></span>
</li>
<!-- Middle crumbs: hidden on mobile, visible sm+ -->
<li
v-for="(crumb, i) in crumbs.slice(1, crumbs.length - 1)"
:key="i"
class="hidden sm:list-item"
>
<NuxtLink :to="crumb.path" class="text-base-content/60 hover:text-primary transition-colors">
{{ crumb.label }}
</NuxtLink>
<span v-else class="text-base-content font-medium">{{ crumb.label }}</span>
</li>
<!-- Last crumb (always visible, current page) -->
<li v-if="crumbs.length > 1">
<span class="text-base-content font-medium">{{ crumbs[crumbs.length - 1].label }}</span>
</li>
</ul>
</div>

View File

@@ -144,9 +144,6 @@
<script setup lang="ts">
import { ref, computed } from 'vue'
import DocumentPreviewModal from '~/components/DocumentPreviewModal.vue'
const route = useRoute()
const machineId = computed(() => route.params.id as string | undefined)
import { canPreviewDocument } from '~/utils/documentPreview'
import {
formatSize,
@@ -154,6 +151,9 @@ import {
downloadDocument,
} from '~/shared/utils/documentDisplayUtils'
const route = useRoute()
const machineId = computed(() => route.params.id as string | undefined)
defineProps<{
products: Array<{
id?: string | null

View File

@@ -68,34 +68,22 @@
</div>
<!-- Empty State -->
<div v-else-if="filteredSites.length === 0" class="text-center py-16">
<div class="max-w-sm mx-auto">
<div class="w-16 h-16 rounded-2xl bg-base-200 grid place-items-center mx-auto mb-5">
<IconLucideFactory
class="w-8 h-8 text-base-content/30"
aria-hidden="true"
/>
</div>
<h3 class="text-lg font-semibold text-base-content mb-1">
Aucune machine trouvée
</h3>
<p class="text-sm text-base-content/50 mb-6">
Commencez par ajouter des sites et des machines.
</p>
<div class="flex gap-2 justify-center">
<button v-if="canEdit" class="btn btn-primary btn-sm" @click="showAddSiteModal = true">
Ajouter un site
</button>
<button
v-if="canEdit"
class="btn btn-ghost btn-sm"
@click="showAddMachineModal = true"
>
Ajouter une machine
</button>
</div>
<CommonEmptyState
v-else-if="filteredSites.length === 0"
:icon="IconLucideFactory"
title="Aucune machine trouvée"
description="Commencez par ajouter des sites et des machines."
class="py-16"
>
<div v-if="canEdit" class="flex gap-2 justify-center">
<button class="btn btn-primary btn-sm" @click="showAddSiteModal = true">
Ajouter un site
</button>
<button class="btn btn-ghost btn-sm" @click="showAddMachineModal = true">
Ajouter une machine
</button>
</div>
</div>
</CommonEmptyState>
<!-- Sites List -->
<div v-else class="space-y-5">

View File

@@ -173,18 +173,14 @@
</div>
<!-- Error State -->
<div v-else class="text-center py-12">
<div class="max-w-md mx-auto">
<div class="w-16 h-16 rounded-2xl bg-base-200 grid place-items-center mx-auto mb-5">
<IconLucideAlertTriangle class="w-8 h-8 text-base-content/30" aria-hidden="true" />
</div>
<h3 class="text-lg font-semibold text-base-content mb-1">Machine non trouvée</h3>
<p class="text-sm text-base-content/50 mb-6">La machine avec l'ID "{{ machineId }}" n'existe pas ou a été supprimée.</p>
<button type="button" class="btn btn-primary" @click="$router.back()">
Retour aux machines
</button>
</div>
</div>
<CommonEmptyState
v-else
:icon="IconLucideAlertTriangle"
title="Machine non trouvée"
:description="`La machine avec l'ID « ${machineId} » n'existe pas ou a été supprimée.`"
action-label="Retour aux machines"
@action="$router.back()"
/>
</main>
<MachinePrintSelectionModal

View File

@@ -53,20 +53,14 @@
<span class="loading loading-spinner loading-lg" />
</div>
<div v-else-if="filteredMachines.length === 0" class="text-center py-12">
<div class="max-w-md mx-auto">
<IconLucideFactory class="w-16 h-16 mx-auto text-gray-400 mb-4" aria-hidden="true" />
<h3 class="text-lg font-medium text-gray-900 mb-2">
Aucune machine trouvée
</h3>
<p class="text-gray-500 mb-4">
Commencez par ajouter votre première machine.
</p>
<NuxtLink to="/machines/new" class="btn btn-primary">
Ajouter une machine
</NuxtLink>
</div>
</div>
<CommonEmptyState
v-else-if="filteredMachines.length === 0"
:icon="IconLucideFactory"
title="Aucune machine trouvée"
description="Commencez par ajouter votre première machine."
action-label="Ajouter une machine"
action-to="/machines/new"
/>
<div v-else class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<div