Feat: Add Copy URL button and reusable toast notification system
Detail page now has a "Copy URL" button that copies the image's direct file URL to the clipboard. A toast service (BehaviorSubject-backed, auto-dismissing after 3s) confirms success or failure. ToastComponent is registered at the app root and available to all future features. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,7 @@ import { FormsModule } from '@angular/forms';
|
||||
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
|
||||
import { ImageRecord, ImageService } from '../services/image.service';
|
||||
import { AuthService } from '../auth/auth.service';
|
||||
import { ToastService } from '../services/toast.service';
|
||||
|
||||
const PLACEHOLDER_SVG = `data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="800" height="500" viewBox="0 0 800 500"><rect width="800" height="500" fill="%23111"/><text x="50%" y="50%" dominant-baseline="middle" text-anchor="middle" font-size="48" fill="%23444">🔗</text></svg>`;
|
||||
|
||||
@@ -54,6 +55,8 @@ const PLACEHOLDER_SVG = `data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/s
|
||||
(error)="onImgError($event)"
|
||||
/>
|
||||
|
||||
<button class="copy-url-btn" (click)="copyUrl()">Copy URL</button>
|
||||
|
||||
<section class="tags-section">
|
||||
<h3>Tags</h3>
|
||||
<div class="chips">
|
||||
@@ -139,6 +142,10 @@ const PLACEHOLDER_SVG = `data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/s
|
||||
.add-tag input:focus { outline: none; border-color: var(--border-focus); }
|
||||
.delete-btn { padding: 10px 24px; background: var(--danger); color: var(--danger-text); border: none; border-radius: var(--radius); cursor: pointer; margin-left: auto; }
|
||||
|
||||
/* Copy URL */
|
||||
.copy-url-btn { padding: 8px 20px; background: var(--surface-raised); color: var(--text); border: 1px solid var(--border); border-radius: var(--radius); cursor: pointer; margin: 12px 0; transition: border-color var(--transition); }
|
||||
.copy-url-btn:hover { border-color: var(--border-focus); }
|
||||
|
||||
/* Delete dialog */
|
||||
.dialog-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.7); display: flex; align-items: center; justify-content: center; z-index: 100; }
|
||||
.dialog { background: var(--surface); padding: 32px; border-radius: 10px; text-align: center; }
|
||||
@@ -163,6 +170,7 @@ export class DetailComponent implements OnInit {
|
||||
private route: ActivatedRoute,
|
||||
public router: Router,
|
||||
private cdr: ChangeDetectorRef,
|
||||
private toastService: ToastService,
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
@@ -235,6 +243,16 @@ export class DetailComponent implements OnInit {
|
||||
this.cdr.markForCheck();
|
||||
}
|
||||
|
||||
copyUrl(): void {
|
||||
if (!this.image) return;
|
||||
const url = this.image.file_url.startsWith('http')
|
||||
? this.image.file_url
|
||||
: window.location.origin + this.image.file_url;
|
||||
navigator.clipboard.writeText(url)
|
||||
.then(() => this.toastService.show('URL copied!'))
|
||||
.catch(() => this.toastService.show('Failed to copy URL', 'error'));
|
||||
}
|
||||
|
||||
goBack(): void { this.router.navigate(['/']); }
|
||||
|
||||
onImgError(event: Event): void {
|
||||
|
||||
Reference in New Issue
Block a user