# Research: Copy URL & Toast Notifications ## Decision 1: Toast Service Architecture **Decision**: `BehaviorSubject` singleton service, one active toast at a time — new toasts replace the current one. **Rationale**: The simplest approach that satisfies FR-007 (reusable from anywhere) and FR-008 (multiple toasts don't overlap illegibly). A queue adds complexity with no meaningful UX benefit for this app's usage pattern (copy URL, upload confirm, etc. — actions that don't overlap in practice). Replacing the current toast on rapid successive calls is acceptable and visually cleaner than a stack. The `BehaviorSubject` integrates naturally with Angular's `async` pipe and OnPush change detection. **Alternatives considered**: - `Subject` (not `BehaviorSubject`): Late subscribers miss toasts that already fired. Rejected — component may subscribe after service emits if change detection is deferred. - Toast queue (array): Adds observable complexity and UI layout decisions. Rejected — over-engineered for this use case. - Angular CDK Overlay: Official but heavy. Pulls in CDK dependency for a feature that needs ~30 lines of code. Rejected per §2.6 (no speculative abstraction) and §6 (no new dependencies). --- ## Decision 2: Clipboard API Usage **Decision**: `navigator.clipboard.writeText(url)` — no polyfill, no fallback to `document.execCommand`. **Rationale**: `execCommand('copy')` is deprecated and removed in some browsers. The Clipboard API is supported in all modern browsers (Chrome 66+, Firefox 63+, Safari 13.1+). The app already requires HTTPS in production (Let's Encrypt via cert-manager), which satisfies the Clipboard API's secure context requirement. On failure (permission denied, API unavailable), catch the rejected Promise and show an error toast. **Alternatives considered**: - `execCommand('copy')` fallback: Deprecated, inconsistent, adds code complexity. The failure path (error toast) covers the rare unavailability case more cleanly. --- ## Decision 3: What URL to Copy **Decision**: Copy `image.file_url` as-is (the direct image file URL). **Rationale**: `file_url` is the CDN URL in production (e.g. `https://cdn.reactbin.juggalol.com/…`) — already absolute. In development it is relative (`/api/v1/images/{id}/file`); for dev use, prepend `window.location.origin`. The direct file URL is the right thing to share for a reaction image library: it embeds inline when pasted into Discord/Slack without requiring a click-through. **Alternatives considered**: - Detail page URL (`/images/{id}`): The user can already copy this from the browser address bar. The file URL is the value-add. - Always prepend `window.location.origin`: Works for both environments, adds a guard. Included as a defensive measure for the dev case. --- ## Decision 4: Toast Positioning **Decision**: Fixed position, bottom-center of the viewport. **Rationale**: Bottom-center is less intrusive than top-right for a brief confirmation toast. It doesn't overlap the image or the copy button. `pointer-events: none` ensures it never blocks interaction. **Alternatives considered**: - Top-right: Common convention (Material, Bootstrap) but overlaps the header/nav area in this layout. - Top-center: Similar issue. --- ## Decision 5: OnPush compatibility **Decision**: `ToastComponent` uses `ChangeDetectionStrategy.OnPush` with the `async` pipe consuming `toastService.current$`. Angular's `async` pipe calls `markForCheck()` automatically when the observable emits, making it fully compatible with OnPush. **Rationale**: Consistent with all other components in the project. No manual `markForCheck()` calls needed in `ToastComponent`.