WEB-492: Material Design 3 implementation: Login

This commit is contained in:
Jose Alberto Hernandez
2026-01-04 14:06:28 -05:00
parent 5af11fe757
commit df7274626c
58 changed files with 3396 additions and 855 deletions
+8
View File
@@ -0,0 +1,8 @@
/**
* Material Design 3 UI Components
*
* This module exports all Material Design 3 components for easy importing.
*/
export { M3ButtonComponent, M3ButtonVariant } from './m3-button/m3-button.component';
export { M3IconComponent, M3IconStyle } from './m3-icon/m3-icon.component';
@@ -0,0 +1,31 @@
<div [class]="containerClasses">
@if (variant === 'filled') {
<md-filled-button [type]="type" [disabled]="disabled" (click)="onClick($event)">
{{ label }}<ng-content></ng-content>
</md-filled-button>
}
@if (variant === 'outlined') {
<md-outlined-button [type]="type" [disabled]="disabled" (click)="onClick($event)">
{{ label }}<ng-content></ng-content>
</md-outlined-button>
}
@if (variant === 'elevated') {
<md-elevated-button [type]="type" [disabled]="disabled" (click)="onClick($event)">
{{ label }}<ng-content></ng-content>
</md-elevated-button>
}
@if (variant === 'text') {
<md-text-button [type]="type" [disabled]="disabled" (click)="onClick($event)">
{{ label }}<ng-content></ng-content>
</md-text-button>
}
@if (variant === 'tonal') {
<md-filled-tonal-button [type]="type" [disabled]="disabled" (click)="onClick($event)">
{{ label }}<ng-content></ng-content>
</md-filled-tonal-button>
}
</div>
@@ -0,0 +1,20 @@
// Material Web Button Component Styles
// Base styles are applied globally in src/theme/_material-web.scss
.m3-button-container {
display: inline-block;
&--full-width {
display: block;
width: 100%;
md-filled-button,
md-outlined-button,
md-elevated-button,
md-text-button,
md-filled-tonal-button {
color: var(--md-filled-button-disabled-label-text-color, #44474e);
width: 100%;
}
}
}
@@ -0,0 +1,153 @@
import { Component, Input, Output, EventEmitter, CUSTOM_ELEMENTS_SCHEMA, ViewEncapsulation } from '@angular/core';
import { CommonModule } from '@angular/common';
// Import Material Web Components
import '@material/web/button/filled-button.js';
import '@material/web/button/outlined-button.js';
import '@material/web/button/elevated-button.js';
import '@material/web/button/text-button.js';
import '@material/web/button/filled-tonal-button.js';
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
export type M3ButtonVariant = 'filled' | 'outlined' | 'elevated' | 'text' | 'tonal';
/**
* Material Design 3 Button Component
*
* Wrapper for @material/web button components following Material Design 3 specifications.
* Uses native Material Design 3 web components with full theming support.
*
* Features:
* - Five button variants: filled, outlined, elevated, text, and tonal
* - Automatic light/dark theme support
* - Proper disabled states with gray colors
* - Hover, focus, and pressed states with ripple effects
* - Full width support
* - Icon support (leading and trailing)
*
* @example
* // Basic usage with label input
* <mifosx-m3-button
* variant="filled"
* [label]="'Submit'"
* (clicked)="onSubmit()">
* </mifosx-m3-button>
*
* @example
* // With content projection
* <mifosx-m3-button variant="outlined" (clicked)="onCancel()">
* Cancel
* </mifosx-m3-button>
*
* @example
* // Full width disabled button
* <mifosx-m3-button
* variant="filled"
* [label]="'Loading...'"
* [disabled]="true"
* [fullWidth]="true">
* </mifosx-m3-button>
*
* @example
* // With translated label
* <mifosx-m3-button
* variant="tonal"
* type="submit"
* [label]="'labels.buttons.Save' | translate"
* (clicked)="onSave()">
* </mifosx-m3-button>
*/
@Component({
selector: 'mifosx-m3-button',
templateUrl: './m3-button.component.html',
styleUrls: ['./m3-button.component.scss'],
standalone: true,
imports: [
STANDALONE_SHARED_IMPORTS,
CommonModule
],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
encapsulation: ViewEncapsulation.None
})
export class M3ButtonComponent {
/**
* Button variant
* - filled: Solid background (default, highest emphasis)
* - outlined: Bordered button (medium emphasis)
* - elevated: Raised button with shadow (medium emphasis)
* - text: Text-only button (low emphasis)
* - tonal: Subtle background button (medium emphasis)
*/
@Input() variant: M3ButtonVariant = 'filled';
/**
* Button type attribute
*/
@Input() type: 'button' | 'submit' | 'reset' = 'button';
/**
* Disabled state
*/
@Input() disabled: boolean = false;
/**
* Button label text
*/
@Input() label?: string;
/**
* Icon to display before text
*/
@Input() icon?: string;
/**
* Icon to display after text
*/
@Input() trailingIcon?: string;
/**
* Whether the button should take full width
*/
@Input() fullWidth: boolean = false;
/**
* Click event emitter
*/
@Output() clicked = new EventEmitter<Event>();
/**
* Handle button click
*/
onClick(event: Event): void {
if (!this.disabled) {
this.clicked.emit(event);
}
}
/**
* Get the Material Web Component tag name based on variant
*/
get componentTag(): string {
switch (this.variant) {
case 'filled':
return 'md-filled-button';
case 'outlined':
return 'md-outlined-button';
case 'elevated':
return 'md-elevated-button';
case 'text':
return 'md-text-button';
case 'tonal':
return 'md-filled-tonal-button';
default:
return 'md-filled-button';
}
}
/**
* Get container classes
*/
get containerClasses(): string {
return this.fullWidth ? 'm3-button-container--full-width' : 'm3-button-container';
}
}
@@ -0,0 +1 @@
<span [class]="iconClass" [ngStyle]="iconStyles" class="m3-icon">{{ name }}</span>
@@ -0,0 +1,71 @@
// Material Symbols Font Faces
// These will be loaded from Google Fonts or local files
@use 'theme/material-web' as *;
.m3-icon {
display: inline-flex;
align-items: center;
justify-content: center;
user-select: none;
vertical-align: middle;
// Smooth rendering
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-rendering: optimizelegibility;
}
// Material Symbols base styles
.material-symbols-outlined,
.material-symbols-filled,
.material-symbols-rounded,
.material-symbols-sharp {
font-family: 'Material Symbols Outlined', sans-serif;
font-weight: normal;
font-style: normal;
line-height: 1;
letter-spacing: normal;
text-transform: none;
white-space: nowrap;
word-wrap: normal;
direction: ltr;
color: var(--md-icon-prefix-label-text-color, #44474e);
}
// Filled variant
.material-symbols-filled {
font-variation-settings:
'FILL' 1,
'wght' 400,
'GRAD' 0,
'opsz' 24;
}
// Outlined variant (default)
.material-symbols-outlined {
font-variation-settings:
'FILL' 0,
'wght' 400,
'GRAD' 0,
'opsz' 24;
}
// Rounded variant
.material-symbols-rounded {
font-family: 'Material Symbols Rounded', sans-serif;
font-variation-settings:
'FILL' 0,
'wght' 400,
'GRAD' 0,
'opsz' 24;
}
// Sharp variant
.material-symbols-sharp {
font-family: 'Material Symbols Sharp', sans-serif;
font-variation-settings:
'FILL' 0,
'wght' 400,
'GRAD' 0,
'opsz' 24;
}
@@ -0,0 +1,95 @@
import { Component, Input, ViewEncapsulation } from '@angular/core';
import { CommonModule } from '@angular/common';
export type M3IconStyle = 'outlined' | 'filled' | 'rounded' | 'sharp';
/**
* Material Design 3 Icon Component
*
* Wrapper for Material Symbols icons following Material Design 3 specifications.
* Uses Google's Material Symbols font for consistent iconography.
*
* Features:
* - Multiple icon styles: outlined (default), filled, rounded, and sharp
* - Automatic theme support
* - Size control
* - Color customization via CSS
*
* @example
* // Basic usage
* <mifosx-m3-icon name="account_circle"></mifosx-m3-icon>
*
* @example
* // With filled style
* <mifosx-m3-icon name="lock" style="filled"></mifosx-m3-icon>
*
* @example
* // With custom size
* <mifosx-m3-icon name="visibility" [size]="24"></mifosx-m3-icon>
*
* Common icon mappings from Font Awesome:
* - user-circle → account_circle
* - lock → lock
* - eye → visibility
* - eye-slash → visibility_off
* - home → home
* - search → search
* - settings → settings
* - menu → menu
* - close → close
*/
@Component({
selector: 'mifosx-m3-icon',
templateUrl: './m3-icon.component.html',
styleUrls: ['./m3-icon.component.scss'],
standalone: true,
imports: [CommonModule],
encapsulation: ViewEncapsulation.None
})
export class M3IconComponent {
/**
* Icon name from Material Symbols
* See: https://fonts.google.com/icons
*/
@Input() name!: string;
/**
* Icon style variant
* - outlined: Default style with strokes (default)
* - filled: Solid filled icons
* - rounded: Rounded corner icons
* - sharp: Sharp corner icons
*/
@Input() style: M3IconStyle = 'outlined';
/**
* Icon size in pixels
* Default is 24px (Material Design standard)
*/
@Input() size: number = 24;
/**
* Whether the icon should be filled (alternative to style="filled")
* This is a convenience property for backwards compatibility
*/
@Input() filled: boolean = false;
/**
* Get the CSS class for the icon style
*/
get iconClass(): string {
const styleToUse = this.filled ? 'filled' : this.style;
return `material-symbols-${styleToUse}`;
}
/**
* Get the inline styles for the icon
*/
get iconStyles(): { [key: string]: string } {
return {
'font-size': `${this.size}px`,
width: `${this.size}px`,
height: `${this.size}px`
};
}
}