# Cooldown Button Component A square Blazor button with a 12-second cooldown animation: when clicked, the button greys out and a circular transparency wedge dials open clockwise, progressively revealing the normal button state underneath. --- ## Visual Design The button has two visual states: **Idle state** – A solid square button with the project's standard `--paper` background and `--primary` border. Hover inverts or brightens the paper. Click triggers a brief scale-down. **Cooldown state** – The native button fades to `opacity: 0` while an absolutely-positioned overlay covers it. The overlay uses a `conic-gradient` CSS mask to create a "dialling open" effect. A number in the centre shows the remaining seconds. --- ## Core Technique: Conic-Gradient Mask The cooldown reveal is accomplished with a **conic-gradient mask** applied to the overlay `
`: ``` mask-image: conic-gradient( transparent 0deg, transparent {angle}deg, #000 {angle}deg, #000 360deg ); ``` - **`transparent`** – lets the button underneath show through (revealed area) - **`#000` (black)** – fully masks the overlay, making it visible (greyed-out area) At `angle = 0deg`, transparent covers nothing and the mask is entirely black → the overlay is fully opaque (button completely greyed out). At `angle = 360deg`, transparent covers the full circle and black covers nothing → the overlay is fully transparent (button completely visible). The angle animates linearly from 0 to 360 over the cooldown duration. Because `conic-gradient` starts at the 12 o'clock position and sweeps clockwise, the reveal begins at the top of the button and rotates around, like a clock hand or a dial opening. --- ## Implementation Architecture ### Component Parameters | Parameter | Type | Default | Description | |------------------|-------------------|---------|------------------------------------| | `ChildContent` | `RenderFragment` | `null` | Text or content inside the button | | `OnClick` | `EventCallback` | — | Fired when the button is clicked | | `CooldownSeconds`| `int` | `12` | Duration of the cooldown in seconds| | `Size` | `int` | `120` | Width and height in pixels (square)| ### Timer Loop A `System.Timers.Timer` fires every ~33 ms (≈30 fps) during the cooldown: ``` OnTick: elapsed = UtcNow - startTime if elapsed >= CooldownSeconds → end cooldown, dispose timer _elapsedAngle = (elapsed / CooldownSeconds) * 360 _remainingSeconds = CooldownSeconds - (int)elapsed InvokeAsync(StateHasChanged) ``` On each tick, `_elapsedAngle` is written into the overlay's inline `style` attribute, causing Blazor to re-render the `mask-image`. The timer is disposed in `Dispose()` to prevent leaks. ### Disposal The component implements `IDisposable` to clean up the timer when the component is removed from the render tree. This follows the same pattern used by `SearchDialogComponent` and `BuildChartComponent` elsewhere in the codebase. --- ## CSS Masking Details Two vendor-prefixed properties are set to ensure cross-browser support: ``` mask-image: conic-gradient(...); -webkit-mask-image: conic-gradient(...); ``` The overlay uses `pointer-events: none` and `user-select: none` so that interaction passes through to the button underneath (which is disabled and transparent). An `rgba(22, 22, 24, 0.82)` semi-transparent background on the overlay produces the greyed-out appearance. The mask controls *where* this background is visible. --- ## Usage on the Home Page The component is added to `Pages/Pages/Home/HomePage.razor` inside the first `PaperComponent`: ```razor Click Me ``` The `OnCooldownClick` handler in the page's `@code` block currently returns `Task.CompletedTask` (a no-op). This is the extension point where real work (e.g. triggering a game action, calling an API, showing a toast) would go. --- ## Adapting the Component - **Change cooldown duration** – set `CooldownSeconds` to any positive integer. - **Change button size** – set `Size` to any pixel dimension (button remains square). - **Custom content** – pass any Blazor markup as `ChildContent` (text, icons, spinners). - **Handle the click** – attach a handler to `OnClick` that returns `Task` or `void`. The `--cooldown-size` CSS custom property is set inline on the wrapper so that the label, overlay, and button all scale together.