@memberjunction/ng-explorer-settings 5.11.0 → 5.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/account-info/account-info.component.js +2 -2
- package/dist/lib/appearance-settings/appearance-settings.component.js +2 -2
- package/dist/lib/application-management/application-dialog/application-dialog.component.js +2 -2
- package/dist/lib/application-management/application-management.component.js +2 -2
- package/dist/lib/application-settings/application-settings.component.js +2 -2
- package/dist/lib/entity-permissions/entity-permissions.component.js +2 -2
- package/dist/lib/entity-permissions/permission-dialog/permission-dialog.component.js +2 -2
- package/dist/lib/general-settings/general-settings.component.js +2 -2
- package/dist/lib/notification-preferences/notification-preferences.component.js +2 -2
- package/dist/lib/role-management/role-dialog/role-dialog.component.js +2 -2
- package/dist/lib/role-management/role-management.component.js +2 -2
- package/dist/lib/settings/settings.component.js +2 -2
- package/dist/lib/sql-logging/sql-logging.component.js +2 -2
- package/dist/lib/user-management/user-dialog/user-dialog.component.js +2 -2
- package/dist/lib/user-management/user-management.component.js +2 -2
- package/dist/lib/user-profile-settings/user-profile-settings.component.js +2 -2
- package/package.json +17 -17
|
@@ -462,11 +462,11 @@ export class UserDialogComponent {
|
|
|
462
462
|
i0.ɵɵconditionalCreate(0, UserDialogComponent_Conditional_0_Template, 92, 12, "div", 0);
|
|
463
463
|
} if (rf & 2) {
|
|
464
464
|
i0.ɵɵconditional(ctx.visible ? 0 : -1);
|
|
465
|
-
} }, dependencies: [i1.ɵNgNoValidate, i1.NgSelectOption, i1.ɵNgSelectMultipleOption, i1.DefaultValueAccessor, i1.CheckboxControlValueAccessor, i1.SelectControlValueAccessor, i1.NgControlStatus, i1.NgControlStatusGroup, i1.FormGroupDirective, i1.FormControlName], styles: ["/* ============================================\n User Dialog Component\n Uses MJ Design Tokens (--mj-*)\n ============================================ */\n\n/* ============================================\n Modal Backdrop & Container\n ============================================ */\n\n.modal-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n backdrop-filter: blur(4px);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1050;\n padding: 1rem;\n animation: fadeIn 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n.modal-dialog {\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-2xl);\n box-shadow: var(--mj-shadow-2xl);\n width: 100%;\n max-width: 900px;\n max-height: calc(100vh - 2rem);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n animation: slideIn 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n@keyframes slideIn {\n from {\n opacity: 0;\n transform: scale(0.95) translateY(20px);\n }\n to {\n opacity: 1;\n transform: scale(1) translateY(0);\n }\n}\n\n/* ============================================\n Modal Header (MJ Blue)\n ============================================ */\n\n.modal-header {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n padding: 24px 32px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 1rem;\n border-radius: var(--mj-radius-2xl) var(--mj-radius-2xl) 0 0;\n flex-shrink: 0;\n}\n\n.dialog-header {\n flex: 1;\n min-width: 0;\n}\n\n.dialog-title {\n margin: 0;\n font-size: 1.5rem;\n font-weight: 600;\n line-height: 1.3;\n display: flex;\n align-items: center;\n gap: 0.75rem;\n color: var(--mj-brand-on-primary);\n}\n\n.dialog-title i {\n font-size: 1.25rem;\n opacity: 0.95;\n}\n\n.dialog-subtitle {\n margin: 0.5rem 0 0 0;\n font-size: 0.875rem;\n opacity: 0.9;\n font-weight: 400;\n line-height: 1.4;\n}\n\n.modal-close {\n background: transparent;\n border: none;\n color: var(--mj-brand-on-primary);\n cursor: pointer;\n padding: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: var(--mj-radius-full);\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n width: 40px;\n height: 40px;\n flex-shrink: 0;\n}\n\n.modal-close:hover {\n background: rgba(255, 255, 255, 0.1);\n}\n\n.modal-close:active {\n background: rgba(255, 255, 255, 0.2);\n transform: scale(0.95);\n}\n\n.modal-close i {\n font-size: 1.25rem;\n}\n\n/* ============================================\n Modal Body\n ============================================ */\n\n.modal-body {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n padding: 0;\n background: var(--mj-bg-page);\n}\n\n.modal-body::-webkit-scrollbar {\n width: 8px;\n}\n\n.modal-body::-webkit-scrollbar-track {\n background: var(--mj-bg-surface-sunken);\n}\n\n.modal-body::-webkit-scrollbar-thumb {\n background: var(--mj-border-default);\n border-radius: var(--mj-radius-full);\n}\n\n.modal-body::-webkit-scrollbar-thumb:hover {\n background: var(--mj-color-neutral-400);\n}\n\n/* ============================================\n Form Structure\n ============================================ */\n\n.content-section {\n padding: 1.5rem 2rem;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.content-section:last-child {\n border-bottom: none;\n}\n\n.form-section {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n.section-header {\n margin-bottom: 1rem;\n}\n\n.section-title {\n margin: 0 0 0.5rem 0;\n font-size: 1.375rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 0.75rem;\n}\n\n.section-title i {\n font-size: 1.25rem;\n color: var(--mj-brand-primary);\n}\n\n.section-description {\n margin: 0;\n font-size: 0.875rem;\n color: var(--mj-text-secondary);\n line-height: 1.5;\n}\n\n/* ============================================\n Form Grid Layout\n ============================================ */\n\n.form-grid {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n.form-row {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 1.5rem;\n}\n\n@media (max-width: 640px) {\n .form-row {\n grid-template-columns: 1fr;\n gap: 1.5rem;\n }\n}\n\n/* ============================================\n Form Fields\n ============================================ */\n\n.form-field {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.field-label {\n font-size: 0.875rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 0.25rem;\n}\n\n.field-label.required::after {\n content: '*';\n color: var(--mj-status-error);\n margin-left: 0.25rem;\n}\n\n.field-input,\n.field-select {\n border: 2px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n padding: 0.875rem 1rem;\n font-size: 1rem;\n font-family: inherit;\n color: var(--mj-text-primary);\n background: var(--mj-bg-page);\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n width: 100%;\n box-sizing: border-box;\n}\n\n.field-input:hover:not(:disabled),\n.field-select:hover:not(:disabled) {\n border-color: var(--mj-color-neutral-400);\n}\n\n.field-input:focus,\n.field-select:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px rgba(0, 118, 182, 0.2);\n}\n\n.field-input:disabled,\n.field-select:disabled {\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n cursor: not-allowed;\n opacity: 0.6;\n}\n\n.field-input.error,\n.field-select.error {\n border-color: var(--mj-status-error);\n}\n\n.field-input.error:focus,\n.field-select.error:focus {\n box-shadow: 0 0 0 3px rgba(211, 47, 47, 0.2);\n}\n\n.field-input::placeholder,\n.field-select::placeholder {\n color: var(--mj-text-secondary);\n}\n\n/* Select Dropdown Styling */\n.field-select {\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%2379747E' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3e%3c/svg%3e\");\n background-position: right 16px center;\n background-repeat: no-repeat;\n background-size: 16px;\n padding-right: calc(16px + 32px);\n appearance: none;\n cursor: pointer;\n}\n\n.field-error {\n font-size: 0.75rem;\n color: var(--mj-status-error);\n display: flex;\n align-items: center;\n gap: 0.5rem;\n margin-top: 0.25rem;\n}\n\n.field-error i {\n font-size: 0.875rem;\n}\n\n/* ============================================\n Checkboxes\n ============================================ */\n\n.checkbox-field {\n display: flex;\n align-items: flex-start;\n gap: 0.75rem;\n cursor: pointer;\n margin-bottom: 0;\n}\n\n.checkbox-input {\n position: absolute;\n opacity: 0;\n cursor: pointer;\n}\n\n.checkbox-label {\n display: flex;\n align-items: flex-start;\n gap: 0.75rem;\n cursor: pointer;\n font-size: 0.875rem;\n color: var(--mj-text-primary);\n line-height: 1.4;\n margin: 0;\n flex: 1;\n}\n\n.checkbox-indicator {\n width: 20px;\n height: 20px;\n border: 2px solid var(--mj-color-neutral-400);\n border-radius: var(--mj-radius-sm);\n background: var(--mj-bg-page);\n flex-shrink: 0;\n position: relative;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n margin-top: 2px;\n}\n\n.checkbox-indicator::after {\n content: '';\n position: absolute;\n left: 6px;\n top: 2px;\n width: 4px;\n height: 8px;\n border: solid var(--mj-brand-on-primary);\n border-width: 0 2px 2px 0;\n opacity: 0;\n transform: rotate(45deg) scale(0.8);\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.checkbox-input:checked + .checkbox-label .checkbox-indicator {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.checkbox-input:checked + .checkbox-label .checkbox-indicator::after {\n opacity: 1;\n transform: rotate(45deg) scale(1);\n}\n\n.checkbox-input:focus + .checkbox-label .checkbox-indicator {\n box-shadow: 0 0 0 3px rgba(0, 118, 182, 0.2);\n}\n\n.checkbox-label strong {\n display: block;\n font-weight: 600;\n margin-bottom: 0.125rem;\n}\n\n/* ============================================\n Role Cards\n ============================================ */\n\n.roles-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));\n gap: 1rem;\n}\n\n@media (max-width: 640px) {\n .roles-grid {\n grid-template-columns: 1fr;\n }\n}\n\n.role-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n padding: 1.25rem;\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n display: flex;\n flex-direction: column;\n}\n\n.role-card:hover {\n border-color: var(--mj-brand-primary);\n box-shadow: var(--mj-shadow-md);\n transform: translateY(-2px);\n}\n\n.role-card.selected {\n background: var(--mj-brand-accent-subtle);\n border-color: var(--mj-brand-primary);\n box-shadow: var(--mj-shadow-md);\n}\n\n.role-content {\n display: flex;\n align-items: flex-start;\n gap: 1rem;\n}\n\n.role-info {\n flex: 1;\n min-width: 0;\n}\n\n.role-name {\n font-size: 1rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0 0 0.25rem 0;\n line-height: 1.3;\n}\n\n.role-description {\n font-size: 0.75rem;\n color: var(--mj-text-secondary);\n line-height: 1.4;\n margin: 0;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n/* ============================================\n Alert Messages\n ============================================ */\n\n.alert {\n display: flex;\n align-items: flex-start;\n gap: 1rem;\n padding: 1rem 1.25rem;\n border-radius: var(--mj-radius-md);\n border: 1px solid;\n font-size: 0.875rem;\n line-height: 1.5;\n}\n\n.alert i {\n font-size: 1.25rem;\n flex-shrink: 0;\n margin-top: 0.125rem;\n}\n\n.alert > div {\n flex: 1;\n min-width: 0;\n}\n\n/* Error Alert (Red) */\n.alert-error {\n background: var(--mj-color-error-100);\n border-color: var(--mj-status-error);\n color: var(--mj-color-error-700);\n}\n\n.alert-error i {\n color: var(--mj-status-error);\n}\n\n/* ============================================\n Modal Footer (Buttons)\n ============================================ */\n\n.modal-footer {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: 1rem;\n padding: 1.5rem 2rem;\n background: var(--mj-bg-surface-sunken);\n border-top: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n/* ============================================\n Buttons\n ============================================ */\n\n.btn {\n padding: 0.75rem 1.5rem;\n font-size: 0.875rem;\n font-weight: 500;\n border-radius: var(--mj-radius-full);\n border: none;\n cursor: pointer;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 44px;\n font-family: inherit;\n text-transform: none;\n letter-spacing: 0.01em;\n}\n\n.btn:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n.btn:active:not(:disabled) {\n transform: scale(0.98);\n}\n\n.btn i {\n font-size: 1rem;\n}\n\n.btn i.fa-spinner {\n animation: spin 1s linear infinite;\n}\n\n@keyframes spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n\n/* Primary Button (MJ Blue - Dark Button) */\n.btn-primary {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.btn-primary:hover:not(:disabled) {\n background: var(--mj-brand-primary-light);\n box-shadow: var(--mj-shadow-md);\n}\n\n.btn-primary:disabled {\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n box-shadow: none;\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n/* Secondary Button (Light Button) */\n.btn-secondary {\n background: var(--mj-bg-page);\n color: var(--mj-brand-primary);\n border: 1px solid var(--mj-color-neutral-400);\n box-shadow: none;\n}\n\n.btn-secondary:hover:not(:disabled) {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n border-color: var(--mj-brand-primary);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.btn-secondary:disabled {\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n border-color: var(--mj-border-default);\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n/* ============================================\n Responsive Design\n ============================================ */\n\n@media (max-width: 768px) {\n .modal-backdrop {\n padding: 0;\n }\n\n .modal-dialog {\n max-width: 100%;\n max-height: 100vh;\n border-radius: 0;\n animation: slideInMobile 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n @keyframes slideInMobile {\n from {\n opacity: 0;\n transform: translateY(100%);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n }\n\n .modal-header {\n padding: 20px 16px;\n border-radius: 0;\n }\n\n .dialog-title {\n font-size: 1.25rem;\n }\n\n .dialog-subtitle {\n font-size: 0.8125rem;\n }\n\n .content-section {\n padding: 1.25rem 1rem;\n }\n\n .section-title {\n font-size: 1.125rem;\n }\n\n .modal-footer {\n padding: 1rem;\n flex-direction: column;\n }\n\n .btn {\n width: 100%;\n justify-content: center;\n }\n\n .roles-grid {\n grid-template-columns: 1fr;\n }\n}\n\n@media (max-width: 480px) {\n .modal-header {\n padding: 16px 12px;\n }\n\n .dialog-title {\n font-size: 1.125rem;\n gap: 0.5rem;\n }\n\n .dialog-title i {\n font-size: 1rem;\n }\n\n .dialog-subtitle {\n font-size: 0.75rem;\n margin-top: 0.25rem;\n }\n\n .content-section {\n padding: 1rem 0.75rem;\n }\n\n .section-title {\n font-size: 1rem;\n gap: 0.5rem;\n }\n\n .field-input,\n .field-select {\n padding: 0.75rem;\n font-size: 0.875rem;\n }\n\n .modal-footer {\n padding: 0.75rem;\n }\n\n .btn {\n padding: 0.625rem 1.25rem;\n font-size: 0.8125rem;\n }\n}\n\n/* ============================================\n Accessibility\n ============================================ */\n\n/* Focus Visible Styles */\n*:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n/* Reduced Motion Support */\n@media (prefers-reduced-motion: reduce) {\n *,\n *::before,\n *::after {\n animation-duration: 0.01ms !important;\n animation-iteration-count: 1 !important;\n transition-duration: 0.01ms !important;\n }\n}\n\n/* High Contrast Mode Support */\n@media (prefers-contrast: high) {\n .modal-dialog {\n border: 2px solid var(--mj-border-default);\n }\n\n .btn {\n border: 2px solid currentColor;\n }\n\n .field-input,\n .field-select {\n border-width: 3px;\n }\n\n .role-card {\n border-width: 2px;\n }\n}\n\n/* ============================================\n Print Styles\n ============================================ */\n\n@media print {\n .modal-backdrop {\n display: none;\n }\n}\n"], encapsulation: 2 });
|
|
465
|
+
} }, dependencies: [i1.ɵNgNoValidate, i1.NgSelectOption, i1.ɵNgSelectMultipleOption, i1.DefaultValueAccessor, i1.CheckboxControlValueAccessor, i1.SelectControlValueAccessor, i1.NgControlStatus, i1.NgControlStatusGroup, i1.FormGroupDirective, i1.FormControlName], styles: ["/* ============================================\n User Dialog Component\n Uses MJ Design Tokens (--mj-*)\n ============================================ */\n\n/* ============================================\n Modal Backdrop & Container\n ============================================ */\n\n.modal-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n backdrop-filter: blur(4px);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1050;\n padding: 1rem;\n animation: fadeIn 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n.modal-dialog {\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-2xl);\n box-shadow: var(--mj-shadow-2xl);\n width: 100%;\n max-width: 900px;\n max-height: calc(100vh - 2rem);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n animation: slideIn 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n@keyframes slideIn {\n from {\n opacity: 0;\n transform: scale(0.95) translateY(20px);\n }\n to {\n opacity: 1;\n transform: scale(1) translateY(0);\n }\n}\n\n/* ============================================\n Modal Header (MJ Blue)\n ============================================ */\n\n.modal-header {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n padding: 24px 32px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 1rem;\n border-radius: var(--mj-radius-2xl) var(--mj-radius-2xl) 0 0;\n flex-shrink: 0;\n}\n\n.dialog-header {\n flex: 1;\n min-width: 0;\n}\n\n.dialog-title {\n margin: 0;\n font-size: 1.5rem;\n font-weight: 600;\n line-height: 1.3;\n display: flex;\n align-items: center;\n gap: 0.75rem;\n color: var(--mj-brand-on-primary);\n}\n\n.dialog-title i {\n font-size: 1.25rem;\n opacity: 0.95;\n}\n\n.dialog-subtitle {\n margin: 0.5rem 0 0 0;\n font-size: 0.875rem;\n opacity: 0.9;\n font-weight: 400;\n line-height: 1.4;\n}\n\n.modal-close {\n background: transparent;\n border: none;\n color: var(--mj-brand-on-primary);\n cursor: pointer;\n padding: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: var(--mj-radius-full);\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n width: 40px;\n height: 40px;\n flex-shrink: 0;\n}\n\n.modal-close:hover {\n background: rgba(255, 255, 255, 0.1);\n}\n\n.modal-close:active {\n background: rgba(255, 255, 255, 0.2);\n transform: scale(0.95);\n}\n\n.modal-close i {\n font-size: 1.25rem;\n}\n\n/* ============================================\n Modal Body\n ============================================ */\n\n.modal-body {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n padding: 0;\n background: var(--mj-bg-page);\n}\n\n.modal-body::-webkit-scrollbar {\n width: 8px;\n}\n\n.modal-body::-webkit-scrollbar-track {\n background: var(--mj-bg-surface-sunken);\n}\n\n.modal-body::-webkit-scrollbar-thumb {\n background: var(--mj-border-default);\n border-radius: var(--mj-radius-full);\n}\n\n.modal-body::-webkit-scrollbar-thumb:hover {\n background: var(--mj-color-neutral-400);\n}\n\n/* ============================================\n Form Structure\n ============================================ */\n\n.content-section {\n padding: 1.5rem 2rem;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.content-section:last-child {\n border-bottom: none;\n}\n\n.form-section {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n.section-header {\n margin-bottom: 1rem;\n}\n\n.section-title {\n margin: 0 0 0.5rem 0;\n font-size: 1.375rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 0.75rem;\n}\n\n.section-title i {\n font-size: 1.25rem;\n color: var(--mj-brand-primary);\n}\n\n.section-description {\n margin: 0;\n font-size: 0.875rem;\n color: var(--mj-text-secondary);\n line-height: 1.5;\n}\n\n/* ============================================\n Form Grid Layout\n ============================================ */\n\n.form-grid {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n.form-row {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 1.5rem;\n}\n\n@media (max-width: 640px) {\n .form-row {\n grid-template-columns: 1fr;\n gap: 1.5rem;\n }\n}\n\n/* ============================================\n Form Fields\n ============================================ */\n\n.form-field {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.field-label {\n font-size: 0.875rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 0.25rem;\n}\n\n.field-label.required::after {\n content: '*';\n color: var(--mj-status-error);\n margin-left: 0.25rem;\n}\n\n.field-input,\n.field-select {\n border: 2px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n padding: 0.875rem 1rem;\n font-size: 1rem;\n font-family: inherit;\n color: var(--mj-text-primary);\n background: var(--mj-bg-page);\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n width: 100%;\n box-sizing: border-box;\n}\n\n.field-input:hover:not(:disabled),\n.field-select:hover:not(:disabled) {\n border-color: var(--mj-color-neutral-400);\n}\n\n.field-input:focus,\n.field-select:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px rgba(0, 118, 182, 0.2);\n}\n\n.field-input:disabled,\n.field-select:disabled {\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n cursor: not-allowed;\n opacity: 0.6;\n}\n\n.field-input.error,\n.field-select.error {\n border-color: var(--mj-status-error);\n}\n\n.field-input.error:focus,\n.field-select.error:focus {\n box-shadow: 0 0 0 3px rgba(211, 47, 47, 0.2);\n}\n\n.field-input::placeholder,\n.field-select::placeholder {\n color: var(--mj-text-secondary);\n}\n\n/* Select Dropdown Styling */\n.field-select {\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%2379747E' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3e%3c/svg%3e\");\n background-position: right 16px center;\n background-repeat: no-repeat;\n background-size: 16px;\n padding-right: calc(16px + 32px);\n appearance: none;\n cursor: pointer;\n}\n\n.field-error {\n font-size: 0.75rem;\n color: var(--mj-status-error);\n display: flex;\n align-items: center;\n gap: 0.5rem;\n margin-top: 0.25rem;\n}\n\n.field-error i {\n font-size: 0.875rem;\n}\n\n/* ============================================\n Checkboxes\n ============================================ */\n\n.checkbox-field {\n display: flex;\n align-items: flex-start;\n gap: 0.75rem;\n cursor: pointer;\n margin-bottom: 0;\n}\n\n.checkbox-input {\n position: absolute;\n opacity: 0;\n cursor: pointer;\n}\n\n.checkbox-label {\n display: flex;\n align-items: flex-start;\n gap: 0.75rem;\n cursor: pointer;\n font-size: 0.875rem;\n color: var(--mj-text-primary);\n line-height: 1.4;\n margin: 0;\n flex: 1;\n}\n\n.checkbox-indicator {\n width: 20px;\n height: 20px;\n border: 2px solid var(--mj-color-neutral-400);\n border-radius: var(--mj-radius-sm);\n background: var(--mj-bg-page);\n flex-shrink: 0;\n position: relative;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n margin-top: 2px;\n}\n\n.checkbox-indicator::after {\n content: '';\n position: absolute;\n left: 6px;\n top: 2px;\n width: 4px;\n height: 8px;\n border: solid var(--mj-brand-on-primary);\n border-width: 0 2px 2px 0;\n opacity: 0;\n transform: rotate(45deg) scale(0.8);\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.checkbox-input:checked + .checkbox-label .checkbox-indicator {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.checkbox-input:checked + .checkbox-label .checkbox-indicator::after {\n opacity: 1;\n transform: rotate(45deg) scale(1);\n}\n\n.checkbox-input:focus + .checkbox-label .checkbox-indicator {\n box-shadow: 0 0 0 3px rgba(0, 118, 182, 0.2);\n}\n\n.checkbox-label strong {\n display: block;\n font-weight: 600;\n margin-bottom: 0.125rem;\n}\n\n/* ============================================\n Role Cards\n ============================================ */\n\n.roles-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));\n gap: 1rem;\n}\n\n@media (max-width: 640px) {\n .roles-grid {\n grid-template-columns: 1fr;\n }\n}\n\n.role-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n padding: 1.25rem;\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n display: flex;\n flex-direction: column;\n}\n\n.role-card:hover {\n border-color: var(--mj-brand-primary);\n box-shadow: var(--mj-shadow-md);\n transform: translateY(-2px);\n}\n\n.role-card.selected {\n background: var(--mj-brand-accent-subtle);\n border-color: var(--mj-brand-primary);\n box-shadow: var(--mj-shadow-md);\n}\n\n.role-content {\n display: flex;\n align-items: flex-start;\n gap: 1rem;\n}\n\n.role-info {\n flex: 1;\n min-width: 0;\n}\n\n.role-name {\n font-size: 1rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0 0 0.25rem 0;\n line-height: 1.3;\n}\n\n.role-description {\n font-size: 0.75rem;\n color: var(--mj-text-secondary);\n line-height: 1.4;\n margin: 0;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n/* ============================================\n Alert Messages\n ============================================ */\n\n.alert {\n display: flex;\n align-items: flex-start;\n gap: 1rem;\n padding: 1rem 1.25rem;\n border-radius: var(--mj-radius-md);\n border: 1px solid;\n font-size: 0.875rem;\n line-height: 1.5;\n}\n\n.alert i {\n font-size: 1.25rem;\n flex-shrink: 0;\n margin-top: 0.125rem;\n}\n\n.alert > div {\n flex: 1;\n min-width: 0;\n}\n\n/* Error Alert (Red) */\n.alert-error {\n background: var(--mj-color-error-100);\n border-color: var(--mj-status-error);\n color: var(--mj-status-error);\n}\n\n.alert-error i {\n color: var(--mj-status-error);\n}\n\n/* ============================================\n Modal Footer (Buttons)\n ============================================ */\n\n.modal-footer {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: 1rem;\n padding: 1.5rem 2rem;\n background: var(--mj-bg-surface-sunken);\n border-top: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n/* ============================================\n Buttons\n ============================================ */\n\n.btn {\n padding: 0.75rem 1.5rem;\n font-size: 0.875rem;\n font-weight: 500;\n border-radius: var(--mj-radius-full);\n border: none;\n cursor: pointer;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 44px;\n font-family: inherit;\n text-transform: none;\n letter-spacing: 0.01em;\n}\n\n.btn:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n.btn:active:not(:disabled) {\n transform: scale(0.98);\n}\n\n.btn i {\n font-size: 1rem;\n}\n\n.btn i.fa-spinner {\n animation: spin 1s linear infinite;\n}\n\n@keyframes spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n\n/* Primary Button (MJ Blue - Dark Button) */\n.btn-primary {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.btn-primary:hover:not(:disabled) {\n background: var(--mj-brand-primary-light);\n box-shadow: var(--mj-shadow-md);\n}\n\n.btn-primary:disabled {\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n box-shadow: none;\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n/* Secondary Button (Light Button) */\n.btn-secondary {\n background: var(--mj-bg-page);\n color: var(--mj-brand-primary);\n border: 1px solid var(--mj-color-neutral-400);\n box-shadow: none;\n}\n\n.btn-secondary:hover:not(:disabled) {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n border-color: var(--mj-brand-primary);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.btn-secondary:disabled {\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n border-color: var(--mj-border-default);\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n/* ============================================\n Responsive Design\n ============================================ */\n\n@media (max-width: 768px) {\n .modal-backdrop {\n padding: 0;\n }\n\n .modal-dialog {\n max-width: 100%;\n max-height: 100vh;\n border-radius: 0;\n animation: slideInMobile 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n @keyframes slideInMobile {\n from {\n opacity: 0;\n transform: translateY(100%);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n }\n\n .modal-header {\n padding: 20px 16px;\n border-radius: 0;\n }\n\n .dialog-title {\n font-size: 1.25rem;\n }\n\n .dialog-subtitle {\n font-size: 0.8125rem;\n }\n\n .content-section {\n padding: 1.25rem 1rem;\n }\n\n .section-title {\n font-size: 1.125rem;\n }\n\n .modal-footer {\n padding: 1rem;\n flex-direction: column;\n }\n\n .btn {\n width: 100%;\n justify-content: center;\n }\n\n .roles-grid {\n grid-template-columns: 1fr;\n }\n}\n\n@media (max-width: 480px) {\n .modal-header {\n padding: 16px 12px;\n }\n\n .dialog-title {\n font-size: 1.125rem;\n gap: 0.5rem;\n }\n\n .dialog-title i {\n font-size: 1rem;\n }\n\n .dialog-subtitle {\n font-size: 0.75rem;\n margin-top: 0.25rem;\n }\n\n .content-section {\n padding: 1rem 0.75rem;\n }\n\n .section-title {\n font-size: 1rem;\n gap: 0.5rem;\n }\n\n .field-input,\n .field-select {\n padding: 0.75rem;\n font-size: 0.875rem;\n }\n\n .modal-footer {\n padding: 0.75rem;\n }\n\n .btn {\n padding: 0.625rem 1.25rem;\n font-size: 0.8125rem;\n }\n}\n\n/* ============================================\n Accessibility\n ============================================ */\n\n/* Focus Visible Styles */\n*:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n/* Reduced Motion Support */\n@media (prefers-reduced-motion: reduce) {\n *,\n *::before,\n *::after {\n animation-duration: 0.01ms !important;\n animation-iteration-count: 1 !important;\n transition-duration: 0.01ms !important;\n }\n}\n\n/* High Contrast Mode Support */\n@media (prefers-contrast: high) {\n .modal-dialog {\n border: 2px solid var(--mj-border-default);\n }\n\n .btn {\n border: 2px solid currentColor;\n }\n\n .field-input,\n .field-select {\n border-width: 3px;\n }\n\n .role-card {\n border-width: 2px;\n }\n}\n\n/* ============================================\n Print Styles\n ============================================ */\n\n@media print {\n .modal-backdrop {\n display: none;\n }\n}\n"], encapsulation: 2 });
|
|
466
466
|
}
|
|
467
467
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(UserDialogComponent, [{
|
|
468
468
|
type: Component,
|
|
469
|
-
args: [{ standalone: false, selector: 'mj-user-dialog', encapsulation: ViewEncapsulation.None, template: "<!-- MD3 Modal Dialog -->\n@if (visible) {\n <div class=\"modal-backdrop\" (click)=\"onCancel()\">\n <div class=\"modal-dialog\" (click)=\"$event.stopPropagation()\">\n <!-- Modal Header with MJ Blue -->\n <div class=\"modal-header\">\n <div class=\"dialog-header\">\n <h2 class=\"dialog-title\">\n <i class=\"fa-solid fa-user\"></i>\n {{ isEditMode ? 'Edit User' : 'Create New User' }}\n </h2>\n <p class=\"dialog-subtitle\">\n {{ isEditMode ? 'Update user information and role assignments' : 'Add a new user to the system' }}\n </p>\n </div>\n <button type=\"button\" class=\"modal-close\" (click)=\"onCancel()\" aria-label=\"Close dialog\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n <!-- Modal Body -->\n <div class=\"modal-body\">\n <form [formGroup]=\"userForm\" (ngSubmit)=\"onSubmit()\">\n @if (error) {\n <div class=\"content-section\">\n <div class=\"alert alert-error\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n <div>{{ error }}</div>\n </div>\n </div>\n }\n <!-- Basic Information Section -->\n <div class=\"content-section\">\n <div class=\"form-section\">\n <div class=\"section-header\">\n <h3 class=\"section-title\">\n <i class=\"fa-solid fa-id-card\"></i>\n Basic Information\n </h3>\n <p class=\"section-description\">Enter the user's personal and contact details</p>\n </div>\n <div class=\"form-grid\">\n <div class=\"form-field\">\n <label class=\"field-label required\" for=\"name\">Username/Email</label>\n <input\n id=\"name\"\n type=\"email\"\n class=\"field-input\"\n formControlName=\"name\"\n placeholder=\"john@company.com\"\n [class.error]=\"userForm.get('name')?.invalid && userForm.get('name')?.touched\"\n />\n @if (userForm.get('name')?.invalid && userForm.get('name')?.touched) {\n <div class=\"field-error\">\n <i class=\"fa-solid fa-exclamation-circle\"></i>\n @if (userForm.get('name')?.errors?.['required']) {\n Username/Email is required\n }\n @if (userForm.get('name')?.errors?.['email']) {\n Please enter a valid email address\n }\n </div>\n }\n </div>\n <div class=\"form-row\">\n <div class=\"form-field\">\n <label class=\"field-label\" for=\"firstName\">First Name</label>\n <input\n id=\"firstName\"\n type=\"text\"\n class=\"field-input\"\n formControlName=\"firstName\"\n placeholder=\"John\"\n />\n </div>\n <div class=\"form-field\">\n <label class=\"field-label\" for=\"lastName\">Last Name</label>\n <input\n id=\"lastName\"\n type=\"text\"\n class=\"field-input\"\n formControlName=\"lastName\"\n placeholder=\"Doe\"\n />\n </div>\n </div>\n <div class=\"form-field\">\n <label class=\"field-label required\" for=\"email\">Email Address</label>\n <input\n id=\"email\"\n type=\"email\"\n class=\"field-input\"\n formControlName=\"email\"\n placeholder=\"john@company.com\"\n [class.error]=\"userForm.get('email')?.invalid && userForm.get('email')?.touched\"\n />\n @if (userForm.get('email')?.invalid && userForm.get('email')?.touched) {\n <div class=\"field-error\">\n <i class=\"fa-solid fa-exclamation-circle\"></i>\n @if (userForm.get('email')?.errors?.['required']) {\n Email address is required\n }\n @if (userForm.get('email')?.errors?.['email']) {\n Please enter a valid email address\n }\n </div>\n }\n </div>\n <div class=\"form-field\">\n <label class=\"field-label\" for=\"title\">Job Title</label>\n <input\n id=\"title\"\n type=\"text\"\n class=\"field-input\"\n formControlName=\"title\"\n placeholder=\"Software Engineer\"\n />\n </div>\n </div>\n </div>\n </div>\n <!-- User Settings Section -->\n <div class=\"content-section\">\n <div class=\"form-section\">\n <div class=\"section-header\">\n <h3 class=\"section-title\">\n <i class=\"fa-solid fa-cog\"></i>\n User Settings\n </h3>\n <p class=\"section-description\">Configure user type and account status</p>\n </div>\n <div class=\"form-grid\">\n <div class=\"form-row\">\n <div class=\"form-field\">\n <label class=\"field-label\" for=\"type\">User Type</label>\n <select id=\"type\" class=\"field-select\" formControlName=\"type\">\n <option value=\"User\">Standard User</option>\n <option value=\"Owner\">System Owner</option>\n </select>\n </div>\n <div class=\"form-field\">\n <div class=\"checkbox-field\">\n <input\n id=\"isActive\"\n type=\"checkbox\"\n class=\"checkbox-input\"\n formControlName=\"isActive\"\n />\n <label class=\"checkbox-label\" for=\"isActive\">\n <div class=\"checkbox-indicator\"></div>\n <div>\n <strong>Active Account</strong>\n <div style=\"font-size: 12px; color: var(--md-on-surface-variant); margin-top: 2px;\">\n User can log in and access the system\n </div>\n </div>\n </label>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n <!-- Role Assignment Section -->\n <div class=\"content-section\">\n <div class=\"form-section\">\n <div class=\"section-header\">\n <h3 class=\"section-title\">\n <i class=\"fa-solid fa-user-tag\"></i>\n Role Assignment\n </h3>\n <p class=\"section-description\">Select the roles to assign to this user</p>\n </div>\n <div class=\"roles-grid\">\n @for (role of data?.availableRoles; track role.ID) {\n <div class=\"role-card\"\n [class.selected]=\"selectedRoleIds.has(role.ID)\"\n (click)=\"toggleRole(role.ID)\">\n <div class=\"role-content\">\n <div class=\"checkbox-field\">\n <input\n type=\"checkbox\"\n class=\"checkbox-input\"\n [id]=\"'role-' + role.ID\"\n [checked]=\"selectedRoleIds.has(role.ID)\"\n (change)=\"onRoleToggle(role.ID, $event)\"\n />\n <label class=\"checkbox-label\" [for]=\"'role-' + role.ID\">\n <div class=\"checkbox-indicator\"></div>\n </label>\n </div>\n <div class=\"role-info\">\n <h4 class=\"role-name\">{{ role.Name }}</h4>\n @if (role.Description) {\n <p class=\"role-description\">{{ role.Description }}</p>\n }\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n <!-- Modal Footer -->\n <div class=\"modal-footer\">\n <button\n type=\"submit\"\n class=\"btn btn-primary\"\n [disabled]=\"userForm.invalid || isLoading\"\n >\n @if (isLoading) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n Saving...\n } @else {\n <i class=\"fa-solid fa-save\"></i>\n {{ isEditMode ? 'Update User' : 'Create User' }}\n }\n </button>\n <button type=\"button\" class=\"btn btn-secondary\" (click)=\"onCancel()\">\n <i class=\"fa-solid fa-times\"></i>\n Cancel\n </button>\n </div>\n </form>\n </div>\n </div>\n </div>\n}\n", styles: ["/* ============================================\n User Dialog Component\n Uses MJ Design Tokens (--mj-*)\n ============================================ */\n\n/* ============================================\n Modal Backdrop & Container\n ============================================ */\n\n.modal-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n backdrop-filter: blur(4px);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1050;\n padding: 1rem;\n animation: fadeIn 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n.modal-dialog {\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-2xl);\n box-shadow: var(--mj-shadow-2xl);\n width: 100%;\n max-width: 900px;\n max-height: calc(100vh - 2rem);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n animation: slideIn 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n@keyframes slideIn {\n from {\n opacity: 0;\n transform: scale(0.95) translateY(20px);\n }\n to {\n opacity: 1;\n transform: scale(1) translateY(0);\n }\n}\n\n/* ============================================\n Modal Header (MJ Blue)\n ============================================ */\n\n.modal-header {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n padding: 24px 32px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 1rem;\n border-radius: var(--mj-radius-2xl) var(--mj-radius-2xl) 0 0;\n flex-shrink: 0;\n}\n\n.dialog-header {\n flex: 1;\n min-width: 0;\n}\n\n.dialog-title {\n margin: 0;\n font-size: 1.5rem;\n font-weight: 600;\n line-height: 1.3;\n display: flex;\n align-items: center;\n gap: 0.75rem;\n color: var(--mj-brand-on-primary);\n}\n\n.dialog-title i {\n font-size: 1.25rem;\n opacity: 0.95;\n}\n\n.dialog-subtitle {\n margin: 0.5rem 0 0 0;\n font-size: 0.875rem;\n opacity: 0.9;\n font-weight: 400;\n line-height: 1.4;\n}\n\n.modal-close {\n background: transparent;\n border: none;\n color: var(--mj-brand-on-primary);\n cursor: pointer;\n padding: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: var(--mj-radius-full);\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n width: 40px;\n height: 40px;\n flex-shrink: 0;\n}\n\n.modal-close:hover {\n background: rgba(255, 255, 255, 0.1);\n}\n\n.modal-close:active {\n background: rgba(255, 255, 255, 0.2);\n transform: scale(0.95);\n}\n\n.modal-close i {\n font-size: 1.25rem;\n}\n\n/* ============================================\n Modal Body\n ============================================ */\n\n.modal-body {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n padding: 0;\n background: var(--mj-bg-page);\n}\n\n.modal-body::-webkit-scrollbar {\n width: 8px;\n}\n\n.modal-body::-webkit-scrollbar-track {\n background: var(--mj-bg-surface-sunken);\n}\n\n.modal-body::-webkit-scrollbar-thumb {\n background: var(--mj-border-default);\n border-radius: var(--mj-radius-full);\n}\n\n.modal-body::-webkit-scrollbar-thumb:hover {\n background: var(--mj-color-neutral-400);\n}\n\n/* ============================================\n Form Structure\n ============================================ */\n\n.content-section {\n padding: 1.5rem 2rem;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.content-section:last-child {\n border-bottom: none;\n}\n\n.form-section {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n.section-header {\n margin-bottom: 1rem;\n}\n\n.section-title {\n margin: 0 0 0.5rem 0;\n font-size: 1.375rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 0.75rem;\n}\n\n.section-title i {\n font-size: 1.25rem;\n color: var(--mj-brand-primary);\n}\n\n.section-description {\n margin: 0;\n font-size: 0.875rem;\n color: var(--mj-text-secondary);\n line-height: 1.5;\n}\n\n/* ============================================\n Form Grid Layout\n ============================================ */\n\n.form-grid {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n.form-row {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 1.5rem;\n}\n\n@media (max-width: 640px) {\n .form-row {\n grid-template-columns: 1fr;\n gap: 1.5rem;\n }\n}\n\n/* ============================================\n Form Fields\n ============================================ */\n\n.form-field {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.field-label {\n font-size: 0.875rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 0.25rem;\n}\n\n.field-label.required::after {\n content: '*';\n color: var(--mj-status-error);\n margin-left: 0.25rem;\n}\n\n.field-input,\n.field-select {\n border: 2px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n padding: 0.875rem 1rem;\n font-size: 1rem;\n font-family: inherit;\n color: var(--mj-text-primary);\n background: var(--mj-bg-page);\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n width: 100%;\n box-sizing: border-box;\n}\n\n.field-input:hover:not(:disabled),\n.field-select:hover:not(:disabled) {\n border-color: var(--mj-color-neutral-400);\n}\n\n.field-input:focus,\n.field-select:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px rgba(0, 118, 182, 0.2);\n}\n\n.field-input:disabled,\n.field-select:disabled {\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n cursor: not-allowed;\n opacity: 0.6;\n}\n\n.field-input.error,\n.field-select.error {\n border-color: var(--mj-status-error);\n}\n\n.field-input.error:focus,\n.field-select.error:focus {\n box-shadow: 0 0 0 3px rgba(211, 47, 47, 0.2);\n}\n\n.field-input::placeholder,\n.field-select::placeholder {\n color: var(--mj-text-secondary);\n}\n\n/* Select Dropdown Styling */\n.field-select {\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%2379747E' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3e%3c/svg%3e\");\n background-position: right 16px center;\n background-repeat: no-repeat;\n background-size: 16px;\n padding-right: calc(16px + 32px);\n appearance: none;\n cursor: pointer;\n}\n\n.field-error {\n font-size: 0.75rem;\n color: var(--mj-status-error);\n display: flex;\n align-items: center;\n gap: 0.5rem;\n margin-top: 0.25rem;\n}\n\n.field-error i {\n font-size: 0.875rem;\n}\n\n/* ============================================\n Checkboxes\n ============================================ */\n\n.checkbox-field {\n display: flex;\n align-items: flex-start;\n gap: 0.75rem;\n cursor: pointer;\n margin-bottom: 0;\n}\n\n.checkbox-input {\n position: absolute;\n opacity: 0;\n cursor: pointer;\n}\n\n.checkbox-label {\n display: flex;\n align-items: flex-start;\n gap: 0.75rem;\n cursor: pointer;\n font-size: 0.875rem;\n color: var(--mj-text-primary);\n line-height: 1.4;\n margin: 0;\n flex: 1;\n}\n\n.checkbox-indicator {\n width: 20px;\n height: 20px;\n border: 2px solid var(--mj-color-neutral-400);\n border-radius: var(--mj-radius-sm);\n background: var(--mj-bg-page);\n flex-shrink: 0;\n position: relative;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n margin-top: 2px;\n}\n\n.checkbox-indicator::after {\n content: '';\n position: absolute;\n left: 6px;\n top: 2px;\n width: 4px;\n height: 8px;\n border: solid var(--mj-brand-on-primary);\n border-width: 0 2px 2px 0;\n opacity: 0;\n transform: rotate(45deg) scale(0.8);\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.checkbox-input:checked + .checkbox-label .checkbox-indicator {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.checkbox-input:checked + .checkbox-label .checkbox-indicator::after {\n opacity: 1;\n transform: rotate(45deg) scale(1);\n}\n\n.checkbox-input:focus + .checkbox-label .checkbox-indicator {\n box-shadow: 0 0 0 3px rgba(0, 118, 182, 0.2);\n}\n\n.checkbox-label strong {\n display: block;\n font-weight: 600;\n margin-bottom: 0.125rem;\n}\n\n/* ============================================\n Role Cards\n ============================================ */\n\n.roles-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));\n gap: 1rem;\n}\n\n@media (max-width: 640px) {\n .roles-grid {\n grid-template-columns: 1fr;\n }\n}\n\n.role-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n padding: 1.25rem;\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n display: flex;\n flex-direction: column;\n}\n\n.role-card:hover {\n border-color: var(--mj-brand-primary);\n box-shadow: var(--mj-shadow-md);\n transform: translateY(-2px);\n}\n\n.role-card.selected {\n background: var(--mj-brand-accent-subtle);\n border-color: var(--mj-brand-primary);\n box-shadow: var(--mj-shadow-md);\n}\n\n.role-content {\n display: flex;\n align-items: flex-start;\n gap: 1rem;\n}\n\n.role-info {\n flex: 1;\n min-width: 0;\n}\n\n.role-name {\n font-size: 1rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0 0 0.25rem 0;\n line-height: 1.3;\n}\n\n.role-description {\n font-size: 0.75rem;\n color: var(--mj-text-secondary);\n line-height: 1.4;\n margin: 0;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n/* ============================================\n Alert Messages\n ============================================ */\n\n.alert {\n display: flex;\n align-items: flex-start;\n gap: 1rem;\n padding: 1rem 1.25rem;\n border-radius: var(--mj-radius-md);\n border: 1px solid;\n font-size: 0.875rem;\n line-height: 1.5;\n}\n\n.alert i {\n font-size: 1.25rem;\n flex-shrink: 0;\n margin-top: 0.125rem;\n}\n\n.alert > div {\n flex: 1;\n min-width: 0;\n}\n\n/* Error Alert (Red) */\n.alert-error {\n background: var(--mj-color-error-100);\n border-color: var(--mj-status-error);\n color: var(--mj-color-error-700);\n}\n\n.alert-error i {\n color: var(--mj-status-error);\n}\n\n/* ============================================\n Modal Footer (Buttons)\n ============================================ */\n\n.modal-footer {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: 1rem;\n padding: 1.5rem 2rem;\n background: var(--mj-bg-surface-sunken);\n border-top: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n/* ============================================\n Buttons\n ============================================ */\n\n.btn {\n padding: 0.75rem 1.5rem;\n font-size: 0.875rem;\n font-weight: 500;\n border-radius: var(--mj-radius-full);\n border: none;\n cursor: pointer;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 44px;\n font-family: inherit;\n text-transform: none;\n letter-spacing: 0.01em;\n}\n\n.btn:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n.btn:active:not(:disabled) {\n transform: scale(0.98);\n}\n\n.btn i {\n font-size: 1rem;\n}\n\n.btn i.fa-spinner {\n animation: spin 1s linear infinite;\n}\n\n@keyframes spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n\n/* Primary Button (MJ Blue - Dark Button) */\n.btn-primary {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.btn-primary:hover:not(:disabled) {\n background: var(--mj-brand-primary-light);\n box-shadow: var(--mj-shadow-md);\n}\n\n.btn-primary:disabled {\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n box-shadow: none;\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n/* Secondary Button (Light Button) */\n.btn-secondary {\n background: var(--mj-bg-page);\n color: var(--mj-brand-primary);\n border: 1px solid var(--mj-color-neutral-400);\n box-shadow: none;\n}\n\n.btn-secondary:hover:not(:disabled) {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n border-color: var(--mj-brand-primary);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.btn-secondary:disabled {\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n border-color: var(--mj-border-default);\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n/* ============================================\n Responsive Design\n ============================================ */\n\n@media (max-width: 768px) {\n .modal-backdrop {\n padding: 0;\n }\n\n .modal-dialog {\n max-width: 100%;\n max-height: 100vh;\n border-radius: 0;\n animation: slideInMobile 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n @keyframes slideInMobile {\n from {\n opacity: 0;\n transform: translateY(100%);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n }\n\n .modal-header {\n padding: 20px 16px;\n border-radius: 0;\n }\n\n .dialog-title {\n font-size: 1.25rem;\n }\n\n .dialog-subtitle {\n font-size: 0.8125rem;\n }\n\n .content-section {\n padding: 1.25rem 1rem;\n }\n\n .section-title {\n font-size: 1.125rem;\n }\n\n .modal-footer {\n padding: 1rem;\n flex-direction: column;\n }\n\n .btn {\n width: 100%;\n justify-content: center;\n }\n\n .roles-grid {\n grid-template-columns: 1fr;\n }\n}\n\n@media (max-width: 480px) {\n .modal-header {\n padding: 16px 12px;\n }\n\n .dialog-title {\n font-size: 1.125rem;\n gap: 0.5rem;\n }\n\n .dialog-title i {\n font-size: 1rem;\n }\n\n .dialog-subtitle {\n font-size: 0.75rem;\n margin-top: 0.25rem;\n }\n\n .content-section {\n padding: 1rem 0.75rem;\n }\n\n .section-title {\n font-size: 1rem;\n gap: 0.5rem;\n }\n\n .field-input,\n .field-select {\n padding: 0.75rem;\n font-size: 0.875rem;\n }\n\n .modal-footer {\n padding: 0.75rem;\n }\n\n .btn {\n padding: 0.625rem 1.25rem;\n font-size: 0.8125rem;\n }\n}\n\n/* ============================================\n Accessibility\n ============================================ */\n\n/* Focus Visible Styles */\n*:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n/* Reduced Motion Support */\n@media (prefers-reduced-motion: reduce) {\n *,\n *::before,\n *::after {\n animation-duration: 0.01ms !important;\n animation-iteration-count: 1 !important;\n transition-duration: 0.01ms !important;\n }\n}\n\n/* High Contrast Mode Support */\n@media (prefers-contrast: high) {\n .modal-dialog {\n border: 2px solid var(--mj-border-default);\n }\n\n .btn {\n border: 2px solid currentColor;\n }\n\n .field-input,\n .field-select {\n border-width: 3px;\n }\n\n .role-card {\n border-width: 2px;\n }\n}\n\n/* ============================================\n Print Styles\n ============================================ */\n\n@media print {\n .modal-backdrop {\n display: none;\n }\n}\n"] }]
|
|
469
|
+
args: [{ standalone: false, selector: 'mj-user-dialog', encapsulation: ViewEncapsulation.None, template: "<!-- MD3 Modal Dialog -->\n@if (visible) {\n <div class=\"modal-backdrop\" (click)=\"onCancel()\">\n <div class=\"modal-dialog\" (click)=\"$event.stopPropagation()\">\n <!-- Modal Header with MJ Blue -->\n <div class=\"modal-header\">\n <div class=\"dialog-header\">\n <h2 class=\"dialog-title\">\n <i class=\"fa-solid fa-user\"></i>\n {{ isEditMode ? 'Edit User' : 'Create New User' }}\n </h2>\n <p class=\"dialog-subtitle\">\n {{ isEditMode ? 'Update user information and role assignments' : 'Add a new user to the system' }}\n </p>\n </div>\n <button type=\"button\" class=\"modal-close\" (click)=\"onCancel()\" aria-label=\"Close dialog\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n <!-- Modal Body -->\n <div class=\"modal-body\">\n <form [formGroup]=\"userForm\" (ngSubmit)=\"onSubmit()\">\n @if (error) {\n <div class=\"content-section\">\n <div class=\"alert alert-error\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n <div>{{ error }}</div>\n </div>\n </div>\n }\n <!-- Basic Information Section -->\n <div class=\"content-section\">\n <div class=\"form-section\">\n <div class=\"section-header\">\n <h3 class=\"section-title\">\n <i class=\"fa-solid fa-id-card\"></i>\n Basic Information\n </h3>\n <p class=\"section-description\">Enter the user's personal and contact details</p>\n </div>\n <div class=\"form-grid\">\n <div class=\"form-field\">\n <label class=\"field-label required\" for=\"name\">Username/Email</label>\n <input\n id=\"name\"\n type=\"email\"\n class=\"field-input\"\n formControlName=\"name\"\n placeholder=\"john@company.com\"\n [class.error]=\"userForm.get('name')?.invalid && userForm.get('name')?.touched\"\n />\n @if (userForm.get('name')?.invalid && userForm.get('name')?.touched) {\n <div class=\"field-error\">\n <i class=\"fa-solid fa-exclamation-circle\"></i>\n @if (userForm.get('name')?.errors?.['required']) {\n Username/Email is required\n }\n @if (userForm.get('name')?.errors?.['email']) {\n Please enter a valid email address\n }\n </div>\n }\n </div>\n <div class=\"form-row\">\n <div class=\"form-field\">\n <label class=\"field-label\" for=\"firstName\">First Name</label>\n <input\n id=\"firstName\"\n type=\"text\"\n class=\"field-input\"\n formControlName=\"firstName\"\n placeholder=\"John\"\n />\n </div>\n <div class=\"form-field\">\n <label class=\"field-label\" for=\"lastName\">Last Name</label>\n <input\n id=\"lastName\"\n type=\"text\"\n class=\"field-input\"\n formControlName=\"lastName\"\n placeholder=\"Doe\"\n />\n </div>\n </div>\n <div class=\"form-field\">\n <label class=\"field-label required\" for=\"email\">Email Address</label>\n <input\n id=\"email\"\n type=\"email\"\n class=\"field-input\"\n formControlName=\"email\"\n placeholder=\"john@company.com\"\n [class.error]=\"userForm.get('email')?.invalid && userForm.get('email')?.touched\"\n />\n @if (userForm.get('email')?.invalid && userForm.get('email')?.touched) {\n <div class=\"field-error\">\n <i class=\"fa-solid fa-exclamation-circle\"></i>\n @if (userForm.get('email')?.errors?.['required']) {\n Email address is required\n }\n @if (userForm.get('email')?.errors?.['email']) {\n Please enter a valid email address\n }\n </div>\n }\n </div>\n <div class=\"form-field\">\n <label class=\"field-label\" for=\"title\">Job Title</label>\n <input\n id=\"title\"\n type=\"text\"\n class=\"field-input\"\n formControlName=\"title\"\n placeholder=\"Software Engineer\"\n />\n </div>\n </div>\n </div>\n </div>\n <!-- User Settings Section -->\n <div class=\"content-section\">\n <div class=\"form-section\">\n <div class=\"section-header\">\n <h3 class=\"section-title\">\n <i class=\"fa-solid fa-cog\"></i>\n User Settings\n </h3>\n <p class=\"section-description\">Configure user type and account status</p>\n </div>\n <div class=\"form-grid\">\n <div class=\"form-row\">\n <div class=\"form-field\">\n <label class=\"field-label\" for=\"type\">User Type</label>\n <select id=\"type\" class=\"field-select\" formControlName=\"type\">\n <option value=\"User\">Standard User</option>\n <option value=\"Owner\">System Owner</option>\n </select>\n </div>\n <div class=\"form-field\">\n <div class=\"checkbox-field\">\n <input\n id=\"isActive\"\n type=\"checkbox\"\n class=\"checkbox-input\"\n formControlName=\"isActive\"\n />\n <label class=\"checkbox-label\" for=\"isActive\">\n <div class=\"checkbox-indicator\"></div>\n <div>\n <strong>Active Account</strong>\n <div style=\"font-size: 12px; color: var(--md-on-surface-variant); margin-top: 2px;\">\n User can log in and access the system\n </div>\n </div>\n </label>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n <!-- Role Assignment Section -->\n <div class=\"content-section\">\n <div class=\"form-section\">\n <div class=\"section-header\">\n <h3 class=\"section-title\">\n <i class=\"fa-solid fa-user-tag\"></i>\n Role Assignment\n </h3>\n <p class=\"section-description\">Select the roles to assign to this user</p>\n </div>\n <div class=\"roles-grid\">\n @for (role of data?.availableRoles; track role.ID) {\n <div class=\"role-card\"\n [class.selected]=\"selectedRoleIds.has(role.ID)\"\n (click)=\"toggleRole(role.ID)\">\n <div class=\"role-content\">\n <div class=\"checkbox-field\">\n <input\n type=\"checkbox\"\n class=\"checkbox-input\"\n [id]=\"'role-' + role.ID\"\n [checked]=\"selectedRoleIds.has(role.ID)\"\n (change)=\"onRoleToggle(role.ID, $event)\"\n />\n <label class=\"checkbox-label\" [for]=\"'role-' + role.ID\">\n <div class=\"checkbox-indicator\"></div>\n </label>\n </div>\n <div class=\"role-info\">\n <h4 class=\"role-name\">{{ role.Name }}</h4>\n @if (role.Description) {\n <p class=\"role-description\">{{ role.Description }}</p>\n }\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n <!-- Modal Footer -->\n <div class=\"modal-footer\">\n <button\n type=\"submit\"\n class=\"btn btn-primary\"\n [disabled]=\"userForm.invalid || isLoading\"\n >\n @if (isLoading) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n Saving...\n } @else {\n <i class=\"fa-solid fa-save\"></i>\n {{ isEditMode ? 'Update User' : 'Create User' }}\n }\n </button>\n <button type=\"button\" class=\"btn btn-secondary\" (click)=\"onCancel()\">\n <i class=\"fa-solid fa-times\"></i>\n Cancel\n </button>\n </div>\n </form>\n </div>\n </div>\n </div>\n}\n", styles: ["/* ============================================\n User Dialog Component\n Uses MJ Design Tokens (--mj-*)\n ============================================ */\n\n/* ============================================\n Modal Backdrop & Container\n ============================================ */\n\n.modal-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n backdrop-filter: blur(4px);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1050;\n padding: 1rem;\n animation: fadeIn 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n.modal-dialog {\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-2xl);\n box-shadow: var(--mj-shadow-2xl);\n width: 100%;\n max-width: 900px;\n max-height: calc(100vh - 2rem);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n animation: slideIn 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n@keyframes slideIn {\n from {\n opacity: 0;\n transform: scale(0.95) translateY(20px);\n }\n to {\n opacity: 1;\n transform: scale(1) translateY(0);\n }\n}\n\n/* ============================================\n Modal Header (MJ Blue)\n ============================================ */\n\n.modal-header {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n padding: 24px 32px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 1rem;\n border-radius: var(--mj-radius-2xl) var(--mj-radius-2xl) 0 0;\n flex-shrink: 0;\n}\n\n.dialog-header {\n flex: 1;\n min-width: 0;\n}\n\n.dialog-title {\n margin: 0;\n font-size: 1.5rem;\n font-weight: 600;\n line-height: 1.3;\n display: flex;\n align-items: center;\n gap: 0.75rem;\n color: var(--mj-brand-on-primary);\n}\n\n.dialog-title i {\n font-size: 1.25rem;\n opacity: 0.95;\n}\n\n.dialog-subtitle {\n margin: 0.5rem 0 0 0;\n font-size: 0.875rem;\n opacity: 0.9;\n font-weight: 400;\n line-height: 1.4;\n}\n\n.modal-close {\n background: transparent;\n border: none;\n color: var(--mj-brand-on-primary);\n cursor: pointer;\n padding: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: var(--mj-radius-full);\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n width: 40px;\n height: 40px;\n flex-shrink: 0;\n}\n\n.modal-close:hover {\n background: rgba(255, 255, 255, 0.1);\n}\n\n.modal-close:active {\n background: rgba(255, 255, 255, 0.2);\n transform: scale(0.95);\n}\n\n.modal-close i {\n font-size: 1.25rem;\n}\n\n/* ============================================\n Modal Body\n ============================================ */\n\n.modal-body {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n padding: 0;\n background: var(--mj-bg-page);\n}\n\n.modal-body::-webkit-scrollbar {\n width: 8px;\n}\n\n.modal-body::-webkit-scrollbar-track {\n background: var(--mj-bg-surface-sunken);\n}\n\n.modal-body::-webkit-scrollbar-thumb {\n background: var(--mj-border-default);\n border-radius: var(--mj-radius-full);\n}\n\n.modal-body::-webkit-scrollbar-thumb:hover {\n background: var(--mj-color-neutral-400);\n}\n\n/* ============================================\n Form Structure\n ============================================ */\n\n.content-section {\n padding: 1.5rem 2rem;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.content-section:last-child {\n border-bottom: none;\n}\n\n.form-section {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n.section-header {\n margin-bottom: 1rem;\n}\n\n.section-title {\n margin: 0 0 0.5rem 0;\n font-size: 1.375rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 0.75rem;\n}\n\n.section-title i {\n font-size: 1.25rem;\n color: var(--mj-brand-primary);\n}\n\n.section-description {\n margin: 0;\n font-size: 0.875rem;\n color: var(--mj-text-secondary);\n line-height: 1.5;\n}\n\n/* ============================================\n Form Grid Layout\n ============================================ */\n\n.form-grid {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n.form-row {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 1.5rem;\n}\n\n@media (max-width: 640px) {\n .form-row {\n grid-template-columns: 1fr;\n gap: 1.5rem;\n }\n}\n\n/* ============================================\n Form Fields\n ============================================ */\n\n.form-field {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.field-label {\n font-size: 0.875rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 0.25rem;\n}\n\n.field-label.required::after {\n content: '*';\n color: var(--mj-status-error);\n margin-left: 0.25rem;\n}\n\n.field-input,\n.field-select {\n border: 2px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n padding: 0.875rem 1rem;\n font-size: 1rem;\n font-family: inherit;\n color: var(--mj-text-primary);\n background: var(--mj-bg-page);\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n width: 100%;\n box-sizing: border-box;\n}\n\n.field-input:hover:not(:disabled),\n.field-select:hover:not(:disabled) {\n border-color: var(--mj-color-neutral-400);\n}\n\n.field-input:focus,\n.field-select:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px rgba(0, 118, 182, 0.2);\n}\n\n.field-input:disabled,\n.field-select:disabled {\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n cursor: not-allowed;\n opacity: 0.6;\n}\n\n.field-input.error,\n.field-select.error {\n border-color: var(--mj-status-error);\n}\n\n.field-input.error:focus,\n.field-select.error:focus {\n box-shadow: 0 0 0 3px rgba(211, 47, 47, 0.2);\n}\n\n.field-input::placeholder,\n.field-select::placeholder {\n color: var(--mj-text-secondary);\n}\n\n/* Select Dropdown Styling */\n.field-select {\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%2379747E' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3e%3c/svg%3e\");\n background-position: right 16px center;\n background-repeat: no-repeat;\n background-size: 16px;\n padding-right: calc(16px + 32px);\n appearance: none;\n cursor: pointer;\n}\n\n.field-error {\n font-size: 0.75rem;\n color: var(--mj-status-error);\n display: flex;\n align-items: center;\n gap: 0.5rem;\n margin-top: 0.25rem;\n}\n\n.field-error i {\n font-size: 0.875rem;\n}\n\n/* ============================================\n Checkboxes\n ============================================ */\n\n.checkbox-field {\n display: flex;\n align-items: flex-start;\n gap: 0.75rem;\n cursor: pointer;\n margin-bottom: 0;\n}\n\n.checkbox-input {\n position: absolute;\n opacity: 0;\n cursor: pointer;\n}\n\n.checkbox-label {\n display: flex;\n align-items: flex-start;\n gap: 0.75rem;\n cursor: pointer;\n font-size: 0.875rem;\n color: var(--mj-text-primary);\n line-height: 1.4;\n margin: 0;\n flex: 1;\n}\n\n.checkbox-indicator {\n width: 20px;\n height: 20px;\n border: 2px solid var(--mj-color-neutral-400);\n border-radius: var(--mj-radius-sm);\n background: var(--mj-bg-page);\n flex-shrink: 0;\n position: relative;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n margin-top: 2px;\n}\n\n.checkbox-indicator::after {\n content: '';\n position: absolute;\n left: 6px;\n top: 2px;\n width: 4px;\n height: 8px;\n border: solid var(--mj-brand-on-primary);\n border-width: 0 2px 2px 0;\n opacity: 0;\n transform: rotate(45deg) scale(0.8);\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.checkbox-input:checked + .checkbox-label .checkbox-indicator {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.checkbox-input:checked + .checkbox-label .checkbox-indicator::after {\n opacity: 1;\n transform: rotate(45deg) scale(1);\n}\n\n.checkbox-input:focus + .checkbox-label .checkbox-indicator {\n box-shadow: 0 0 0 3px rgba(0, 118, 182, 0.2);\n}\n\n.checkbox-label strong {\n display: block;\n font-weight: 600;\n margin-bottom: 0.125rem;\n}\n\n/* ============================================\n Role Cards\n ============================================ */\n\n.roles-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));\n gap: 1rem;\n}\n\n@media (max-width: 640px) {\n .roles-grid {\n grid-template-columns: 1fr;\n }\n}\n\n.role-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n padding: 1.25rem;\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n display: flex;\n flex-direction: column;\n}\n\n.role-card:hover {\n border-color: var(--mj-brand-primary);\n box-shadow: var(--mj-shadow-md);\n transform: translateY(-2px);\n}\n\n.role-card.selected {\n background: var(--mj-brand-accent-subtle);\n border-color: var(--mj-brand-primary);\n box-shadow: var(--mj-shadow-md);\n}\n\n.role-content {\n display: flex;\n align-items: flex-start;\n gap: 1rem;\n}\n\n.role-info {\n flex: 1;\n min-width: 0;\n}\n\n.role-name {\n font-size: 1rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0 0 0.25rem 0;\n line-height: 1.3;\n}\n\n.role-description {\n font-size: 0.75rem;\n color: var(--mj-text-secondary);\n line-height: 1.4;\n margin: 0;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n/* ============================================\n Alert Messages\n ============================================ */\n\n.alert {\n display: flex;\n align-items: flex-start;\n gap: 1rem;\n padding: 1rem 1.25rem;\n border-radius: var(--mj-radius-md);\n border: 1px solid;\n font-size: 0.875rem;\n line-height: 1.5;\n}\n\n.alert i {\n font-size: 1.25rem;\n flex-shrink: 0;\n margin-top: 0.125rem;\n}\n\n.alert > div {\n flex: 1;\n min-width: 0;\n}\n\n/* Error Alert (Red) */\n.alert-error {\n background: var(--mj-color-error-100);\n border-color: var(--mj-status-error);\n color: var(--mj-status-error);\n}\n\n.alert-error i {\n color: var(--mj-status-error);\n}\n\n/* ============================================\n Modal Footer (Buttons)\n ============================================ */\n\n.modal-footer {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: 1rem;\n padding: 1.5rem 2rem;\n background: var(--mj-bg-surface-sunken);\n border-top: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n/* ============================================\n Buttons\n ============================================ */\n\n.btn {\n padding: 0.75rem 1.5rem;\n font-size: 0.875rem;\n font-weight: 500;\n border-radius: var(--mj-radius-full);\n border: none;\n cursor: pointer;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 44px;\n font-family: inherit;\n text-transform: none;\n letter-spacing: 0.01em;\n}\n\n.btn:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n.btn:active:not(:disabled) {\n transform: scale(0.98);\n}\n\n.btn i {\n font-size: 1rem;\n}\n\n.btn i.fa-spinner {\n animation: spin 1s linear infinite;\n}\n\n@keyframes spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n\n/* Primary Button (MJ Blue - Dark Button) */\n.btn-primary {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.btn-primary:hover:not(:disabled) {\n background: var(--mj-brand-primary-light);\n box-shadow: var(--mj-shadow-md);\n}\n\n.btn-primary:disabled {\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n box-shadow: none;\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n/* Secondary Button (Light Button) */\n.btn-secondary {\n background: var(--mj-bg-page);\n color: var(--mj-brand-primary);\n border: 1px solid var(--mj-color-neutral-400);\n box-shadow: none;\n}\n\n.btn-secondary:hover:not(:disabled) {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n border-color: var(--mj-brand-primary);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.btn-secondary:disabled {\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n border-color: var(--mj-border-default);\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n/* ============================================\n Responsive Design\n ============================================ */\n\n@media (max-width: 768px) {\n .modal-backdrop {\n padding: 0;\n }\n\n .modal-dialog {\n max-width: 100%;\n max-height: 100vh;\n border-radius: 0;\n animation: slideInMobile 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n @keyframes slideInMobile {\n from {\n opacity: 0;\n transform: translateY(100%);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n }\n\n .modal-header {\n padding: 20px 16px;\n border-radius: 0;\n }\n\n .dialog-title {\n font-size: 1.25rem;\n }\n\n .dialog-subtitle {\n font-size: 0.8125rem;\n }\n\n .content-section {\n padding: 1.25rem 1rem;\n }\n\n .section-title {\n font-size: 1.125rem;\n }\n\n .modal-footer {\n padding: 1rem;\n flex-direction: column;\n }\n\n .btn {\n width: 100%;\n justify-content: center;\n }\n\n .roles-grid {\n grid-template-columns: 1fr;\n }\n}\n\n@media (max-width: 480px) {\n .modal-header {\n padding: 16px 12px;\n }\n\n .dialog-title {\n font-size: 1.125rem;\n gap: 0.5rem;\n }\n\n .dialog-title i {\n font-size: 1rem;\n }\n\n .dialog-subtitle {\n font-size: 0.75rem;\n margin-top: 0.25rem;\n }\n\n .content-section {\n padding: 1rem 0.75rem;\n }\n\n .section-title {\n font-size: 1rem;\n gap: 0.5rem;\n }\n\n .field-input,\n .field-select {\n padding: 0.75rem;\n font-size: 0.875rem;\n }\n\n .modal-footer {\n padding: 0.75rem;\n }\n\n .btn {\n padding: 0.625rem 1.25rem;\n font-size: 0.8125rem;\n }\n}\n\n/* ============================================\n Accessibility\n ============================================ */\n\n/* Focus Visible Styles */\n*:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n/* Reduced Motion Support */\n@media (prefers-reduced-motion: reduce) {\n *,\n *::before,\n *::after {\n animation-duration: 0.01ms !important;\n animation-iteration-count: 1 !important;\n transition-duration: 0.01ms !important;\n }\n}\n\n/* High Contrast Mode Support */\n@media (prefers-contrast: high) {\n .modal-dialog {\n border: 2px solid var(--mj-border-default);\n }\n\n .btn {\n border: 2px solid currentColor;\n }\n\n .field-input,\n .field-select {\n border-width: 3px;\n }\n\n .role-card {\n border-width: 2px;\n }\n}\n\n/* ============================================\n Print Styles\n ============================================ */\n\n@media print {\n .modal-backdrop {\n display: none;\n }\n}\n"] }]
|
|
470
470
|
}], () => [], { data: [{
|
|
471
471
|
type: Input
|
|
472
472
|
}], visible: [{
|