Improve MassDataGrid UI: custom sort icons & filter inputs

Replaced default sort icons with custom SVGs for clarity.
Updated filter row to use styled DxTextBox inputs with search icons.
Ensured consistent and intuitive filtering experience across columns.
This commit is contained in:
OlgunR
2026-02-05 08:54:21 +01:00
parent 88c34ef94b
commit 4ef80ce875
2 changed files with 180 additions and 14 deletions

View File

@@ -9,6 +9,47 @@
margin-top: 12px;
margin-bottom: 16px;
}
.massdata-grid .dxbl-grid-sort-asc,
.massdata-grid .dxbl-grid-sort-desc {
display: none;
}
.massdata-grid th.dxbl-grid-header-sortable {
position: relative;
padding-right: 1.5rem;
}
.massdata-grid th.dxbl-grid-header-sortable::before,
.massdata-grid th.dxbl-grid-header-sortable::after {
content: "";
position: absolute;
right: 0.45rem;
width: 0.7rem;
height: 0.7rem;
background-repeat: no-repeat;
background-size: 0.7rem 0.7rem;
opacity: 0.35;
pointer-events: none;
}
.massdata-grid th.dxbl-grid-header-sortable::before {
top: 38%;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4.957 10.999a1 1 0 0 1-.821-1.571l2.633-3.785a1.5 1.5 0 0 1 2.462 0l2.633 3.785a1 1 0 0 1-.821 1.57H4.957Z' fill='%23888888'/%3E%3C/svg%3E");
}
.massdata-grid th.dxbl-grid-header-sortable::after {
top: 58%;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4.957 5a1 1 0 0 0-.821 1.571l2.633 3.784a1.5 1.5 0 0 0 2.462 0l2.633-3.784A1 1 0 0 0 11.043 5H4.957Z' fill='%23888888'/%3E%3C/svg%3E");
}
.massdata-grid th.dxbl-grid-header-sortable[aria-sort="ascending"]::after {
opacity: 0;
}
.massdata-grid th.dxbl-grid-header-sortable[aria-sort="descending"]::before {
opacity: 0;
}
.massdata-grid .filter-search-input input {
padding-right: 1.75rem;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M9.309 10.016a4.5 4.5 0 1 1 .707-.707l3.838 3.837a.5.5 0 0 1-.708.708L9.31 10.016ZM10 6.5a3.5 3.5 0 1 0-7 0 3.5 3.5 0 0 0 7 0Z' fill='%23666666'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: right 0.5rem center;
background-size: 0.9rem;
}
</style>
@if (!string.IsNullOrWhiteSpace(errorMessage))
@@ -65,13 +106,55 @@ else
<div class="grid-section">
<DxGrid Data="@items" TItem="MassDataReadDto" KeyFieldName="@nameof(MassDataReadDto.Id)" ShowFilterRow="true" ShowGroupPanel="true" AllowColumnResize="true" PagerVisible="false" PageSize="100" CssClass="mb-3 massdata-grid">
<Columns>
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.Id)" Caption="Id" Width="90px" />
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.CustomerName)" Caption="CustomerName" />
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.Amount)" Caption="Amount" DisplayFormat="c2" />
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.Category)" Caption="Category" />
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.StatusFlag)" Caption="Status" />
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.AddedWhen)" Caption="Added" />
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.ChangedWhen)" Caption="Changed" />
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.Id)" Caption="Id" Width="90px">
<FilterRowCellTemplate Context="filter">
<DxTextBox Text="@(filter.FilterRowValue?.ToString())"
TextChanged="@(value => filter.FilterRowValue = value)"
CssClass="filter-search-input" />
</FilterRowCellTemplate>
</DxGridDataColumn>
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.CustomerName)" Caption="CustomerName">
<FilterRowCellTemplate Context="filter">
<DxTextBox Text="@(filter.FilterRowValue as string)"
TextChanged="@(value => filter.FilterRowValue = value)"
CssClass="filter-search-input" />
</FilterRowCellTemplate>
</DxGridDataColumn>
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.Amount)" Caption="Amount" DisplayFormat="c2">
<FilterRowCellTemplate Context="filter">
<DxTextBox Text="@(filter.FilterRowValue?.ToString())"
TextChanged="@(value => filter.FilterRowValue = value)"
CssClass="filter-search-input" />
</FilterRowCellTemplate>
</DxGridDataColumn>
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.Category)" Caption="Category">
<FilterRowCellTemplate Context="filter">
<DxTextBox Text="@(filter.FilterRowValue as string)"
TextChanged="@(value => filter.FilterRowValue = value)"
CssClass="filter-search-input" />
</FilterRowCellTemplate>
</DxGridDataColumn>
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.StatusFlag)" Caption="Status">
<FilterRowCellTemplate Context="filter">
<DxTextBox Text="@(filter.FilterRowValue?.ToString())"
TextChanged="@(value => filter.FilterRowValue = value)"
CssClass="filter-search-input" />
</FilterRowCellTemplate>
</DxGridDataColumn>
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.AddedWhen)" Caption="Added">
<FilterRowCellTemplate Context="filter">
<DxTextBox Text="@(filter.FilterRowValue?.ToString())"
TextChanged="@(value => filter.FilterRowValue = value)"
CssClass="filter-search-input" />
</FilterRowCellTemplate>
</DxGridDataColumn>
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.ChangedWhen)" Caption="Changed">
<FilterRowCellTemplate Context="filter">
<DxTextBox Text="@(filter.FilterRowValue?.ToString())"
TextChanged="@(value => filter.FilterRowValue = value)"
CssClass="filter-search-input" />
</FilterRowCellTemplate>
</DxGridDataColumn>
<DxGridDataColumn Caption="" Width="220px" AllowSort="false">
<CellDisplayTemplate Context="cell">
@{ var item = (MassDataReadDto)cell.DataItem; }

View File

@@ -9,6 +9,47 @@
margin-top: 12px;
margin-bottom: 16px;
}
.massdata-grid .dxbl-grid-sort-asc,
.massdata-grid .dxbl-grid-sort-desc {
display: none;
}
.massdata-grid th.dxbl-grid-header-sortable {
position: relative;
padding-right: 1.5rem;
}
.massdata-grid th.dxbl-grid-header-sortable::before,
.massdata-grid th.dxbl-grid-header-sortable::after {
content: "";
position: absolute;
right: 0.45rem;
width: 0.7rem;
height: 0.7rem;
background-repeat: no-repeat;
background-size: 0.7rem 0.7rem;
opacity: 0.35;
pointer-events: none;
}
.massdata-grid th.dxbl-grid-header-sortable::before {
top: 38%;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4.957 10.999a1 1 0 0 1-.821-1.571l2.633-3.785a1.5 1.5 0 0 1 2.462 0l2.633 3.785a1 1 0 0 1-.821 1.57H4.957Z' fill='%23888888'/%3E%3C/svg%3E");
}
.massdata-grid th.dxbl-grid-header-sortable::after {
top: 58%;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4.957 5a1 1 0 0 0-.821 1.571l2.633 3.784a1.5 1.5 0 0 0 2.462 0l2.633-3.784A1 1 0 0 0 11.043 5H4.957Z' fill='%23888888'/%3E%3C/svg%3E");
}
.massdata-grid th.dxbl-grid-header-sortable[aria-sort="ascending"]::after {
opacity: 0;
}
.massdata-grid th.dxbl-grid-header-sortable[aria-sort="descending"]::before {
opacity: 0;
}
.massdata-grid .filter-search-input input {
padding-right: 1.75rem;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M9.309 10.016a4.5 4.5 0 1 1 .707-.707l3.838 3.837a.5.5 0 0 1-.708.708L9.31 10.016ZM10 6.5a3.5 3.5 0 1 0-7 0 3.5 3.5 0 0 0 7 0Z' fill='%23666666'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: right 0.5rem center;
background-size: 0.9rem;
}
</style>
@if (!string.IsNullOrWhiteSpace(errorMessage))
@@ -65,13 +106,55 @@ else
<div class="grid-section">
<DxGrid Data="@items" TItem="MassDataReadDto" KeyFieldName="@nameof(MassDataReadDto.Id)" ShowFilterRow="true" ShowGroupPanel="true" AllowColumnResize="true" PagerVisible="false" PageSize="100" CssClass="mb-3 massdata-grid">
<Columns>
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.Id)" Caption="Id" Width="90px" />
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.CustomerName)" Caption="CustomerName" />
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.Amount)" Caption="Amount" DisplayFormat="c2" />
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.Category)" Caption="Category" />
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.StatusFlag)" Caption="Status" />
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.AddedWhen)" Caption="Added" />
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.ChangedWhen)" Caption="Changed" />
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.Id)" Caption="Id" Width="90px">
<FilterRowCellTemplate Context="filter">
<DxTextBox Text="@(filter.FilterRowValue?.ToString())"
TextChanged="@(value => filter.FilterRowValue = value)"
CssClass="filter-search-input" />
</FilterRowCellTemplate>
</DxGridDataColumn>
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.CustomerName)" Caption="CustomerName">
<FilterRowCellTemplate Context="filter">
<DxTextBox Text="@(filter.FilterRowValue as string)"
TextChanged="@(value => filter.FilterRowValue = value)"
CssClass="filter-search-input" />
</FilterRowCellTemplate>
</DxGridDataColumn>
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.Amount)" Caption="Amount" DisplayFormat="c2">
<FilterRowCellTemplate Context="filter">
<DxTextBox Text="@(filter.FilterRowValue?.ToString())"
TextChanged="@(value => filter.FilterRowValue = value)"
CssClass="filter-search-input" />
</FilterRowCellTemplate>
</DxGridDataColumn>
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.Category)" Caption="Category">
<FilterRowCellTemplate Context="filter">
<DxTextBox Text="@(filter.FilterRowValue as string)"
TextChanged="@(value => filter.FilterRowValue = value)"
CssClass="filter-search-input" />
</FilterRowCellTemplate>
</DxGridDataColumn>
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.StatusFlag)" Caption="Status">
<FilterRowCellTemplate Context="filter">
<DxTextBox Text="@(filter.FilterRowValue?.ToString())"
TextChanged="@(value => filter.FilterRowValue = value)"
CssClass="filter-search-input" />
</FilterRowCellTemplate>
</DxGridDataColumn>
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.AddedWhen)" Caption="Added">
<FilterRowCellTemplate Context="filter">
<DxTextBox Text="@(filter.FilterRowValue?.ToString())"
TextChanged="@(value => filter.FilterRowValue = value)"
CssClass="filter-search-input" />
</FilterRowCellTemplate>
</DxGridDataColumn>
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.ChangedWhen)" Caption="Changed">
<FilterRowCellTemplate Context="filter">
<DxTextBox Text="@(filter.FilterRowValue?.ToString())"
TextChanged="@(value => filter.FilterRowValue = value)"
CssClass="filter-search-input" />
</FilterRowCellTemplate>
</DxGridDataColumn>
<DxGridDataColumn Caption="" Width="220px" AllowSort="false">
<CellDisplayTemplate Context="cell">
@{ var item = (MassDataReadDto)cell.DataItem; }