FRONT-I-01: Extract Auth components to Razor Class Library packages/blazor-ui/
- Created GoodGo.BlazorUi RCL (net10.0, MudBlazor 8.15) at packages/blazor-ui/
- Moved AuthButton, AuthCard, AuthInput, OtpInput, BrandPanel, SocialLogin, LanguageSwitcher
- Referenced RCL from WebClientTpos.Client via ProjectReference
- Added GoodGo.BlazorUi.Components.Auth/Common namespaces to _Imports.razor
FRONT-I-02: Add ARIA/accessibility attributes (WCAG 2.1 AA)
- AuthButton: aria-label, aria-busy, aria-disabled, aria-hidden on decorative icons
- OtpInput: role=group, aria-label per digit, autocomplete=one-time-code
- PosLayout: aria-expanded + aria-controls on sidebar/order toggles, aria-label on all icon buttons
FRONT-I-03: Implement Style Dictionary design token pipeline
- Created packages/design-tokens/ with token JSON (color, spacing, typography, border)
- Style Dictionary config outputs: CSS custom properties → wwwroot/css/tokens.generated.css
- Second output: C# constants → packages/blazor-ui/DesignTokens/DesignTokens.g.cs
- Added tokens:build script to root package.json
- Added tokens.generated.css link to index.html (before app.css for cascade correctness)
FRONT-I-04: Replace eval() in OtpInput with safe JS interop
- Created wwwroot/js/otp-input.js with window.focusOtpInput(index) helper
- Replaced JS.InvokeVoidAsync("eval", ...) with JS.InvokeVoidAsync("focusOtpInput", index)
- Eliminates CSP-violating eval(), improves security and debuggability
Co-Authored-By: Paperclip <noreply@paperclip.ing>
79 lines
2.5 KiB
Plaintext
79 lines
2.5 KiB
Plaintext
@*
|
|
EN: Auth CTA button with color variants (orange, blue, green, outline, ghost).
|
|
VI: Nút CTA xác thực với các biến thể màu (cam, xanh dương, xanh lá, outline, ghost).
|
|
*@
|
|
|
|
<button type="@ButtonType"
|
|
class="auth-btn auth-btn--@Variant @CssClass"
|
|
disabled="@(Disabled || Loading)"
|
|
aria-label="@AriaLabel"
|
|
aria-busy="@(Loading ? "true" : "false")"
|
|
aria-disabled="@((Disabled || Loading) ? "true" : "false")"
|
|
@onclick="OnClick">
|
|
@if (Loading)
|
|
{
|
|
<span class="spinner-small" aria-hidden="true"></span>
|
|
}
|
|
@if (IconName != null)
|
|
{
|
|
<i data-lucide="@IconName" aria-hidden="true"></i>
|
|
}
|
|
@ChildContent
|
|
</button>
|
|
|
|
@code {
|
|
/// <summary>
|
|
/// EN: Button color variant. Options: orange, blue, green, outline, ghost.
|
|
/// VI: Biến thể màu. Tùy chọn: orange, blue, green, outline, ghost.
|
|
/// </summary>
|
|
[Parameter] public string Variant { get; set; } = "orange";
|
|
|
|
/// <summary>
|
|
/// EN: HTML button type attribute.
|
|
/// VI: Attribute type của button.
|
|
/// </summary>
|
|
[Parameter] public string ButtonType { get; set; } = "button";
|
|
|
|
/// <summary>
|
|
/// EN: Whether the button is disabled.
|
|
/// VI: Button có bị disable không.
|
|
/// </summary>
|
|
[Parameter] public bool Disabled { get; set; }
|
|
|
|
/// <summary>
|
|
/// EN: Whether to show a loading spinner.
|
|
/// VI: Có hiển thị spinner loading không.
|
|
/// </summary>
|
|
[Parameter] public bool Loading { get; set; }
|
|
|
|
/// <summary>
|
|
/// EN: Optional Lucide icon name.
|
|
/// VI: Tên icon Lucide tùy chọn.
|
|
/// </summary>
|
|
[Parameter] public string? IconName { get; set; }
|
|
|
|
/// <summary>
|
|
/// EN: Additional CSS classes.
|
|
/// VI: CSS class bổ sung.
|
|
/// </summary>
|
|
[Parameter] public string? CssClass { get; set; }
|
|
|
|
/// <summary>
|
|
/// EN: Click event callback.
|
|
/// VI: Callback sự kiện click.
|
|
/// </summary>
|
|
[Parameter] public EventCallback<MouseEventArgs> OnClick { get; set; }
|
|
|
|
/// <summary>
|
|
/// EN: Accessible label for screen readers (required when button has no visible text).
|
|
/// VI: Nhãn accessible cho screen reader (bắt buộc khi button không có text hiển thị).
|
|
/// </summary>
|
|
[Parameter] public string? AriaLabel { get; set; }
|
|
|
|
/// <summary>
|
|
/// EN: Button content.
|
|
/// VI: Nội dung button.
|
|
/// </summary>
|
|
[Parameter] public RenderFragment? ChildContent { get; set; }
|
|
}
|