mirror of
https://github.com/booklore-app/booklore.git
synced 2025-12-23 22:28:11 -05:00
More UI tweaks (#1740)
This commit is contained in:
@@ -20,6 +20,7 @@ export class BookDialogHelperService {
|
||||
modal: true,
|
||||
closable: true,
|
||||
contentStyle: {overflow: 'auto'},
|
||||
styleClass: 'dynamic-dialog-minimal',
|
||||
baseZIndex: 10,
|
||||
style: {
|
||||
position: 'absolute',
|
||||
@@ -40,6 +41,7 @@ export class BookDialogHelperService {
|
||||
dismissableMask: true,
|
||||
closable: true,
|
||||
contentStyle: {overflow: 'auto'},
|
||||
styleClass: 'dynamic-dialog-minimal',
|
||||
baseZIndex: 10,
|
||||
style: {
|
||||
position: 'absolute',
|
||||
|
||||
@@ -467,6 +467,7 @@ export class BookCardComponent implements OnInit, OnChanges, OnDestroy {
|
||||
dismissableMask: true,
|
||||
closable: true,
|
||||
contentStyle: {overflow: 'auto'},
|
||||
styleClass: 'dynamic-dialog-minimal',
|
||||
baseZIndex: 10,
|
||||
style: {
|
||||
position: 'absolute',
|
||||
|
||||
@@ -77,6 +77,7 @@
|
||||
label="Create Shelf"
|
||||
icon="pi pi-plus"
|
||||
[outlined]="true"
|
||||
severity="info"
|
||||
(onClick)="createShelfDialog()"
|
||||
/>
|
||||
<div class="footer-actions">
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
max-width: 550px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-top: 20px;
|
||||
|
||||
@media (max-width: 640px) {
|
||||
width: 100%;
|
||||
@@ -16,8 +15,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
padding: 1.25rem 3.5rem 1.25rem 1.25rem;
|
||||
|
||||
padding: 1.5rem 1.5rem 1.25rem 1.5rem;
|
||||
border-radius: 10px 10px 0 0;
|
||||
border: 1px solid var(--border-color);
|
||||
border-bottom: none;
|
||||
@@ -94,7 +92,7 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
padding: 1.5rem;
|
||||
padding: 1.75rem;
|
||||
background: var(--card-background);
|
||||
border: 1px solid var(--border-color);
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);
|
||||
@@ -342,7 +340,7 @@
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding: 1rem 1.5rem;
|
||||
padding: 1.25rem 1.5rem;
|
||||
background: var(--card-background);
|
||||
border: 1px solid var(--border-color);
|
||||
border-top: none;
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="divider"></div>
|
||||
<div class="gradient-divider"></div>
|
||||
|
||||
<div class="form-group highlight-group">
|
||||
<label class="form-label">
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 600px;
|
||||
padding-top: 20px;
|
||||
|
||||
@media (max-width: 640px) {
|
||||
min-width: auto;
|
||||
@@ -15,7 +14,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
padding: 1.25rem;
|
||||
padding: 1.5rem 1.5rem 1.25rem 1.5rem;
|
||||
border-radius: 10px 10px 0 0;
|
||||
border: 1px solid var(--border-color);
|
||||
|
||||
@@ -300,18 +299,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
.divider {
|
||||
height: 1px;
|
||||
background: linear-gradient(90deg, transparent, var(--border-color), transparent);
|
||||
margin: 0.25rem 0;
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
padding: 1rem 1.5rem;
|
||||
padding: 1.25rem 1.5rem;
|
||||
background: var(--card-background);
|
||||
border: 1px solid var(--border-color);
|
||||
border-top: none;
|
||||
|
||||
@@ -45,6 +45,7 @@ export class LibraryShelfMenuService {
|
||||
header: 'Edit Library',
|
||||
modal: true,
|
||||
closable: true,
|
||||
styleClass: 'dynamic-dialog-minimal',
|
||||
data: {
|
||||
mode: 'edit',
|
||||
libraryId: entity?.id
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="divider"></div>
|
||||
<div class="gradient-divider"></div>
|
||||
|
||||
<div class="form-group highlight-group">
|
||||
<label class="form-label">
|
||||
@@ -113,7 +113,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="divider"></div>
|
||||
<div class="gradient-divider"></div>
|
||||
|
||||
<div class="form-section">
|
||||
<div class="form-group">
|
||||
@@ -170,7 +170,7 @@
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="divider"></div>
|
||||
<div class="gradient-divider"></div>
|
||||
|
||||
<div class="form-section">
|
||||
<div class="form-group">
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);
|
||||
margin-top: 20px;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
width: 100%;
|
||||
@@ -29,7 +28,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
padding: 1.25rem;
|
||||
padding: 1.75rem 1.75rem 1.25rem 1.75rem;
|
||||
background: var(--overlay-background);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
border-radius: 10px 10px 0 0;
|
||||
@@ -254,7 +253,7 @@
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 1rem 1.5rem;
|
||||
padding: 1rem 2rem;
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
|
||||
|
||||
@@ -83,6 +83,7 @@ export class LibraryCreatorComponent implements OnInit {
|
||||
showHeader: false,
|
||||
modal: true,
|
||||
closable: true,
|
||||
styleClass: 'dynamic-dialog-minimal',
|
||||
contentStyle: {overflow: 'hidden'},
|
||||
baseZIndex: 10
|
||||
});
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
max-width: 75rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-top: 20px;
|
||||
|
||||
@media (max-width: 1280px) {
|
||||
width: 100%;
|
||||
@@ -16,8 +15,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
padding: 1.25rem;
|
||||
|
||||
padding: 1.5rem 1.5rem 1.25rem 1.5rem;
|
||||
border-radius: 10px 10px 0 0;
|
||||
border: 1px solid var(--border-color);
|
||||
border-bottom: none;
|
||||
@@ -97,7 +95,7 @@
|
||||
}
|
||||
|
||||
.magic-shelf-content {
|
||||
padding: 1.5rem;
|
||||
padding: 2rem;
|
||||
background: var(--card-background);
|
||||
border: 1px solid var(--border-color);
|
||||
border-bottom: none;
|
||||
@@ -221,7 +219,7 @@
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding: 1rem 1.5rem;
|
||||
padding: 1.25rem 1.5rem;
|
||||
background: var(--card-background);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 0 0 10px 10px;
|
||||
|
||||
@@ -112,7 +112,7 @@
|
||||
</div>
|
||||
|
||||
@if (book?.metadata?.amazonRating || book?.metadata?.goodreadsRating || book?.metadata?.hardcoverRating || book?.metadata?.googleId) {
|
||||
<div class="divider"></div>
|
||||
<div class="gradient-divider"></div>
|
||||
}
|
||||
|
||||
<div class="external-ratings">
|
||||
|
||||
@@ -1,63 +1,203 @@
|
||||
<form [formGroup]="emailProviderForm" (ngSubmit)="createEmailProvider()" class="space-y-6 p-6">
|
||||
|
||||
<div class="flex items-center gap-4">
|
||||
<label class="w-40 text-right font-medium">Provider Name:</label>
|
||||
<input type="text" pInputText formControlName="name" placeholder="Enter provider name..." class="w-full md:w-80"/>
|
||||
</div>
|
||||
@if (emailProviderForm.get('name')?.invalid && (emailProviderForm.get('name')?.dirty || emailProviderForm.get('name')?.touched)) {
|
||||
<small class="text-red-500 pl-44">
|
||||
Provider name is required.
|
||||
</small>
|
||||
}
|
||||
|
||||
<div class="flex items-center gap-4">
|
||||
<label class="w-40 text-right font-medium">Host:</label>
|
||||
<input type="text" pInputText formControlName="host" placeholder="Enter host..." class="w-full md:w-80"/>
|
||||
</div>
|
||||
@if (emailProviderForm.get('host')?.invalid && (emailProviderForm.get('host')?.dirty || emailProviderForm.get('host')?.touched)) {
|
||||
<small class="text-red-500 pl-44">
|
||||
Host is required.
|
||||
</small>
|
||||
}
|
||||
|
||||
<div class="flex items-center gap-4">
|
||||
<label class="w-40 text-right font-medium">Port:</label>
|
||||
<input type="number" pInputText formControlName="port" placeholder="Enter port..." class="w-full md:w-80"/>
|
||||
</div>
|
||||
@if (emailProviderForm.get('port')?.invalid && (emailProviderForm.get('port')?.dirty || emailProviderForm.get('port')?.touched)) {
|
||||
<small class="text-red-500 pl-44">
|
||||
Port is required and must be a number.
|
||||
</small>
|
||||
}
|
||||
|
||||
<div class="flex items-center gap-4">
|
||||
<label class="w-40 text-right font-medium">Username:</label>
|
||||
<input type="text" pInputText formControlName="username" placeholder="Enter username..." class="w-full md:w-80"/>
|
||||
<div class="email-provider-creator">
|
||||
<div class="panel-header">
|
||||
<div class="header-icon-wrapper">
|
||||
<i class="pi pi-envelope header-icon"></i>
|
||||
</div>
|
||||
<div class="header-text">
|
||||
<h2 class="panel-title">Create Email Provider</h2>
|
||||
<p class="panel-description">Configure a new email provider for sending notifications</p>
|
||||
</div>
|
||||
<p-button
|
||||
icon="pi pi-times"
|
||||
(click)="closeDialog()"
|
||||
severity="secondary"
|
||||
[text]="true"
|
||||
[rounded]="true"
|
||||
class="close-button"
|
||||
pTooltip="Close"
|
||||
tooltipPosition="left"/>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-4">
|
||||
<label class="w-40 text-right font-medium">Password:</label>
|
||||
<input type="password" pInputText formControlName="password" placeholder="Enter password..." class="w-full md:w-80"/>
|
||||
</div>
|
||||
<form [formGroup]="emailProviderForm" (ngSubmit)="createEmailProvider()">
|
||||
<div class="form-container">
|
||||
<div class="form-group highlight-group">
|
||||
<label for="providerName" class="form-label">
|
||||
<i class="pi pi-tag label-icon"></i>
|
||||
Provider Name
|
||||
<span class="required-indicator">*</span>
|
||||
</label>
|
||||
<div class="input-wrapper">
|
||||
<input
|
||||
id="providerName"
|
||||
type="text"
|
||||
pInputText
|
||||
formControlName="name"
|
||||
class="input-full"
|
||||
placeholder="e.g., Gmail SMTP, SendGrid"
|
||||
[class.filled]="emailProviderForm.get('name')?.value"
|
||||
autofocus
|
||||
/>
|
||||
@if (emailProviderForm.get('name')?.value && emailProviderForm.get('name')?.valid) {
|
||||
<i class="pi pi-check-circle input-icon success"></i>
|
||||
}
|
||||
</div>
|
||||
@if (emailProviderForm.get('name')?.invalid && (emailProviderForm.get('name')?.dirty || emailProviderForm.get('name')?.touched)) {
|
||||
<small class="field-error">Provider name is required.</small>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-4">
|
||||
<label class="w-40 text-right font-medium">From Address:</label>
|
||||
<input type="text" pInputText formControlName="fromAddress" placeholder="Enter from address... " class="w-full md:w-80"/>
|
||||
</div>
|
||||
<div class="gradient-divider"></div>
|
||||
|
||||
<div class="flex items-center gap-4">
|
||||
<label class="w-40 text-right font-medium">Auth:</label>
|
||||
<p-checkbox formControlName="auth" [binary]="true"></p-checkbox>
|
||||
</div>
|
||||
<div class="form-group highlight-group">
|
||||
<label for="host" class="form-label">
|
||||
<i class="pi pi-server label-icon"></i>
|
||||
Host
|
||||
<span class="required-indicator">*</span>
|
||||
</label>
|
||||
<div class="input-wrapper">
|
||||
<input
|
||||
id="host"
|
||||
type="text"
|
||||
pInputText
|
||||
formControlName="host"
|
||||
class="input-full"
|
||||
placeholder="e.g., smtp.gmail.com"
|
||||
[class.filled]="emailProviderForm.get('host')?.value"
|
||||
/>
|
||||
@if (emailProviderForm.get('host')?.value && emailProviderForm.get('host')?.valid) {
|
||||
<i class="pi pi-check-circle input-icon success"></i>
|
||||
}
|
||||
</div>
|
||||
@if (emailProviderForm.get('host')?.invalid && (emailProviderForm.get('host')?.dirty || emailProviderForm.get('host')?.touched)) {
|
||||
<small class="field-error">Host is required.</small>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-4">
|
||||
<label class="w-40 text-right font-medium">StartTLS:</label>
|
||||
<p-checkbox formControlName="startTls" [binary]="true"></p-checkbox>
|
||||
</div>
|
||||
<div class="form-group highlight-group">
|
||||
<label for="port" class="form-label">
|
||||
<i class="pi pi-hashtag label-icon"></i>
|
||||
Port
|
||||
<span class="required-indicator">*</span>
|
||||
</label>
|
||||
<div class="input-wrapper">
|
||||
<input
|
||||
id="port"
|
||||
type="number"
|
||||
pInputText
|
||||
formControlName="port"
|
||||
class="input-full"
|
||||
placeholder="e.g., 587, 465"
|
||||
[class.filled]="emailProviderForm.get('port')?.value"
|
||||
/>
|
||||
@if (emailProviderForm.get('port')?.value && emailProviderForm.get('port')?.valid) {
|
||||
<i class="pi pi-check-circle input-icon success"></i>
|
||||
}
|
||||
</div>
|
||||
@if (emailProviderForm.get('port')?.invalid && (emailProviderForm.get('port')?.dirty || emailProviderForm.get('port')?.touched)) {
|
||||
<small class="field-error">Port is required and must be a number.</small>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end">
|
||||
<p-button label="Create Email Provider" [disabled]="emailProviderForm.invalid" type="submit">
|
||||
</p-button>
|
||||
</div>
|
||||
<div class="gradient-divider"></div>
|
||||
|
||||
</form>
|
||||
<div class="form-group highlight-group">
|
||||
<label for="username" class="form-label">
|
||||
<i class="pi pi-user label-icon"></i>
|
||||
Username
|
||||
</label>
|
||||
<input
|
||||
id="username"
|
||||
type="text"
|
||||
pInputText
|
||||
formControlName="username"
|
||||
class="input-full"
|
||||
placeholder="Enter username"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="form-group highlight-group">
|
||||
<label for="password" class="form-label">
|
||||
<i class="pi pi-lock label-icon"></i>
|
||||
Password
|
||||
</label>
|
||||
<input
|
||||
id="password"
|
||||
type="password"
|
||||
pInputText
|
||||
formControlName="password"
|
||||
class="input-full"
|
||||
placeholder="Enter password"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="form-group highlight-group">
|
||||
<label for="fromAddress" class="form-label">
|
||||
<i class="pi pi-at label-icon"></i>
|
||||
From Address
|
||||
</label>
|
||||
<input
|
||||
id="fromAddress"
|
||||
type="text"
|
||||
pInputText
|
||||
formControlName="fromAddress"
|
||||
class="input-full"
|
||||
placeholder="e.g., noreply@example.com"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="gradient-divider"></div>
|
||||
|
||||
<div class="form-group highlight-group checkbox-group">
|
||||
<div class="checkbox-row">
|
||||
<p-checkbox formControlName="auth" [binary]="true" inputId="auth"></p-checkbox>
|
||||
<label for="auth" class="checkbox-label">
|
||||
<span class="checkbox-title">Enable Authentication</span>
|
||||
<span class="checkbox-description">Require username and password for SMTP</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group highlight-group checkbox-group">
|
||||
<div class="checkbox-row">
|
||||
<p-checkbox formControlName="startTls" [binary]="true" inputId="startTls"></p-checkbox>
|
||||
<label for="startTls" class="checkbox-label">
|
||||
<span class="checkbox-title">Enable StartTLS</span>
|
||||
<span class="checkbox-description">Use TLS encryption for secure connection</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dialog-footer">
|
||||
<div class="validation-status">
|
||||
@if (emailProviderForm.invalid) {
|
||||
<div class="validation-message error">
|
||||
<i class="pi pi-exclamation-circle"></i>
|
||||
<span>Please fill in all required fields</span>
|
||||
</div>
|
||||
} @else {
|
||||
<div class="validation-message success">
|
||||
<i class="pi pi-check-circle"></i>
|
||||
<span>Ready to create provider</span>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div class="footer-actions">
|
||||
<p-button
|
||||
label="Cancel"
|
||||
severity="secondary"
|
||||
[outlined]="true"
|
||||
(onClick)="closeDialog()"
|
||||
type="button"
|
||||
/>
|
||||
<p-button
|
||||
label="Create Provider"
|
||||
icon="pi pi-plus"
|
||||
severity="success"
|
||||
type="submit"
|
||||
[disabled]="emailProviderForm.invalid"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,365 @@
|
||||
.email-provider-form {
|
||||
padding: 1.5rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.email-provider-creator {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 600px;
|
||||
|
||||
@media (max-width: 640px) {
|
||||
min-width: auto;
|
||||
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);
|
||||
|
||||
.header-icon-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
background: var(--primary-color);
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.2);
|
||||
|
||||
.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);
|
||||
}
|
||||
}
|
||||
|
||||
.close-button {
|
||||
position: absolute;
|
||||
top: 0.75rem;
|
||||
right: 0.75rem;
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
padding: 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;
|
||||
}
|
||||
}
|
||||
|
||||
.close-button {
|
||||
top: 0.5rem;
|
||||
right: 0.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.form-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 1.5rem;
|
||||
background: var(--card-background);
|
||||
border: 1px solid var(--border-color);
|
||||
border-top: none;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);
|
||||
max-height: 60vh;
|
||||
overflow-y: auto;
|
||||
|
||||
@media (max-width: 480px) {
|
||||
padding: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.form-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
|
||||
&.highlight-group {
|
||||
padding: 0.875rem;
|
||||
}
|
||||
|
||||
&.checkbox-group {
|
||||
padding: 0.75rem 0.875rem;
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
gap: 0.375rem;
|
||||
margin-bottom: 1rem;
|
||||
|
||||
&.highlight-group {
|
||||
padding: 0.625rem;
|
||||
}
|
||||
|
||||
&.checkbox-group {
|
||||
padding: 0.5rem 0.625rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.form-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.375rem;
|
||||
font-size: 0.95rem;
|
||||
font-weight: 600;
|
||||
color: var(--text-color);
|
||||
|
||||
.label-icon {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.required-indicator {
|
||||
color: var(--p-red-500);
|
||||
margin-left: 0.125rem;
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
}
|
||||
|
||||
.form-input {
|
||||
width: 100%;
|
||||
max-width: 20rem;
|
||||
}
|
||||
|
||||
.input-wrapper {
|
||||
position: relative;
|
||||
|
||||
.input-full {
|
||||
width: 100%;
|
||||
padding-right: 2.5rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.input-icon {
|
||||
position: absolute;
|
||||
right: 0.75rem;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
font-size: 1rem;
|
||||
pointer-events: none;
|
||||
|
||||
&.success {
|
||||
color: var(--p-green-500);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.input-full {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.form-error {
|
||||
color: #ef4444;
|
||||
padding-left: 10rem;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.field-error {
|
||||
color: #ef4444;
|
||||
font-size: 0.875rem;
|
||||
margin-top: 0.25rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
|
||||
&::before {
|
||||
content: '⚠';
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
}
|
||||
|
||||
.checkbox-row {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 0.75rem;
|
||||
|
||||
.checkbox-label {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.125rem;
|
||||
cursor: pointer;
|
||||
flex: 1;
|
||||
|
||||
.checkbox-title {
|
||||
font-size: 0.9375rem;
|
||||
font-weight: 600;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.checkbox-description {
|
||||
font-size: 0.8rem;
|
||||
color: var(--text-secondary-color);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
gap: 0.5rem;
|
||||
|
||||
.checkbox-label {
|
||||
.checkbox-title {
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.checkbox-description {
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.gradient-divider {
|
||||
height: 1px;
|
||||
background: linear-gradient(
|
||||
to right,
|
||||
transparent,
|
||||
var(--border-color) 20%,
|
||||
var(--border-color) 80%,
|
||||
transparent
|
||||
);
|
||||
margin: 1.25rem 0;
|
||||
|
||||
@media (max-width: 480px) {
|
||||
margin: 1rem 0;
|
||||
}
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
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);
|
||||
|
||||
.validation-status {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.footer-actions {
|
||||
display: flex;
|
||||
gap: 0.75rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
padding: 1rem;
|
||||
gap: 0.75rem;
|
||||
|
||||
.validation-status {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.footer-actions {
|
||||
width: 100%;
|
||||
justify-content: flex-end;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.validation-message {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.375rem;
|
||||
padding: 0.25rem 0.5rem;
|
||||
font-weight: 500;
|
||||
border-radius: 6px;
|
||||
font-size: 0.875rem;
|
||||
width: fit-content;
|
||||
max-width: 100%;
|
||||
|
||||
i {
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
&.error {
|
||||
background: rgba(239, 68, 68, 0.1);
|
||||
color: rgb(239, 68, 68);
|
||||
border: 1px solid rgba(239, 68, 68, 0.3);
|
||||
|
||||
i {
|
||||
color: rgb(239, 68, 68);
|
||||
}
|
||||
}
|
||||
|
||||
&.success {
|
||||
background: rgba(34, 197, 94, 0.1);
|
||||
color: rgb(34, 197, 94);
|
||||
border: 1px solid rgba(34, 197, 94, 0.3);
|
||||
|
||||
i {
|
||||
color: rgb(34, 197, 94);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
font-size: 0.8rem;
|
||||
padding: 0.375rem 0.5rem;
|
||||
width: 100%;
|
||||
|
||||
i {
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
@@ -72,4 +72,8 @@ export class CreateEmailProviderDialogComponent implements OnInit {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
closeDialog(): void {
|
||||
this.ref.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,33 +1,121 @@
|
||||
<form [formGroup]="emailRecipientForm" (ngSubmit)="createEmailRecipient()" class="space-y-6 p-6">
|
||||
|
||||
<div class="flex items-center gap-4">
|
||||
<label class="w-40 text-right font-medium">Recipient Name:</label>
|
||||
<input type="text" pInputText formControlName="name" placeholder="Enter recipient name..." class="w-full md:w-80"/>
|
||||
</div>
|
||||
@if (emailRecipientForm.get('name')?.invalid && (emailRecipientForm.get('name')?.dirty || emailRecipientForm.get('name')?.touched)) {
|
||||
<small class="text-red-500 pl-44">
|
||||
Recipient name is required.
|
||||
</small>
|
||||
}
|
||||
|
||||
<div class="flex items-center gap-4">
|
||||
<label class="w-40 text-right font-medium">Email Address:</label>
|
||||
<input type="email" pInputText formControlName="email" placeholder="Enter email address..." class="w-full md:w-80"/>
|
||||
</div>
|
||||
@if (emailRecipientForm.get('email')?.invalid && (emailRecipientForm.get('email')?.dirty || emailRecipientForm.get('email')?.touched)) {
|
||||
<small class="text-red-500 pl-44">
|
||||
Valid email is required.
|
||||
</small>
|
||||
}
|
||||
|
||||
<div class="flex items-center gap-4">
|
||||
<label class="w-40 text-right font-medium">Default Recipient:</label>
|
||||
<p-checkbox formControlName="defaultRecipient" [binary]="true"></p-checkbox>
|
||||
<div class="email-recipient-creator">
|
||||
<div class="panel-header">
|
||||
<div class="header-icon-wrapper">
|
||||
<i class="pi pi-user header-icon"></i>
|
||||
</div>
|
||||
<div class="header-text">
|
||||
<h2 class="panel-title">Create Email Recipient</h2>
|
||||
<p class="panel-description">Add a new recipient for email notifications</p>
|
||||
</div>
|
||||
<p-button
|
||||
icon="pi pi-times"
|
||||
(click)="closeDialog()"
|
||||
severity="secondary"
|
||||
[text]="true"
|
||||
[rounded]="true"
|
||||
class="close-button"
|
||||
pTooltip="Close"
|
||||
tooltipPosition="left"/>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end">
|
||||
<p-button label="Add Recipient" [disabled]="emailRecipientForm.invalid" type="submit">
|
||||
</p-button>
|
||||
</div>
|
||||
<form [formGroup]="emailRecipientForm" (ngSubmit)="createEmailRecipient()">
|
||||
<div class="form-container">
|
||||
<div class="form-group highlight-group">
|
||||
<label for="recipientName" class="form-label">
|
||||
<i class="pi pi-user label-icon"></i>
|
||||
Recipient Name
|
||||
<span class="required-indicator">*</span>
|
||||
</label>
|
||||
<div class="input-wrapper">
|
||||
<input
|
||||
id="recipientName"
|
||||
type="text"
|
||||
pInputText
|
||||
formControlName="name"
|
||||
class="input-full"
|
||||
placeholder="Enter recipient name..."
|
||||
[class.filled]="emailRecipientForm.get('name')?.value"
|
||||
autofocus
|
||||
/>
|
||||
@if (emailRecipientForm.get('name')?.value && emailRecipientForm.get('name')?.valid) {
|
||||
<i class="pi pi-check-circle input-icon success"></i>
|
||||
}
|
||||
</div>
|
||||
@if (emailRecipientForm.get('name')?.invalid && (emailRecipientForm.get('name')?.dirty || emailRecipientForm.get('name')?.touched)) {
|
||||
<small class="field-error">Recipient name is required.</small>
|
||||
}
|
||||
</div>
|
||||
|
||||
</form>
|
||||
<div class="gradient-divider"></div>
|
||||
|
||||
<div class="form-group highlight-group">
|
||||
<label for="email" class="form-label">
|
||||
<i class="pi pi-at label-icon"></i>
|
||||
Email Address
|
||||
<span class="required-indicator">*</span>
|
||||
</label>
|
||||
<div class="input-wrapper">
|
||||
<input
|
||||
id="email"
|
||||
type="email"
|
||||
pInputText
|
||||
formControlName="email"
|
||||
class="input-full"
|
||||
placeholder="Enter email address..."
|
||||
[class.filled]="emailRecipientForm.get('email')?.value"
|
||||
/>
|
||||
@if (emailRecipientForm.get('email')?.value && emailRecipientForm.get('email')?.valid) {
|
||||
<i class="pi pi-check-circle input-icon success"></i>
|
||||
}
|
||||
</div>
|
||||
@if (emailRecipientForm.get('email')?.invalid && (emailRecipientForm.get('email')?.dirty || emailRecipientForm.get('email')?.touched)) {
|
||||
<small class="field-error">Valid email is required.</small>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="gradient-divider"></div>
|
||||
|
||||
<div class="form-group highlight-group checkbox-group">
|
||||
<div class="checkbox-row">
|
||||
<p-checkbox formControlName="defaultRecipient" [binary]="true" inputId="defaultRecipient"></p-checkbox>
|
||||
<label for="defaultRecipient" class="checkbox-label">
|
||||
<span class="checkbox-title">Default Recipient</span>
|
||||
<span class="checkbox-description">Set as default recipient for all notifications</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dialog-footer">
|
||||
<div class="validation-status">
|
||||
@if (emailRecipientForm.invalid) {
|
||||
<div class="validation-message error">
|
||||
<i class="pi pi-exclamation-circle"></i>
|
||||
<span>Please fill in all required fields</span>
|
||||
</div>
|
||||
} @else {
|
||||
<div class="validation-message success">
|
||||
<i class="pi pi-check-circle"></i>
|
||||
<span>Ready to add recipient</span>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div class="footer-actions">
|
||||
<p-button
|
||||
label="Cancel"
|
||||
severity="secondary"
|
||||
[outlined]="true"
|
||||
(onClick)="closeDialog()"
|
||||
type="button"
|
||||
/>
|
||||
<p-button
|
||||
label="Add Recipient"
|
||||
icon="pi pi-plus"
|
||||
severity="success"
|
||||
type="submit"
|
||||
[disabled]="emailRecipientForm.invalid"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,336 @@
|
||||
.email-recipient-creator {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 600px;
|
||||
|
||||
@media (max-width: 640px) {
|
||||
min-width: auto;
|
||||
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);
|
||||
|
||||
.header-icon-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
background: var(--primary-color);
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.2);
|
||||
|
||||
.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);
|
||||
}
|
||||
}
|
||||
|
||||
.close-button {
|
||||
position: absolute;
|
||||
top: 0.75rem;
|
||||
right: 0.75rem;
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
padding: 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;
|
||||
}
|
||||
}
|
||||
|
||||
.close-button {
|
||||
top: 0.5rem;
|
||||
right: 0.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.form-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 1.5rem;
|
||||
background: var(--card-background);
|
||||
border: 1px solid var(--border-color);
|
||||
border-top: none;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);
|
||||
max-height: 60vh;
|
||||
overflow-y: auto;
|
||||
|
||||
@media (max-width: 480px) {
|
||||
padding: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.form-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
|
||||
&.highlight-group {
|
||||
padding: 0.875rem;
|
||||
}
|
||||
|
||||
&.checkbox-group {
|
||||
padding: 0.75rem 0.875rem;
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
gap: 0.375rem;
|
||||
|
||||
&.highlight-group {
|
||||
padding: 0.625rem;
|
||||
}
|
||||
|
||||
&.checkbox-group {
|
||||
padding: 0.5rem 0.625rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.form-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.375rem;
|
||||
font-size: 0.95rem;
|
||||
font-weight: 600;
|
||||
color: var(--text-color);
|
||||
|
||||
.label-icon {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.required-indicator {
|
||||
color: var(--p-red-500);
|
||||
margin-left: 0.125rem;
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
}
|
||||
|
||||
.input-wrapper {
|
||||
position: relative;
|
||||
|
||||
.input-full {
|
||||
width: 100%;
|
||||
padding-right: 2.5rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.input-icon {
|
||||
position: absolute;
|
||||
right: 0.75rem;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
font-size: 1rem;
|
||||
pointer-events: none;
|
||||
|
||||
&.success {
|
||||
color: var(--p-green-500);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.input-full {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.field-error {
|
||||
color: #ef4444;
|
||||
font-size: 0.875rem;
|
||||
margin-top: 0.25rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
|
||||
&::before {
|
||||
content: '⚠';
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
}
|
||||
|
||||
.checkbox-row {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 0.75rem;
|
||||
|
||||
.checkbox-label {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.125rem;
|
||||
cursor: pointer;
|
||||
flex: 1;
|
||||
|
||||
.checkbox-title {
|
||||
font-size: 0.9375rem;
|
||||
font-weight: 600;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.checkbox-description {
|
||||
font-size: 0.8rem;
|
||||
color: var(--text-secondary-color);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
gap: 0.5rem;
|
||||
|
||||
.checkbox-label {
|
||||
.checkbox-title {
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.checkbox-description {
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.gradient-divider {
|
||||
height: 1px;
|
||||
background: linear-gradient(
|
||||
to right,
|
||||
transparent,
|
||||
var(--border-color) 20%,
|
||||
var(--border-color) 80%,
|
||||
transparent
|
||||
);
|
||||
margin: 1.25rem 0;
|
||||
|
||||
@media (max-width: 480px) {
|
||||
margin: 1rem 0;
|
||||
}
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
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);
|
||||
|
||||
.validation-status {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.footer-actions {
|
||||
display: flex;
|
||||
gap: 0.75rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
padding: 1rem;
|
||||
gap: 0.75rem;
|
||||
|
||||
.validation-status {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.footer-actions {
|
||||
width: 100%;
|
||||
justify-content: flex-end;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.validation-message {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.375rem;
|
||||
padding: 0.25rem 0.5rem;
|
||||
font-weight: 500;
|
||||
border-radius: 6px;
|
||||
font-size: 0.875rem;
|
||||
width: fit-content;
|
||||
max-width: 100%;
|
||||
|
||||
i {
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
&.error {
|
||||
background: rgba(239, 68, 68, 0.1);
|
||||
color: rgb(239, 68, 68);
|
||||
border: 1px solid rgba(239, 68, 68, 0.3);
|
||||
|
||||
i {
|
||||
color: rgb(239, 68, 68);
|
||||
}
|
||||
}
|
||||
|
||||
&.success {
|
||||
background: rgba(34, 197, 94, 0.1);
|
||||
color: rgb(34, 197, 94);
|
||||
border: 1px solid rgba(34, 197, 94, 0.3);
|
||||
|
||||
i {
|
||||
color: rgb(34, 197, 94);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
font-size: 0.8rem;
|
||||
padding: 0.375rem 0.5rem;
|
||||
width: 100%;
|
||||
|
||||
i {
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import {Checkbox} from 'primeng/checkbox';
|
||||
import {Button} from 'primeng/button';
|
||||
import {InputText} from 'primeng/inputtext';
|
||||
import {EmailV2RecipientService} from '../email-v2-recipient/email-v2-recipient.service';
|
||||
import {Tooltip} from 'primeng/tooltip';
|
||||
|
||||
@Component({
|
||||
selector: 'app-create-email-recipient-dialog',
|
||||
@@ -13,7 +14,8 @@ import {EmailV2RecipientService} from '../email-v2-recipient/email-v2-recipient.
|
||||
Checkbox,
|
||||
ReactiveFormsModule,
|
||||
Button,
|
||||
InputText
|
||||
InputText,
|
||||
Tooltip
|
||||
],
|
||||
templateUrl: './create-email-recipient-dialog.component.html',
|
||||
styleUrls: ['./create-email-recipient-dialog.component.scss']
|
||||
@@ -33,6 +35,10 @@ export class CreateEmailRecipientDialogComponent {
|
||||
});
|
||||
}
|
||||
|
||||
closeDialog(): void {
|
||||
this.ref.close();
|
||||
}
|
||||
|
||||
createEmailRecipient(): void {
|
||||
if (this.emailRecipientForm.invalid) {
|
||||
this.messageService.add({
|
||||
|
||||
@@ -128,7 +128,8 @@ export class EmailV2ProviderComponent implements OnInit {
|
||||
header: 'Create Email Provider',
|
||||
modal: true,
|
||||
closable: true,
|
||||
style: {position: 'absolute', top: '15%'},
|
||||
showHeader: false,
|
||||
styleClass: 'dynamic-dialog-minimal',
|
||||
});
|
||||
this.ref?.onClose.subscribe((result) => {
|
||||
if (result) {
|
||||
|
||||
@@ -21,7 +21,7 @@ import {CreateEmailRecipientDialogComponent} from '../create-email-recipient-dia
|
||||
TableModule,
|
||||
Tooltip,
|
||||
FormsModule
|
||||
],
|
||||
],
|
||||
templateUrl: './email-v2-recipient.component.html',
|
||||
styleUrl: './email-v2-recipient.component.scss'
|
||||
})
|
||||
@@ -115,7 +115,8 @@ export class EmailV2RecipientComponent implements OnInit {
|
||||
header: 'Add New Recipient',
|
||||
modal: true,
|
||||
closable: true,
|
||||
style: {position: 'absolute', top: '15%'},
|
||||
showHeader: false,
|
||||
styleClass: 'dynamic-dialog-minimal',
|
||||
});
|
||||
this.ref?.onClose.subscribe((result) => {
|
||||
if (result) {
|
||||
|
||||
@@ -187,7 +187,7 @@
|
||||
</div>
|
||||
|
||||
<p-dialog
|
||||
header="Create User"
|
||||
header="Create OPDS User"
|
||||
[(visible)]="showCreateUserDialog"
|
||||
[modal]="true"
|
||||
styleClass="user-dialog"
|
||||
|
||||
@@ -88,6 +88,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gradient-divider"></div>
|
||||
|
||||
<div class="form-section">
|
||||
<h3 class="section-title">
|
||||
<i class="pi pi-book"></i>
|
||||
@@ -114,6 +116,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gradient-divider"></div>
|
||||
|
||||
<div class="form-section">
|
||||
<h3 class="section-title">
|
||||
<i class="pi pi-shield"></i>
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
max-width: 650px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-top: 20px;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
width: 100%;
|
||||
@@ -15,8 +14,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
padding: 1.25rem;
|
||||
|
||||
padding: 1.5rem 1.5rem 1.25rem 1.5rem;
|
||||
border-radius: 10px 10px 0 0;
|
||||
border: 1px solid var(--border-color);
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);
|
||||
@@ -82,13 +80,12 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2rem;
|
||||
padding: 2rem 1.5rem 1.5rem 1.5rem;
|
||||
padding: 2rem;
|
||||
background: var(--card-background);
|
||||
border: 1px solid var(--border-color);
|
||||
border-top: none;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);
|
||||
max-height: 60vh;
|
||||
overflow-y: auto;
|
||||
max-height: 60vh;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
@@ -118,7 +115,7 @@
|
||||
.form-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
gap: 0.75rem;
|
||||
|
||||
.section-title {
|
||||
display: flex;
|
||||
@@ -129,7 +126,6 @@
|
||||
font-weight: 600;
|
||||
color: var(--text-color);
|
||||
padding-bottom: 0.5rem;
|
||||
border-bottom: 2px solid var(--border-color);
|
||||
|
||||
i {
|
||||
color: var(--primary-color);
|
||||
@@ -287,7 +283,7 @@
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding: 1rem 1.5rem;
|
||||
padding: 1.25rem 1.5rem;
|
||||
background: var(--card-background);
|
||||
border: 1px solid var(--border-color);
|
||||
border-top: none;
|
||||
@@ -328,4 +324,3 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -110,6 +110,7 @@ export class UserManagementComponent implements OnInit, OnDestroy {
|
||||
showHeader: false,
|
||||
modal: true,
|
||||
closable: true,
|
||||
styleClass: 'dynamic-dialog-minimal',
|
||||
});
|
||||
this.ref?.onClose.subscribe((result) => {
|
||||
if (result) {
|
||||
|
||||
@@ -76,6 +76,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gradient-divider"></div>
|
||||
|
||||
<div class="form-section">
|
||||
<h3 class="section-title">
|
||||
<i class="pi pi-shield"></i>
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
max-width: 650px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-top: 20px;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
width: 100%;
|
||||
@@ -16,8 +15,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
padding: 1.25rem 3.5rem 1.25rem 1.25rem;
|
||||
|
||||
padding: 1.5rem 1.5rem 1.25rem 1.5rem;
|
||||
border-radius: 10px 10px 0 0;
|
||||
border: 1px solid var(--border-color);
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);
|
||||
@@ -97,8 +95,8 @@
|
||||
.form-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 3.5rem;
|
||||
padding: 2rem 1.5rem 1.5rem 1.5rem;
|
||||
gap: 2rem;
|
||||
padding: 2rem;
|
||||
background: var(--card-background);
|
||||
border: 1px solid var(--border-color);
|
||||
border-top: none;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
Open Metadata Center
|
||||
</h2>
|
||||
<p class="settings-description">
|
||||
Decide how you want to view book details — inline as a full page or in a pop-up dialog.
|
||||
Decide how you want to view book details - inline as a full page or in a pop-up dialog.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -38,10 +38,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
@if (value === 'library') {
|
||||
<div class="divider"></div>
|
||||
<div class="gradient-divider"></div>
|
||||
<div class="library-selection">
|
||||
<div class="section-header">
|
||||
<span class="section-title">
|
||||
@@ -77,7 +75,7 @@
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="divider"></div>
|
||||
<div class="gradient-divider"></div>
|
||||
|
||||
<div class="file-upload-section">
|
||||
<div class="section-header">
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
max-width: 700px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-top: 20px;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
width: 100%;
|
||||
@@ -16,8 +15,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
padding: 1.25rem;
|
||||
|
||||
padding: 1.5rem 1.5rem 1.25rem 1.5rem;
|
||||
border-radius: 10px 10px 0 0;
|
||||
border: 1px solid var(--border-color);
|
||||
border-bottom: none;
|
||||
@@ -100,7 +98,7 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
padding: 1.5rem;
|
||||
padding: 1.75rem;
|
||||
background: var(--card-background);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 0 0 10px 10px;
|
||||
@@ -427,12 +425,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.divider {
|
||||
height: 1px;
|
||||
background: linear-gradient(90deg, transparent, var(--border-color), transparent);
|
||||
margin: 0.25rem 0;
|
||||
}
|
||||
|
||||
:host ::ng-deep .p-fileupload-content p-progressbar {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<div class="current-path">
|
||||
<div class="path-label">
|
||||
<i class="pi pi-map-marker"></i>
|
||||
<span>Current:</span>
|
||||
<span>Current Path:</span>
|
||||
</div>
|
||||
<div class="path-value">
|
||||
{{ selectedProductName || '/' }}
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
max-width: 550px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-top: 20px;
|
||||
|
||||
@media (max-width: 640px) {
|
||||
width: 100%;
|
||||
@@ -25,7 +24,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
padding: 1.25rem 1.25rem;
|
||||
padding: 1.5rem 1.5rem 1.25rem 1.5rem;
|
||||
border-radius: 10px 10px 0 0;
|
||||
border: 1px solid var(--border-color);
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);
|
||||
@@ -91,7 +90,7 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
padding: 1rem 1.5rem;
|
||||
padding: 1rem 2rem;
|
||||
background: var(--card-background);
|
||||
border: 1px solid var(--border-color);
|
||||
border-top: none;
|
||||
@@ -100,7 +99,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding: 0.625rem 0.875rem;
|
||||
padding: 0.625rem;
|
||||
background: var(--overlay-background);
|
||||
border-radius: 6px;
|
||||
|
||||
@@ -114,7 +113,7 @@
|
||||
white-space: nowrap;
|
||||
|
||||
i {
|
||||
color: var(--primary-color);
|
||||
color: coral;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,7 +201,7 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
padding: 1.5rem;
|
||||
padding: 1rem 2rem;
|
||||
background: var(--card-background);
|
||||
border: 1px solid var(--border-color);
|
||||
border-top: none;
|
||||
@@ -504,7 +503,7 @@
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding: 1rem 1.5rem;
|
||||
padding: 1.25rem 1.5rem;
|
||||
background: var(--card-background);
|
||||
border: 1px solid var(--border-color);
|
||||
border-top: none;
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
}
|
||||
|
||||
:host(.active-menuitem) .menu-item-container {
|
||||
background-color: color-mix(in srgb, var(--p-primary-300), transparent 92%);
|
||||
background-color: color-mix(in srgb, var(--p-primary-300), transparent 93%);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,14 +13,15 @@ export class DialogLauncherService {
|
||||
|
||||
dialogService = inject(DialogService);
|
||||
|
||||
open(options: { component: any; header: string; top?: string; width?: string; showHeader?: boolean }): DynamicDialogRef | null {
|
||||
open(options: { component: any; header: string; top?: string; width?: string; showHeader?: boolean; styleClass?: string }): DynamicDialogRef | null {
|
||||
const isMobile = window.innerWidth <= 768;
|
||||
const {component, header, top, width, showHeader = true} = options;
|
||||
const {component, header, top, width, showHeader = true, styleClass} = options;
|
||||
return this.dialogService.open(component, {
|
||||
header,
|
||||
showHeader,
|
||||
modal: true,
|
||||
closable: true,
|
||||
styleClass: styleClass,
|
||||
style: {
|
||||
position: 'absolute',
|
||||
...(top ? {top} : {}),
|
||||
@@ -50,6 +51,7 @@ export class DialogLauncherService {
|
||||
this.open({
|
||||
component: LibraryCreatorComponent,
|
||||
header: 'Create New Library',
|
||||
styleClass: 'dynamic-dialog-minimal',
|
||||
showHeader: false
|
||||
});
|
||||
}
|
||||
@@ -58,7 +60,8 @@ export class DialogLauncherService {
|
||||
this.open({
|
||||
component: BookUploaderComponent,
|
||||
header: 'Book Uploader',
|
||||
showHeader: false
|
||||
showHeader: false,
|
||||
styleClass: 'dynamic-dialog-minimal'
|
||||
});
|
||||
}
|
||||
|
||||
@@ -66,6 +69,7 @@ export class DialogLauncherService {
|
||||
this.open({
|
||||
component: UserProfileDialogComponent,
|
||||
header: 'User Profile Information',
|
||||
styleClass: 'dynamic-dialog-minimal',
|
||||
showHeader: false
|
||||
});
|
||||
}
|
||||
@@ -74,6 +78,7 @@ export class DialogLauncherService {
|
||||
this.open({
|
||||
component: MagicShelfComponent,
|
||||
header: 'Magic Shelf Creator',
|
||||
styleClass: 'dynamic-dialog-minimal',
|
||||
showHeader: false
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,3 +3,19 @@
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.dynamic-dialog-minimal.p-dialog {
|
||||
border: none;
|
||||
|
||||
.p-dialog-content {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.gradient-divider {
|
||||
min-height: 1px;
|
||||
height: 1px;
|
||||
background: linear-gradient(90deg, transparent, var(--border-color), transparent);
|
||||
margin: 0.25rem 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user