mirror of
https://origin.cursor.com/mrdevmx/panels.git
synced 2026-10-09 14:13:18 +00:00
Agrupar el menú principal y acercar el ribbon al mockup.
El menú queda en una sola fila con iconos, desplegables por módulo y sin wrap; el ribbon se compacta como tarjeta de acciones. Co-authored-by: alberto.martinez <alberto.martinez@mrdev.mx>
This commit is contained in:
parent
496273b41c
commit
1e1c3b21b8
4 changed files with 256 additions and 23 deletions
|
|
@ -27,6 +27,7 @@ html, body, #__nuxt {
|
|||
min-height: 44px;
|
||||
padding: 0 8px !important;
|
||||
flex-shrink: 0;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
.menubar-link {
|
||||
display: flex;
|
||||
|
|
@ -50,9 +51,8 @@ html, body, #__nuxt {
|
|||
box-shadow: inset 0 -2px 0 #1c4a7a;
|
||||
}
|
||||
.ribbon.p-toolbar {
|
||||
border-radius: 0 !important;
|
||||
border: none !important;
|
||||
border-bottom: 1px solid #d5dde6 !important;
|
||||
border-radius: 8px !important;
|
||||
border: 1px solid #e1e6ed !important;
|
||||
background: #fff !important;
|
||||
padding: 4px 10px 6px !important;
|
||||
flex-shrink: 0;
|
||||
|
|
|
|||
|
|
@ -782,7 +782,7 @@ html, body, #__nuxt {
|
|||
padding-inline: 16px;
|
||||
font-size: 13px;
|
||||
}
|
||||
.menubar-link > i { display: none; }
|
||||
.menubar-link > i { display: inline-flex; }
|
||||
.menubar-link.is-active {
|
||||
box-shadow: inset 0 -3px 0 #2f6fe4;
|
||||
}
|
||||
|
|
@ -2236,3 +2236,188 @@ html.dark .p-dialog .p-dialog-header-icon {
|
|||
.cost-warn { background: #fff8e1 !important; color: #e65100 !important; }
|
||||
.cost-critical { background: #ffebee !important; color: #b42318 !important; }
|
||||
.cost-critical-text { color: #b42318; font-weight: 600; }
|
||||
|
||||
/* Grouped menubar: single row, icons, card-style submenus. */
|
||||
.menubar.p-menubar {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
align-items: center;
|
||||
min-height: 52px;
|
||||
height: 52px;
|
||||
overflow: visible;
|
||||
}
|
||||
.brand-lockup {
|
||||
height: 52px;
|
||||
min-width: 148px;
|
||||
padding-right: 18px;
|
||||
}
|
||||
.menubar .p-menubar-start,
|
||||
.menubar .p-menubar-end {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
.menubar .p-menubar-root-list {
|
||||
display: flex;
|
||||
flex-wrap: nowrap !important;
|
||||
align-items: stretch;
|
||||
min-width: 0;
|
||||
flex: 1 1 auto;
|
||||
gap: 2px;
|
||||
margin: 0;
|
||||
overflow: visible;
|
||||
}
|
||||
.menubar .p-menubar-item {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
.menubar-link {
|
||||
min-height: 52px;
|
||||
height: 52px;
|
||||
box-sizing: border-box;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 7px;
|
||||
padding-inline: 11px;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
color: #243044;
|
||||
}
|
||||
.menubar-link > i {
|
||||
display: inline-flex !important;
|
||||
font-size: 13px;
|
||||
color: #4b6380;
|
||||
}
|
||||
.menubar-link .menubar-chevron {
|
||||
margin-left: 1px;
|
||||
font-size: 10px;
|
||||
opacity: .7;
|
||||
}
|
||||
.menubar-link.is-active {
|
||||
color: #1f5fd1;
|
||||
box-shadow: inset 0 -3px 0 #2f6fe4;
|
||||
}
|
||||
.menubar-link.is-active > i,
|
||||
.menubar-link.is-active .menubar-chevron {
|
||||
color: #2f6fe4;
|
||||
}
|
||||
.menubar .p-menubar-submenu {
|
||||
min-width: 228px;
|
||||
padding: 6px;
|
||||
margin-top: 0;
|
||||
border: 1px solid #e1e6ed;
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
box-shadow: 0 10px 28px rgba(23, 32, 51, .12);
|
||||
}
|
||||
.menubar .p-menubar-submenu .p-menubar-item-content {
|
||||
border-radius: 6px;
|
||||
}
|
||||
.menubar .p-menubar-submenu .menubar-link {
|
||||
width: 100%;
|
||||
min-height: 38px;
|
||||
height: 38px;
|
||||
padding: 0 10px;
|
||||
font-weight: 500;
|
||||
border-radius: 6px;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
.menubar .p-menubar-submenu .menubar-link:hover {
|
||||
background: #f4f7fb;
|
||||
}
|
||||
.menubar .p-menubar-submenu .menubar-link.is-active {
|
||||
background: #eaf2ff;
|
||||
color: #174fba;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
/* Ribbon as compact action card (mockup). */
|
||||
.ribbon.p-toolbar {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
min-height: 88px;
|
||||
margin: 8px 8px 10px;
|
||||
padding: 8px 12px 6px !important;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
border: 1px solid var(--shell-border, #e1e6ed) !important;
|
||||
border-radius: 8px !important;
|
||||
background: #fff !important;
|
||||
box-shadow: var(--shell-shadow, 0 2px 9px rgba(23, 32, 51, .055));
|
||||
}
|
||||
.ribbon .p-toolbar-start {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
align-items: stretch;
|
||||
gap: 0;
|
||||
min-width: 0;
|
||||
}
|
||||
.ribbon-cluster {
|
||||
flex: 0 0 auto;
|
||||
align-items: stretch;
|
||||
}
|
||||
.ribbon-group {
|
||||
gap: 4px;
|
||||
}
|
||||
.ribbon-group-items {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
gap: 4px;
|
||||
}
|
||||
.ribbon-group-label {
|
||||
text-transform: none;
|
||||
letter-spacing: .02em;
|
||||
font-size: 10px;
|
||||
color: #748095;
|
||||
}
|
||||
.ribbon .ribbon-action {
|
||||
min-width: 64px;
|
||||
min-height: 64px;
|
||||
padding: 8px 10px 6px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.ribbon .ribbon-action .p-button-icon {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
margin-bottom: 4px;
|
||||
font-size: 20px !important;
|
||||
line-height: 22px;
|
||||
color: #4b6380;
|
||||
}
|
||||
.ribbon .ribbon-action .p-button-label {
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
line-height: 1.2;
|
||||
}
|
||||
.ribbon .ribbon-action--alta .p-button-icon {
|
||||
color: #2f6fe4;
|
||||
}
|
||||
.ribbon .ribbon-action:not(:disabled):hover {
|
||||
background: #f4f7fb;
|
||||
}
|
||||
.ribbon .p-divider-vertical {
|
||||
min-height: 64px;
|
||||
margin-inline: 8px;
|
||||
}
|
||||
|
||||
html.dark .menubar .p-menubar-submenu {
|
||||
background: #111b2e !important;
|
||||
border-color: #243044 !important;
|
||||
box-shadow: 0 10px 28px rgba(0, 0, 0, .4);
|
||||
}
|
||||
html.dark .menubar .p-menubar-submenu .menubar-link {
|
||||
color: #f1f5f9 !important;
|
||||
}
|
||||
html.dark .menubar .p-menubar-submenu .menubar-link:hover {
|
||||
background: rgba(47, 111, 228, 0.14) !important;
|
||||
}
|
||||
html.dark .menubar .p-menubar-submenu .menubar-link.is-active {
|
||||
background: rgba(47, 111, 228, 0.22) !important;
|
||||
color: #93c5fd !important;
|
||||
}
|
||||
html.dark .menubar-link > i,
|
||||
html.dark .menubar-link .menubar-chevron {
|
||||
color: #94a3b8;
|
||||
}
|
||||
html.dark .menubar-link.is-active > i,
|
||||
html.dark .menubar-link.is-active .menubar-chevron {
|
||||
color: #93c5fd;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<Toolbar class="ribbon">
|
||||
<Toolbar v-if="ribbon.length" class="ribbon">
|
||||
<template #start>
|
||||
<div v-for="(group, i) in ribbon" :key="group.key" class="ribbon-cluster">
|
||||
<Divider v-if="i > 0" layout="vertical" />
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div class="shell">
|
||||
<Menubar class="menubar" :model="menu">
|
||||
<Menubar class="menubar" :model="menu" breakpoint="1100px">
|
||||
<template #start>
|
||||
<button type="button" class="brand-lockup" aria-label="Ir al inicio" @click="navigateTo('/')">
|
||||
<span class="brand-mark" aria-hidden="true">
|
||||
|
|
@ -9,10 +9,19 @@
|
|||
<span class="brand-word">{{ brand }}</span>
|
||||
</button>
|
||||
</template>
|
||||
<template #item="{ item, props }">
|
||||
<a v-bind="props.action" class="menubar-link" :class="{ 'is-active': isActive(String(item.to || '')) }">
|
||||
<i v-if="item.icon" :class="item.icon" />
|
||||
<template #item="{ item, props, hasSubmenu, root }">
|
||||
<a
|
||||
v-bind="props.action"
|
||||
class="menubar-link"
|
||||
:class="{
|
||||
'is-active': itemIsActive(item),
|
||||
'is-root': root !== false,
|
||||
'has-submenu': Boolean(hasSubmenu || item.items?.length),
|
||||
}"
|
||||
>
|
||||
<i v-if="item.icon" :class="item.icon" aria-hidden="true" />
|
||||
<span>{{ item.label }}</span>
|
||||
<i v-if="hasSubmenu || item.items?.length" class="pi pi-angle-down menubar-chevron" aria-hidden="true" />
|
||||
</a>
|
||||
</template>
|
||||
<template #end>
|
||||
|
|
@ -140,20 +149,53 @@ const profileItems = computed(() => [
|
|||
|
||||
const brand = computed(() => "PANELS");
|
||||
|
||||
const menu = [
|
||||
{ label: "Inicio", icon: "pi pi-home", to: "/", command: () => navigateTo("/") },
|
||||
{ label: "Proyectos", icon: "pi pi-building", to: "/proyectos", command: () => navigateTo("/proyectos") },
|
||||
{ label: "Presupuesto", icon: "pi pi-calculator", to: "/presupuesto", command: () => navigateTo("/presupuesto") },
|
||||
{ label: "Programa de obra", icon: "pi pi-calendar", to: "/programa-obra", command: () => navigateTo("/programa-obra") },
|
||||
{ label: "Control costos", icon: "pi pi-chart-bar", to: "/control-presupuesto", command: () => navigateTo("/control-presupuesto") },
|
||||
{ label: "Gastos", icon: "pi pi-money-bill", to: "/gastos", command: () => navigateTo("/gastos") },
|
||||
{ label: "Almacén", icon: "pi pi-box", to: "/almacen", command: () => navigateTo("/almacen") },
|
||||
{ label: "Padrón", icon: "pi pi-users", to: "/padron", command: () => navigateTo("/padron") },
|
||||
{ label: "Kanban", icon: "pi pi-th-large", to: "/kanban", command: () => navigateTo("/kanban") },
|
||||
{ label: "Gafetes", icon: "pi pi-id-card", to: "/gafetes", command: () => navigateTo("/gafetes") },
|
||||
{ label: "Nómina", icon: "pi pi-wallet", to: "/nomina", command: () => navigateTo("/nomina") },
|
||||
{ label: "Usuarios", icon: "pi pi-shield", to: "/usuarios", command: () => navigateTo("/usuarios") },
|
||||
{ label: "Ayuda", icon: "pi pi-question-circle", command: showHelp },
|
||||
type NavItem = {
|
||||
label: string;
|
||||
icon?: string;
|
||||
to?: string;
|
||||
command?: () => void;
|
||||
items?: NavItem[];
|
||||
};
|
||||
|
||||
function nav(label: string, icon: string, to: string): NavItem {
|
||||
return { label, icon, to, command: () => navigateTo(to) };
|
||||
}
|
||||
|
||||
const menu: NavItem[] = [
|
||||
nav("Inicio", "pi pi-home", "/"),
|
||||
{
|
||||
label: "Obra",
|
||||
icon: "pi pi-building",
|
||||
items: [
|
||||
nav("Proyectos", "pi pi-building", "/proyectos"),
|
||||
nav("Presupuesto", "pi pi-calculator", "/presupuesto"),
|
||||
nav("Programa de obra", "pi pi-calendar", "/programa-obra"),
|
||||
nav("Control costos", "pi pi-chart-bar", "/control-presupuesto"),
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "Operación",
|
||||
icon: "pi pi-briefcase",
|
||||
items: [
|
||||
nav("Gastos", "pi pi-money-bill", "/gastos"),
|
||||
nav("Almacén", "pi pi-box", "/almacen"),
|
||||
nav("Kanban", "pi pi-th-large", "/kanban"),
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "Personal",
|
||||
icon: "pi pi-users",
|
||||
items: [
|
||||
nav("Padrón", "pi pi-users", "/padron"),
|
||||
nav("Gafetes", "pi pi-id-card", "/gafetes"),
|
||||
nav("Nómina", "pi pi-wallet", "/nomina"),
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "Administración",
|
||||
icon: "pi pi-shield",
|
||||
items: [nav("Usuarios", "pi pi-shield", "/usuarios")],
|
||||
},
|
||||
];
|
||||
|
||||
function isActive(to: string) {
|
||||
|
|
@ -162,6 +204,12 @@ function isActive(to: string) {
|
|||
return route.path === to || route.path.startsWith(`${to}/`);
|
||||
}
|
||||
|
||||
function itemIsActive(item: NavItem | undefined): boolean {
|
||||
if (!item) return false;
|
||||
if (item.to && isActive(item.to)) return true;
|
||||
return Boolean(item.items?.some((child) => itemIsActive(child)));
|
||||
}
|
||||
|
||||
function goSearch() {
|
||||
navigateTo("/padron");
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue