refactor(ProductCategoriesPage) , refactor(ICrudApiRest)

- NEW VERSION OF PRODUCT CATEGORIES PAGE
- Change products categories page style and ux
- Change icrud api rest and get guid in instead of dto or model
subProduct
Amir Hossein Khademi 2024-06-07 23:03:55 +03:30
parent ea84220cac
commit 55931702a9
8 changed files with 314 additions and 110 deletions

View File

@ -63,12 +63,12 @@
<MudGrid Spacing="0"> <MudGrid Spacing="0">
<MudItem md="3" lg="2"> <MudItem xs="0" md="3" lg="2">
<MudHidden Breakpoint="Breakpoint.SmAndDown"> <MudHidden Breakpoint="Breakpoint.SmAndDown">
<SideBarUi/> <SideBarUi/>
</MudHidden> </MudHidden>
</MudItem> </MudItem>
<MudItem sm="12" md="9" lg="10"> <MudItem xs="12" sm="12" md="9" lg="10">
<div> <div>
@Body @Body

View File

@ -5,24 +5,123 @@
@inject ISnackbar Snackbar @inject ISnackbar Snackbar
@inject IUserUtility UserUtility @inject IUserUtility UserUtility
@* <style>
.mud-input-label {
background-color: var(--mud-palette-background-grey);
}
</style> *@
<MudPaper class="bg-[--mud-palette-background-grey] h-screen w-full p-3 md:p-8">
<MudStack class="w-full p-8 h-screen bg-[--mud-palette-background-grey]"> <MudStack Row="true" class="overflow-x-auto pb-3">
<MudGrid> <MudStack Spacing="1" class="min-w-[340px]">
<MudItem xs="12">
<MudStack Row="true" class="mb-5"> <MudStack Row="true" class="mb-5">
<MudText Typo="Typo.h4">دسته بندی ها</MudText> <MudText Typo="Typo.h6" class="my-auto"><b>دسته های اصلی</b></MudText>
@* <MudChip Color="Color.Info" Variant="Variant.Outlined">124 عدد</MudChip> *@
<MudSpacer /> <MudSpacer />
<MudButton Variant="Variant.Filled" <MudIconButton Icon="@Icons.Material.Filled.Add"
DisableElevation="true" Size="@Size.Small"
StartIcon="@Icons.Material.Outlined.Add" Variant="@Variant.Outlined"
Color="Color.Secondary" OnClick="()=>ViewModel.ChangeOriginalCategoryVisibility()"
OnClick="ViewModel.AddProductCategoryClicked" Color="@Color.Secondary" />
class="my-auto">افزودن دسته بندی</MudButton>
</MudStack> </MudStack>
<MudPaper class="!max-h-[80vh] overflow-auto"> @if (ViewModel.OriginalCategoryVisibility)
{
<MudTextField class="-mt-2 mb-3" T="string" Label="نام دسته بندی" Variant="Variant.Text" Immediate="false" ValueChanged="name => ViewModel.AddFastProductCategory(name)"></MudTextField>
}
@foreach (var item in ViewModel.PageDto)
{
<MudCard class="@(item.IsSelected ? "cursor-pointer border-dashed border-2 border-blue-400 " : "cursor-pointer" )" @onclick="()=>ViewModel.SelectCategory(item)">
<MudCardHeader>
<CardHeaderContent>
<MudText Typo="Typo.body1">@item.Name</MudText>
</CardHeaderContent>
<CardHeaderActions>
<MudStack Row="true" Spacing="1">
<MudIconButton Icon="@Icons.Material.Filled.Edit"
Size="@Size.Small"
class="mt-1"
Variant="@Variant.Outlined"
OnClick="async () => await ViewModel.EditProductCategoryClicked(item)"
Color="@Color.Info" />
<MudIconButton Icon="@Icons.Material.Filled.Delete"
Size="@Size.Small"
class="mt-1"
Variant="@Variant.Outlined"
OnClick="async () => await ViewModel.DeleteProductCategoryAsync(item.Id)"
Color="@Color.Error" />
</MudStack>
</CardHeaderActions>
</MudCardHeader>
</MudCard>
}
</MudStack>
@foreach (var item in ViewModel.SelectedCategories)
{
<MudStack Spacing="1" class="min-w-[340px]">
<MudStack Row="true" class="mb-5">
<MudText Typo="Typo.h6" class="my-auto"><b>@item.Name</b></MudText>
<MudSpacer />
<MudIconButton Icon="@Icons.Material.Filled.Add"
Size="@Size.Small"
Variant="@Variant.Outlined"
OnClick="()=>item.AddNewCatVisibility = !item.AddNewCatVisibility"
Color="@Color.Secondary" />
</MudStack>
@if (item.AddNewCatVisibility)
{
<MudTextField class="-mt-2 mb-3 flex-none" T="string" Label="نام دسته بندی" Variant="Variant.Text" Immediate="false" ValueChanged="name => ViewModel.AddFastProductCategory(name,item.Id)"></MudTextField>
}
@foreach (var child in item.Children)
{
<MudCard class="@(child.IsSelected ? "cursor-pointer border-dashed border-2 border-blue-400 " : "cursor-pointer" )" @onclick="()=>ViewModel.SelectCategory(child)">
<MudCardHeader>
<CardHeaderContent>
<MudText Typo="Typo.body1">@child.Name</MudText>
</CardHeaderContent>
<CardHeaderActions>
<MudStack Row="true" Spacing="1">
<MudIconButton Icon="@Icons.Material.Filled.Edit"
Size="@Size.Small"
class="mt-1"
Variant="@Variant.Outlined"
OnClick="async () => await ViewModel.EditProductCategoryClicked(child)"
Color="@Color.Info" />
<MudIconButton Icon="@Icons.Material.Filled.Delete"
Size="@Size.Small"
class="mt-1"
Variant="@Variant.Outlined"
OnClick="async () => await ViewModel.DeleteProductCategoryAsync(child.Id)"
Color="@Color.Error" />
</MudStack>
</CardHeaderActions>
</MudCardHeader>
</MudCard>
}
</MudStack>
}
</MudStack>
</MudPaper>
@code
{
public CategoriesPageViewModel ViewModel { get; set; }
protected override async Task OnInitializedAsync()
{
ViewModel = new CategoriesPageViewModel(NavigationManager, Snackbar, UserUtility, RestWrapper, DialogService);
await ViewModel.InitializeAsync();
await base.OnInitializedAsync();
}
}
@* <MudPaper class="!max-h-[80vh] overflow-auto">
<MudDataGrid FixedFooter="true" FixedHeader="true" Striped="true" <MudDataGrid FixedFooter="true" FixedHeader="true" Striped="true"
T="ProductCategorySDto" Items="@ViewModel.PageDto" CurrentPage="@ViewModel.CurrentPage" T="ProductCategorySDto" Items="@ViewModel.PageDto" CurrentPage="@ViewModel.CurrentPage"
RowsPerPage="15" Filterable="false" Loading="@ViewModel.IsProcessing" RowsPerPage="15" Filterable="false" Loading="@ViewModel.IsProcessing"
@ -37,11 +136,11 @@
<Columns> <Columns>
<HierarchyColumn T="ProductCategorySDto" ButtonDisabledFunc="@(x => x.Description.IsNullOrEmpty())" /> <HierarchyColumn T="ProductCategorySDto" ButtonDisabledFunc="@(x => x.Description.IsNullOrEmpty())" />
<PropertyColumn Title="نام دسته" Resizable="false" Property="arg => arg.Name"/> <PropertyColumn Title="نام دسته" Resizable="false" Property="arg => arg.Name"/>
@* <TemplateColumn Title="توضیحاتــ" Resizable="false" T="ProductCategorySDto"> <TemplateColumn Title="توضیحاتــ" Resizable="false" T="ProductCategorySDto">
<CellTemplate> <CellTemplate>
<p class="line-clamp-1">@context.Item.Description</p> <p class="line-clamp-1">@context.Item.Description</p>
</CellTemplate> </CellTemplate>
</TemplateColumn> *@ </TemplateColumn>
<TemplateColumn Resizable="false" Title="دسته اصلی" T="ProductCategorySDto"> <TemplateColumn Resizable="false" Title="دسته اصلی" T="ProductCategorySDto">
<CellTemplate> <CellTemplate>
@if (@context.Item.IsMain) @if (@context.Item.IsMain)
@ -91,24 +190,9 @@
<MudStack Row="true" class="w-full"> <MudStack Row="true" class="w-full">
<MudPagination Rectangular="true" Variant="Variant.Filled" Count="@ViewModel.PageCount" <MudPagination Rectangular="true" Variant="Variant.Filled" Count="@ViewModel.PageCount"
SelectedChanged="@ViewModel.ChangePageAsync" class="my-4 mx-auto"/> SelectedChanged="@ViewModel.ChangePageAsync" class="mx-auto my-4"/>
</MudStack> </MudStack>
</PagerContent> </PagerContent>
</MudDataGrid> </MudDataGrid>
</MudPaper> </MudPaper> *@
</MudItem>
</MudGrid>
</MudStack>
@code
{
public CategoriesPageViewModel ViewModel { get; set; }
protected override async Task OnInitializedAsync()
{
ViewModel = new CategoriesPageViewModel(NavigationManager, Snackbar, UserUtility, RestWrapper, DialogService);
await ViewModel.InitializeAsync();
await base.OnInitializedAsync();
}
}

View File

@ -9,8 +9,6 @@ public class CategoriesPageViewModel : BaseViewModel<ObservableCollection<Produc
private readonly IRestWrapper _restWrapper; private readonly IRestWrapper _restWrapper;
public string Search = string.Empty; public string Search = string.Empty;
public int CurrentPage = 0;
public int PageCount = 1;
public CategoriesPageViewModel(NavigationManager navigationManager, ISnackbar snackbar, IUserUtility userUtility, IRestWrapper restWrapper, IDialogService dialogService) : base(userUtility) public CategoriesPageViewModel(NavigationManager navigationManager, ISnackbar snackbar, IUserUtility userUtility, IRestWrapper restWrapper, IDialogService dialogService) : base(userUtility)
{ {
@ -26,13 +24,10 @@ public class CategoriesPageViewModel : BaseViewModel<ObservableCollection<Produc
try try
{ {
IsProcessing = true; IsProcessing = true;
CurrentPage = 0;
PageDto.Clear(); PageDto.Clear();
var dto = await _restWrapper.CrudDtoApiRest<ProductCategory, ProductCategorySDto, Guid>(Address.ProductCategoryController) var dto = await _restWrapper.ProductCategoryRestApi.ReadAll(true);
.ReadAll(CurrentPage);
dto.ForEach(d => PageDto.Add(d)); dto.ForEach(d => PageDto.Add(d));
if (PageDto.Count == 15)
PageCount = 2;
} }
catch (ApiException ex) catch (ApiException ex)
{ {
@ -51,38 +46,6 @@ public class CategoriesPageViewModel : BaseViewModel<ObservableCollection<Produc
await base.InitializeAsync(); await base.InitializeAsync();
} }
public async Task ChangePageAsync(int page)
{
CurrentPage = page-1;
if (CurrentPage > PageCount-2)
{
try
{
IsProcessing = true;
var dto = await _restWrapper.CrudDtoApiRest<ProductCategory, ProductCategorySDto, Guid>(Address.ProductCategoryController)
.ReadAll(CurrentPage);
dto.ForEach(d => PageDto.Add(d));
if(PageDto.Count % 15==0)
PageCount = CurrentPage + 2;
}
catch (ApiException ex)
{
var exe = await ex.GetContentAsAsync<ApiResult>();
_snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
}
catch (Exception e)
{
_snackbar.Add(e.Message, Severity.Error);
}
finally
{
IsProcessing = false;
}
}
}
public async Task AddProductCategoryClicked() public async Task AddProductCategoryClicked()
{ {
@ -150,13 +113,9 @@ public class CategoriesPageViewModel : BaseViewModel<ObservableCollection<Produc
if (Search.IsNullOrEmpty()) if (Search.IsNullOrEmpty())
throw new AppException("دسته بندی برای جست جو وارد نشده است"); throw new AppException("دسته بندی برای جست جو وارد نشده است");
IsProcessing = true; IsProcessing = true;
CurrentPage = 0;
PageCount = 1;
PageDto.Clear(); PageDto.Clear();
var dto = await _restWrapper.ProductCategoryRestApi.ReadAll(Search); var dto = await _restWrapper.ProductCategoryRestApi.ReadAll(Search);
dto.ForEach(d => PageDto.Add(d)); dto.ForEach(d => PageDto.Add(d));
if (PageDto.Count == 15)
PageCount = 2;
} }
catch (ApiException ex) catch (ApiException ex)
{ {
@ -173,4 +132,90 @@ public class CategoriesPageViewModel : BaseViewModel<ObservableCollection<Produc
IsProcessing = false; IsProcessing = false;
} }
} }
public List<ProductCategorySDto> SelectedCategories = new();
public void SelectCategory(ProductCategorySDto category)
{
var selected = SelectedCategories.FirstOrDefault(c => c.Id == category.Id);
if (selected != null)
{
UnSelectCategory(selected);
return;
}
var parent = FindParent(category.ParentId, PageDto.ToList());
if (parent != null)
category.Index = parent.Index + 1;
category.IsSelected = true;
var currentSelectedIndex = SelectedCategories.FirstOrDefault(c => c.Index == category.Index);
if (currentSelectedIndex != null)
UnSelectCategory(currentSelectedIndex);
SelectedCategories.Add(category);
}
public bool OriginalCategoryVisibility = false;
public bool ChangeOriginalCategoryVisibility() => OriginalCategoryVisibility = !OriginalCategoryVisibility;
public void AddFastProductCategory(string categoryName, Guid? parentId = null)
{
if(categoryName.IsNullOrEmpty())
return;
ProductCategorySDto category = new ProductCategorySDto { Name = categoryName, IsMain = true};
if (parentId != null)
{
category.IsMain = false;
category.ParentId = parentId.Value;
}
var command = category.Adapt<CreateProductCategoryCommand>() with{Files = new()};
Task.Run(async () =>
{
var token = await _userUtility.GetBearerTokenAsync();
if (token == null)
return;
var response = await _restWrapper.CrudApiRest<ProductCategory, Guid>(Address.ProductCategoryController)
.Create(command, token);
category.Id = response;
});
if (parentId == null)
{
category.IsMain = true;
PageDto.Add(category);
}
else
{
var parent = FindParent(parentId.Value, PageDto.ToList());
if (parent != null)
{
category.Index = parent.Index + 1;
parent.Children.Add(category);
}
}
categoryName = string.Empty;
}
private void UnSelectCategory(ProductCategorySDto category)
{
category.IsSelected = false;
foreach (var selected in SelectedCategories.Where(c => c.ParentId == category.Id).ToList())
UnSelectCategory(selected);
SelectedCategories.Remove(category);
}
private ProductCategorySDto? FindParent(Guid parentId, List<ProductCategorySDto> categories)
{
var parent = categories.FirstOrDefault(c => c.Id == parentId);
if (parent != null)
return parent;
foreach (var category in categories)
{
var founded = FindParent(parentId, category.Children);
if (founded != null)
return founded;
}
return null;
}
} }

View File

@ -1,9 +1,9 @@
namespace Netina.AdminPanel.PWA.Services.RestServices; namespace Netina.AdminPanel.PWA.Services.RestServices;
public interface ICrudApiRest<T, in TKey> where T : class public interface ICrudApiRest<T, TKey> where T : class
{ {
[Post("")] [Post("")]
Task Create<TCreateCommand>([Body] TCreateCommand payload, [Header("Authorization")] string authorization); Task<TKey> Create<TCreateCommand>([Body] TCreateCommand payload, [Header("Authorization")] string authorization);
[Get("")] [Get("")]
Task<List<T>> ReadAll([Query] int page,[Header("Authorization")] string authorization); Task<List<T>> ReadAll([Query] int page,[Header("Authorization")] string authorization);

View File

@ -8,6 +8,8 @@ public interface IProductCategoryRestApi
[Get("")] [Get("")]
Task<List<ProductCategorySDto>> ReadAll([Query] int page); Task<List<ProductCategorySDto>> ReadAll([Query] int page);
[Get("")] [Get("")]
Task<List<ProductCategorySDto>> ReadAll([Query] bool sortByMain);
[Get("")]
Task<List<ProductCategorySDto>> ReadAll([Query] int page,[Query]string categoryName); Task<List<ProductCategorySDto>> ReadAll([Query] int page,[Query]string categoryName);
[Get("")] [Get("")]
Task<List<ProductCategorySDto>> ReadAll([Query] string categoryName); Task<List<ProductCategorySDto>> ReadAll([Query] string categoryName);

View File

@ -8,6 +8,14 @@ module.exports = {
"./node_modules/flowbite/**/*.js" "./node_modules/flowbite/**/*.js"
], ],
theme: { theme: {
screens: {
'xs': '380px',
'sm': '600px',
'md': '960px',
'lg': '1280px',
'xl': '1920px',
'2xl': '2560px',
},
fontSize: { fontSize: {
xs: '.75rem', xs: '.75rem',
sm: '.875rem', sm: '.875rem',

View File

@ -977,22 +977,22 @@ input:checked + .toggle-bg {
.container { .container {
width: 100%; width: 100%;
} }
@media (min-width: 640px) { @media (min-width: 380px) {
.container { .container {
max-width: 640px; max-width: 380px;
} }
} }
@media (min-width: 768px) { @media (min-width: 600px) {
.container { .container {
max-width: 768px; max-width: 600px;
} }
} }
@media (min-width: 1024px) { @media (min-width: 960px) {
.container { .container {
max-width: 1024px; max-width: 960px;
} }
} }
@media (min-width: 1280px) { @media (min-width: 1280px) {
@ -1001,10 +1001,16 @@ input:checked + .toggle-bg {
max-width: 1280px; max-width: 1280px;
} }
} }
@media (min-width: 1536px) { @media (min-width: 1920px) {
.container { .container {
max-width: 1536px; max-width: 1920px;
}
}
@media (min-width: 2560px) {
.container {
max-width: 2560px;
} }
} }
.visible { .visible {
@ -1150,6 +1156,9 @@ input:checked + .toggle-bg {
.-mt-1 { .-mt-1 {
margin-top: -0.25rem; margin-top: -0.25rem;
} }
.-mt-2 {
margin-top: -0.5rem;
}
.-mt-3 { .-mt-3 {
margin-top: -0.75rem; margin-top: -0.75rem;
} }
@ -1353,6 +1362,9 @@ input:checked + .toggle-bg {
.w-screen { .w-screen {
width: 100vw; width: 100vw;
} }
.min-w-\[340px\] {
min-width: 340px;
}
.flex-1 { .flex-1 {
flex: 1 1 0%; flex: 1 1 0%;
} }
@ -1466,6 +1478,9 @@ input:checked + .toggle-bg {
.overflow-hidden { .overflow-hidden {
overflow: hidden; overflow: hidden;
} }
.overflow-x-auto {
overflow-x: auto;
}
.overflow-x-hidden { .overflow-x-hidden {
overflow-x: hidden; overflow-x: hidden;
} }
@ -1565,6 +1580,10 @@ input:checked + .toggle-bg {
--tw-border-opacity: 1; --tw-border-opacity: 1;
border-color: rgb(167 139 250 / var(--tw-border-opacity)); border-color: rgb(167 139 250 / var(--tw-border-opacity));
} }
.border-yellow-400 {
--tw-border-opacity: 1;
border-color: rgb(227 160 8 / var(--tw-border-opacity));
}
.bg-\[\#000000\] { .bg-\[\#000000\] {
--tw-bg-opacity: 1; --tw-bg-opacity: 1;
background-color: rgb(0 0 0 / var(--tw-bg-opacity)); background-color: rgb(0 0 0 / var(--tw-bg-opacity));
@ -1704,6 +1723,9 @@ input:checked + .toggle-bg {
padding-top: 2rem; padding-top: 2rem;
padding-bottom: 2rem; padding-bottom: 2rem;
} }
.pb-3 {
padding-bottom: 0.75rem;
}
.pt-2 { .pt-2 {
padding-top: 0.5rem; padding-top: 0.5rem;
} }
@ -2218,7 +2240,7 @@ code {
color: rgb(255 255 255 / var(--tw-text-opacity)); color: rgb(255 255 255 / var(--tw-text-opacity));
} }
@media (min-width: 640px) { @media (min-width: 600px) {
.sm\:mr-3 { .sm\:mr-3 {
margin-right: 0.75rem; margin-right: 0.75rem;
@ -2238,7 +2260,7 @@ code {
} }
} }
@media (min-width: 768px) { @media (min-width: 960px) {
.md\:visible { .md\:visible {
visibility: visible; visibility: visible;
@ -2277,13 +2299,17 @@ code {
padding: 1.25rem; padding: 1.25rem;
} }
.md\:p-8 {
padding: 2rem;
}
.md\:px-10 { .md\:px-10 {
padding-left: 2.5rem; padding-left: 2.5rem;
padding-right: 2.5rem; padding-right: 2.5rem;
} }
} }
@media (min-width: 1024px) { @media (min-width: 1280px) {
.lg\:h-60 { .lg\:h-60 {
height: 15rem; height: 15rem;

View File

@ -1031,21 +1031,21 @@ input:checked + .toggle-bg {
width: 100%; width: 100%;
} }
@media (min-width: 640px) { @media (min-width: 380px) {
.container { .container {
max-width: 640px; max-width: 380px;
} }
} }
@media (min-width: 768px) { @media (min-width: 600px) {
.container { .container {
max-width: 768px; max-width: 600px;
} }
} }
@media (min-width: 1024px) { @media (min-width: 960px) {
.container { .container {
max-width: 1024px; max-width: 960px;
} }
} }
@ -1055,9 +1055,15 @@ input:checked + .toggle-bg {
} }
} }
@media (min-width: 1536px) { @media (min-width: 1920px) {
.container { .container {
max-width: 1536px; max-width: 1920px;
}
}
@media (min-width: 2560px) {
.container {
max-width: 2560px;
} }
} }
@ -1247,6 +1253,10 @@ input:checked + .toggle-bg {
margin-top: -0.25rem; margin-top: -0.25rem;
} }
.-mt-2 {
margin-top: -0.5rem;
}
.-mt-3 { .-mt-3 {
margin-top: -0.75rem; margin-top: -0.75rem;
} }
@ -1451,6 +1461,14 @@ input:checked + .toggle-bg {
min-height: 33rem; min-height: 33rem;
} }
.min-h-full {
min-height: 100%;
}
.\!min-h-full {
min-height: 100% !important;
}
.w-1\/2 { .w-1\/2 {
width: 50%; width: 50%;
} }
@ -1516,6 +1534,10 @@ input:checked + .toggle-bg {
width: 100vw; width: 100vw;
} }
.min-w-\[340px\] {
min-width: 340px;
}
.flex-1 { .flex-1 {
flex: 1 1 0%; flex: 1 1 0%;
} }
@ -1662,6 +1684,10 @@ input:checked + .toggle-bg {
overflow: hidden; overflow: hidden;
} }
.overflow-x-auto {
overflow-x: auto;
}
.overflow-x-hidden { .overflow-x-hidden {
overflow-x: hidden; overflow-x: hidden;
} }
@ -1790,6 +1816,11 @@ input:checked + .toggle-bg {
border-color: rgb(167 139 250 / var(--tw-border-opacity)); border-color: rgb(167 139 250 / var(--tw-border-opacity));
} }
.border-yellow-400 {
--tw-border-opacity: 1;
border-color: rgb(227 160 8 / var(--tw-border-opacity));
}
.bg-\[\#000000\] { .bg-\[\#000000\] {
--tw-bg-opacity: 1; --tw-bg-opacity: 1;
background-color: rgb(0 0 0 / var(--tw-bg-opacity)); background-color: rgb(0 0 0 / var(--tw-bg-opacity));
@ -1979,6 +2010,10 @@ input:checked + .toggle-bg {
padding-top: 2rem; padding-top: 2rem;
} }
.pb-3 {
padding-bottom: 0.75rem;
}
.text-center { .text-center {
text-align: center; text-align: center;
} }
@ -2557,7 +2592,7 @@ code {
color: rgb(255 255 255 / var(--tw-text-opacity)); color: rgb(255 255 255 / var(--tw-text-opacity));
} }
@media (min-width: 640px) { @media (min-width: 600px) {
.sm\:mr-3 { .sm\:mr-3 {
margin-right: 0.75rem; margin-right: 0.75rem;
} }
@ -2576,7 +2611,7 @@ code {
} }
} }
@media (min-width: 768px) { @media (min-width: 960px) {
.md\:visible { .md\:visible {
visibility: visible; visibility: visible;
} }
@ -2614,13 +2649,17 @@ code {
padding: 1.25rem; padding: 1.25rem;
} }
.md\:p-8 {
padding: 2rem;
}
.md\:px-10 { .md\:px-10 {
padding-left: 2.5rem; padding-left: 2.5rem;
padding-right: 2.5rem; padding-right: 2.5rem;
} }
} }
@media (min-width: 1024px) { @media (min-width: 1280px) {
.lg\:h-60 { .lg\:h-60 {
height: 15rem; height: 15rem;
} }