added dropdown in header
This commit is contained in:
parent
d839f631f8
commit
e2bd654c9c
@ -1,6 +1,7 @@
|
||||
import React, { useEffect, useRef } from "react";
|
||||
import { PmsGrid } from "./index";
|
||||
import { initPopover } from "./GridService";
|
||||
import PmsHeaderOption from "./PmsHeaderOption";
|
||||
|
||||
/**
|
||||
* CIVIL BOQ / INVENTORY DEMO DATA
|
||||
@ -719,6 +720,8 @@ export default function DemoBOQGrid() {
|
||||
return (
|
||||
<div className="container-fluid py-3">
|
||||
<div className="card p-3">
|
||||
|
||||
|
||||
<PmsGrid
|
||||
data={boqData.map((r) => ({
|
||||
...r,
|
||||
|
||||
@ -2,6 +2,7 @@ import React, { useRef } from "react";
|
||||
import { useGridCore } from "./useGridCore";
|
||||
import { exportToCSV } from "./utils";
|
||||
import "./pms-grid.css";
|
||||
import PmsHeaderOption from "./PmsHeaderOption";
|
||||
|
||||
/*
|
||||
Props:
|
||||
@ -55,10 +56,17 @@ export default function PmsGrid({
|
||||
setColState,
|
||||
} = grid;
|
||||
|
||||
// simple pin toggle
|
||||
const togglePin = (key) => {
|
||||
// --- Pin / Unpin helpers ---
|
||||
const pinColumn = (key, side) => {
|
||||
const col = colState.find((c) => c.key === key);
|
||||
updateColumn(key, { pinned: col.pinned === "left" ? null : "left" });
|
||||
if (!col) return;
|
||||
// if already pinned to that side → unpin
|
||||
const newPinned = col.pinned === side || side === "none" ? null : side;
|
||||
updateColumn(key, { pinned: newPinned });
|
||||
};
|
||||
|
||||
const unpinColumn = (key) => {
|
||||
updateColumn(key, { pinned: null });
|
||||
};
|
||||
|
||||
// resizing via mouse down on handle
|
||||
@ -199,7 +207,7 @@ export default function PmsGrid({
|
||||
style={{ maxHeight: features.maxHeight || "60vh" }}
|
||||
>
|
||||
<table
|
||||
className="table table-sm rounded mb-0"
|
||||
className="table table-sm rounded mb-0 "
|
||||
style={{ width: "max-content", minWidth: "100%" }}
|
||||
>
|
||||
<thead
|
||||
@ -243,7 +251,7 @@ export default function PmsGrid({
|
||||
key={col.key}
|
||||
draggable={features.reorder}
|
||||
onDragStart={(e) => onDragStart(e, col.key)}
|
||||
onDragOver={(e) => e.preventDefault()}
|
||||
onDragOver={(e)=> e.preventDefault()}
|
||||
onDrop={(e) => onDrop(e, col.key)}
|
||||
className={`pms-col-header vs-th ${
|
||||
col.pinned ? `pinned pinned-${col.pinned}` : ""
|
||||
@ -269,17 +277,17 @@ export default function PmsGrid({
|
||||
}`}
|
||||
></i>
|
||||
)}
|
||||
{col.pinned === col.key && <i className="bx bx-x"></i>}
|
||||
</div>
|
||||
|
||||
<div className="d-flex align-items-center gap-1">
|
||||
{features.pinning && (
|
||||
<button
|
||||
className="btn btn-sm btn-link p-0"
|
||||
title="Pin/Unpin"
|
||||
onClick={() => togglePin(col.key)}
|
||||
>
|
||||
<i className="bx bx-pin"></i>
|
||||
</button>
|
||||
<PmsHeaderOption
|
||||
pinned={col.pinned}
|
||||
onPinLeft={() => pinColumn(col.key, "left")}
|
||||
onPinRight={() => pinColumn(col.key, "right")}
|
||||
onUnpin={() => unpinColumn(col.key)}
|
||||
/>
|
||||
)}
|
||||
{features.resizing && (
|
||||
<i
|
||||
@ -322,7 +330,7 @@ export default function PmsGrid({
|
||||
{!loading && groupBy && groupedRows && groupedRows.length > 0
|
||||
? groupedRows.map((g) => (
|
||||
<React.Fragment key={g.key}>
|
||||
<tr className="table-secondary">
|
||||
<tr className="table-secondary border-0">
|
||||
<td
|
||||
colSpan={
|
||||
visibleColumns.length +
|
||||
|
||||
52
src/services/pmsGrid/PmsHeaderOption.jsx
Normal file
52
src/services/pmsGrid/PmsHeaderOption.jsx
Normal file
@ -0,0 +1,52 @@
|
||||
const PmsHeaderOption = ({ pinned, onPinLeft, onPinRight, onUnpin }) => {
|
||||
return (
|
||||
<div className="dropdown z-100">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-icon btn-text-secondary rounded-pill p-0"
|
||||
data-bs-toggle="dropdown"
|
||||
data-bs-auto-close="outside"
|
||||
aria-expanded="false"
|
||||
>
|
||||
<i className="bx bx-dots-vertical-rounded bx-sm text-muted"></i>
|
||||
</button>
|
||||
|
||||
<ul className="dropdown-menu dropdown-menu-end shadow-sm border-0 rounded-3 py-2">
|
||||
<li>
|
||||
<button
|
||||
className={`dropdown-item d-flex align-items-center ${
|
||||
pinned === "left" ? "active" : ""
|
||||
}`}
|
||||
onClick={onPinLeft}
|
||||
>
|
||||
<i className="bx bx-pin me-2"></i> Pin Left
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button
|
||||
className={`dropdown-item d-flex align-items-center ${
|
||||
pinned === "right" ? "active" : ""
|
||||
}`}
|
||||
onClick={onPinRight}
|
||||
>
|
||||
<i className="bx bx-pin me-2"></i> Pin Right
|
||||
</button>
|
||||
</li>
|
||||
{pinned && (
|
||||
<>
|
||||
<li><hr className="dropdown-divider" /></li>
|
||||
<li>
|
||||
<button
|
||||
className="dropdown-item text-danger d-flex align-items-center"
|
||||
onClick={onUnpin}
|
||||
>
|
||||
<i className="bx bx-x me-2"></i> Unpin Column
|
||||
</button>
|
||||
</li>
|
||||
</>
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default PmsHeaderOption;
|
||||
@ -5,24 +5,25 @@
|
||||
width: 100%;
|
||||
position: relative;
|
||||
font-size: 0.875rem;
|
||||
|
||||
}
|
||||
|
||||
/* ──────────────────────────────
|
||||
SCROLLABLE WRAPPER
|
||||
────────────────────────────── */
|
||||
.grid-wrapper {
|
||||
max-height: 60vh;
|
||||
max-height: 50vh;
|
||||
overflow-y: auto;
|
||||
overflow-x: auto;
|
||||
position: relative;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 0.2rem;
|
||||
background: #fff;
|
||||
/* ✅ Force horizontal scroll even if few columns */
|
||||
/* Force horizontal scroll even if few columns */
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* ✅ Always visible scrollbar (cross browser) */
|
||||
/* Always visible scrollbar (cross browser) */
|
||||
.grid-wrapper::-webkit-scrollbar {
|
||||
height: 3px;
|
||||
width: 3px;
|
||||
@ -39,13 +40,19 @@
|
||||
TABLE BASE STYLE
|
||||
────────────────────────────── */
|
||||
.pms-grid table {
|
||||
width: max-content; /* ✅ allows scrolling horizontally */
|
||||
width: max-content; /* allows scrolling horizontally */
|
||||
min-width: 100%;
|
||||
border-collapse: separate;
|
||||
border-spacing: 0;
|
||||
table-layout: fixed;
|
||||
background: #fff;
|
||||
}
|
||||
.pms-col-header {
|
||||
position: relative;
|
||||
overflow: visible !important;
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
|
||||
.pms-grid th,
|
||||
.pms-grid td {
|
||||
@ -81,7 +88,7 @@
|
||||
box-shadow: 2px 0 4px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
/* ✅ Always sticky first column (checkbox) */
|
||||
/* Always sticky first column (checkbox) */
|
||||
.pms-grid th:first-child,
|
||||
.pms-grid td:first-child {
|
||||
position: sticky;
|
||||
@ -94,7 +101,7 @@
|
||||
box-shadow: 2px 0 3px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
/* ✅ Always sticky last column (Actions) */
|
||||
/* Always sticky last column (Actions) */
|
||||
.pms-grid th:last-child,
|
||||
.pms-grid td:last-child {
|
||||
position: sticky;
|
||||
@ -114,7 +121,7 @@
|
||||
display: inline-block;
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s;
|
||||
color: #0d6efd;
|
||||
color: var(--bs-primary);
|
||||
}
|
||||
|
||||
.pms-col-header:hover .resize-handle {
|
||||
@ -157,6 +164,9 @@
|
||||
.z-6 {
|
||||
z-index: 6 !important;
|
||||
}
|
||||
.z-100{
|
||||
z-index: 100 !important;
|
||||
}
|
||||
/* ──────────────────────────────
|
||||
PINNED HEADER COLUMNS (Fix for misalignment)
|
||||
────────────────────────────── */
|
||||
@ -165,7 +175,7 @@
|
||||
.pms-grid th.pinned-left {
|
||||
position: sticky;
|
||||
left: 0;
|
||||
z-index: 9;
|
||||
z-index: 12;
|
||||
background: #fff;
|
||||
box-shadow: 2px 0 3px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
@ -174,9 +184,10 @@
|
||||
.pms-grid th.pinned-right {
|
||||
position: sticky;
|
||||
right: 0;
|
||||
z-index: 9;
|
||||
z-index: 12;
|
||||
background: #fff;
|
||||
box-shadow: -2px 0 3px rgba(0, 0, 0, 0.08);
|
||||
|
||||
}
|
||||
|
||||
/* Match body pinned cell behavior */
|
||||
@ -186,6 +197,7 @@
|
||||
z-index: 8;
|
||||
background: #fff;
|
||||
box-shadow: 2px 0 3px rgba(0, 0, 0, 0.08);
|
||||
border-right: 1px solid var(--bs-primary);
|
||||
}
|
||||
|
||||
.pms-grid td.pinned-right {
|
||||
@ -194,4 +206,27 @@
|
||||
z-index: 8;
|
||||
background: #fff;
|
||||
box-shadow: -2px 0 3px rgba(0, 0, 0, 0.08);
|
||||
|
||||
|
||||
}
|
||||
.dropend:hover > .dropdown-menu {
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
||||
/* Hover color consistency with Sneat variables */
|
||||
.dropdown-item:focus,
|
||||
.dropdown-item:hover {
|
||||
background-color: rgba(var(--bs-primary-rgb), 0.08);
|
||||
color: var(--bs-primary);
|
||||
}
|
||||
|
||||
/* Responsive fallback: stack submenu below parent on small screens */
|
||||
@media (max-width: 768px) {
|
||||
.dropend .dropdown-menu {
|
||||
position: relative;
|
||||
left: 0;
|
||||
top: 0;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user