mirror of
https://github.com/booklore-app/booklore.git
synced 2025-12-23 22:28:11 -05:00
Improve the UI of the shelf edit dialog
This commit is contained in:
@@ -1,25 +1,66 @@
|
||||
<div class="flex flex-col py-4 px-4 gap-6 h-96 w-96">
|
||||
<div class="flex flex-col gap-10">
|
||||
<div class="flex items-center gap-4">
|
||||
<p>Shelf Name: </p>
|
||||
<input type="text" pInputText [(ngModel)]="shelfName" placeholder="Enter shelf name..."/>
|
||||
<div class="shelf-form">
|
||||
<div class="panel-header">
|
||||
<div class="header-icon-wrapper">
|
||||
<i class="pi pi-pencil header-icon"></i>
|
||||
</div>
|
||||
<div class="flex items-center gap-5">
|
||||
<p>Shelf Icon:</p>
|
||||
@if (!selectedIcon) {
|
||||
<div>
|
||||
<p-button label="Select Icon" icon="pi pi-search" (onClick)="openIconPicker()"></p-button>
|
||||
<div class="header-text">
|
||||
<h2 class="panel-title">Edit Shelf</h2>
|
||||
<p class="panel-description">
|
||||
Customize your shelf name and icon
|
||||
</p>
|
||||
</div>
|
||||
<p-button
|
||||
icon="pi pi-times"
|
||||
[text]="true"
|
||||
[rounded]="true"
|
||||
severity="secondary"
|
||||
(onClick)="closeDialog()"
|
||||
styleClass="close-button">
|
||||
</p-button>
|
||||
</div>
|
||||
|
||||
<div class="shelf-container">
|
||||
<div class="shelf-fields">
|
||||
<div class="shelf-row">
|
||||
<label class="label">Shelf Name:</label>
|
||||
<input type="text" pInputText [(ngModel)]="shelfName" placeholder="Enter shelf name..." class="input"/>
|
||||
</div>
|
||||
|
||||
<div class="shelf-row">
|
||||
<label class="label">Shelf Icon:</label>
|
||||
<div class="icon-section">
|
||||
@if (!selectedIcon) {
|
||||
<p-button label="Select Icon" icon="pi pi-search" [outlined]="true" severity="info" (onClick)="openIconPicker()"></p-button>
|
||||
}
|
||||
|
||||
@if (selectedIcon) {
|
||||
<div class="icon-container">
|
||||
<div class="icon-wrapper">
|
||||
<i [class]="selectedIcon" class="icon"></i>
|
||||
</div>
|
||||
<p-button icon="pi pi-times" (onClick)="clearSelectedIcon()" [rounded]="true" [text]="true" severity="danger"></p-button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
@if (selectedIcon) {
|
||||
<div>
|
||||
<i [class]="selectedIcon" class="text-xl mr-3"></i>
|
||||
<p-button icon="pi pi-times" (onClick)="clearSelectedIcon()" [rounded]="true" [text]="true" [outlined]="true" severity="danger"></p-button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-end">
|
||||
<p-button label="Save" icon="pi pi-check" (onClick)="save()"></p-button>
|
||||
|
||||
<div class="dialog-footer">
|
||||
<div></div>
|
||||
<div class="footer-actions">
|
||||
<p-button
|
||||
label="Cancel"
|
||||
severity="secondary"
|
||||
[outlined]="true"
|
||||
(onClick)="closeDialog()"
|
||||
/>
|
||||
<p-button
|
||||
label="Save Changes"
|
||||
icon="pi pi-check"
|
||||
severity="success"
|
||||
(onClick)="save()"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
.shelf-form {
|
||||
width: 550px;
|
||||
max-width: 550px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@media (max-width: 640px) {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.panel-header {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
padding: 1.5rem 1.5rem 1.25rem 1.5rem;
|
||||
border-radius: 10px 10px 0 0;
|
||||
border: 1px solid var(--border-color);
|
||||
border-bottom: none;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);
|
||||
|
||||
.header-icon-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
background: var(--primary-color);
|
||||
border-radius: 10px;
|
||||
|
||||
.header-icon {
|
||||
font-size: 1.5rem;
|
||||
color: var(--primary-contrast-color);
|
||||
}
|
||||
}
|
||||
|
||||
.header-text {
|
||||
flex: 1;
|
||||
|
||||
.panel-title {
|
||||
margin: 0 0 0.25rem 0;
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.panel-description {
|
||||
margin: 0;
|
||||
font-size: 0.875rem;
|
||||
color: var(--text-secondary-color);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
padding: 1rem 3rem 1rem 1rem;
|
||||
|
||||
.header-icon-wrapper {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
|
||||
.header-icon {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
.header-text {
|
||||
.panel-title {
|
||||
font-size: 1.125rem;
|
||||
}
|
||||
|
||||
.panel-description {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
}
|
||||
|
||||
::ng-deep .close-button {
|
||||
top: 0.5rem;
|
||||
right: 0.5rem;
|
||||
|
||||
.p-button {
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.shelf-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
padding: 1.75rem;
|
||||
background: var(--card-background);
|
||||
border: 1px solid var(--border-color);
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);
|
||||
min-height: 200px;
|
||||
|
||||
@media (max-width: 480px) {
|
||||
padding: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.shelf-fields {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.shelf-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
|
||||
@media (max-width: 480px) {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.label {
|
||||
width: 7rem;
|
||||
font-weight: 600;
|
||||
font-size: 0.9375rem;
|
||||
color: var(--text-color);
|
||||
margin: 0;
|
||||
|
||||
@media (max-width: 480px) {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.input {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.icon-section {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@media (max-width: 480px) {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.icon-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding: 0.5rem 0.75rem;
|
||||
background: var(--ground-background);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 8px;
|
||||
|
||||
.icon-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
background: var(--primary-color);
|
||||
border-radius: 8px;
|
||||
|
||||
.icon {
|
||||
font-size: 1.25rem;
|
||||
color: var(--primary-contrast-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding: 1.25rem 1.5rem;
|
||||
background: var(--card-background);
|
||||
border: 1px solid var(--border-color);
|
||||
border-top: none;
|
||||
border-radius: 0 0 10px 10px;
|
||||
box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.06);
|
||||
|
||||
.footer-actions {
|
||||
display: flex;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
flex-direction: column;
|
||||
padding: 1rem;
|
||||
gap: 0.5rem;
|
||||
|
||||
.footer-actions {
|
||||
width: 100%;
|
||||
justify-content: flex-end;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,12 +16,12 @@ import {IconPickerService} from '../../../../shared/service/icon-picker.service'
|
||||
InputText,
|
||||
ReactiveFormsModule,
|
||||
FormsModule
|
||||
],
|
||||
],
|
||||
templateUrl: './shelf-edit-dialog.component.html',
|
||||
standalone: true,
|
||||
styleUrl: './shelf-edit-dialog.component.scss'
|
||||
})
|
||||
export class ShelfEditDialogComponent implements OnInit{
|
||||
export class ShelfEditDialogComponent implements OnInit {
|
||||
|
||||
private shelfService = inject(ShelfService);
|
||||
private dynamicDialogConfig = inject(DynamicDialogConfig);
|
||||
@@ -36,7 +36,7 @@ export class ShelfEditDialogComponent implements OnInit{
|
||||
ngOnInit(): void {
|
||||
const shelfId = this.dynamicDialogConfig?.data.shelfId;
|
||||
this.shelf = this.shelfService.getShelfById(shelfId);
|
||||
if(this.shelf) {
|
||||
if (this.shelf) {
|
||||
this.shelfName = this.shelf.name;
|
||||
this.selectedIcon = 'pi pi-' + this.shelf.icon;
|
||||
}
|
||||
@@ -71,4 +71,8 @@ export class ShelfEditDialogComponent implements OnInit{
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
closeDialog() {
|
||||
this.dynamicDialogRef.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ export class LibraryShelfMenuService {
|
||||
header: 'Edit Library',
|
||||
modal: true,
|
||||
closable: true,
|
||||
showHeader: false,
|
||||
styleClass: 'dynamic-dialog-minimal',
|
||||
data: {
|
||||
mode: 'edit',
|
||||
@@ -164,13 +165,11 @@ export class LibraryShelfMenuService {
|
||||
header: 'Edit Shelf',
|
||||
modal: true,
|
||||
closable: true,
|
||||
showHeader: false,
|
||||
styleClass: 'dynamic-dialog-minimal',
|
||||
data: {
|
||||
shelfId: entity?.id
|
||||
},
|
||||
style: {
|
||||
position: 'absolute',
|
||||
top: '15%',
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
@@ -228,8 +227,11 @@ export class LibraryShelfMenuService {
|
||||
header: 'Edit Magic Shelf',
|
||||
modal: true,
|
||||
closable: true,
|
||||
showHeader: false,
|
||||
styleClass: 'dynamic-dialog-minimal',
|
||||
data: {
|
||||
id: entity?.id
|
||||
id: entity?.id,
|
||||
editMode: true,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
<i class="pi pi-book"></i>
|
||||
</div>
|
||||
<div class="main-header-content">
|
||||
<h1 class="main-header-title">Library Creator</h1>
|
||||
<h1 class="main-header-title">
|
||||
{{ mode === 'edit' ? 'Edit Library' : 'Create New Library' }}
|
||||
</h1>
|
||||
<p class="main-header-subtitle">Set up a new library to organize and manage your book collection</p>
|
||||
</div>
|
||||
<p-button
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
<i class="pi pi-sparkles header-icon"></i>
|
||||
</div>
|
||||
<div class="header-text">
|
||||
<h2 class="panel-title">Magic Shelf Builder</h2>
|
||||
<h2 class="panel-title">
|
||||
{{ editMode ? 'Edit Magic Shelf' : 'Magic Shelf Builder' }}
|
||||
</h2>
|
||||
<p class="panel-description">Create smart shelves with custom rules to automatically organize your books</p>
|
||||
</div>
|
||||
<p-button
|
||||
|
||||
@@ -200,6 +200,7 @@ export class MagicShelfComponent implements OnInit {
|
||||
|
||||
shelfId: number | null = null;
|
||||
isAdmin: boolean = false;
|
||||
editMode!: boolean;
|
||||
|
||||
libraryService = inject(LibraryService);
|
||||
magicShelfService = inject(MagicShelfService);
|
||||
@@ -216,6 +217,7 @@ export class MagicShelfComponent implements OnInit {
|
||||
ngOnInit(): void {
|
||||
this.isAdmin = this.userService.getCurrentUser()?.permissions.admin ?? false;
|
||||
const id = this.config?.data?.id;
|
||||
this.editMode = !!this.config?.data?.editMode;
|
||||
|
||||
if (id) {
|
||||
this.shelfId = id;
|
||||
|
||||
Reference in New Issue
Block a user