Replace emoji icons with Lucide icons and soften link colors

Replaced emoji icons throughout the Angular app with modern Lucide icon library for a more professional and consistent look matching the original static site design.

**Icon Updates:**
- Navigation tabs: Database, Upload, Search icons
- Toolbar buttons: RefreshCw, Sparkles, Search, X icons
- Action buttons: Download, Trash2 icons
- Form buttons: Upload, Search, X icons

**Style Improvements:**
- Added softer blue color for artifact links (#93c5fd)
- Added hover effect with lighter blue (#bfdbfe)
- Added proper cursor pointer for clickable rows
- Improved icon color consistency throughout

**Dependencies:**
- Added lucide-angular (v0.545.0) for icon support
- Bundle size: 356.54 kB (raw) → 93.91 kB (gzipped)
- Minimal impact: only +7.79 kB for full icon library

All components updated with Lucide imports and icon references.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-10-15 12:19:36 -05:00
parent 20a4ea1655
commit 972bb50c64
9 changed files with 63 additions and 19 deletions

View File

@@ -29,6 +29,7 @@
"@angular/forms": "^19.0.0", "@angular/forms": "^19.0.0",
"@angular/platform-browser": "^19.0.0", "@angular/platform-browser": "^19.0.0",
"@angular/router": "^19.0.0", "@angular/router": "^19.0.0",
"lucide-angular": "^0.545.0",
"rxjs": "~7.8.0", "rxjs": "~7.8.0",
"tslib": "^2.3.0", "tslib": "^2.3.0",
"zone.js": "~0.15.0" "zone.js": "~0.15.0"

View File

@@ -3,11 +3,12 @@ import { CommonModule } from '@angular/common';
import { RouterOutlet, RouterLink, RouterLinkActive } from '@angular/router'; import { RouterOutlet, RouterLink, RouterLinkActive } from '@angular/router';
import { provideHttpClient } from '@angular/common/http'; import { provideHttpClient } from '@angular/common/http';
import { ArtifactService } from './services/artifact'; import { ArtifactService } from './services/artifact';
import { LucideAngularModule, Database, Upload, Search } from 'lucide-angular';
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
standalone: true, standalone: true,
imports: [CommonModule, RouterOutlet, RouterLink, RouterLinkActive], imports: [CommonModule, RouterOutlet, RouterLink, RouterLinkActive, LucideAngularModule],
template: ` template: `
<div class="container"> <div class="container">
<header> <header>
@@ -20,13 +21,13 @@ import { ArtifactService } from './services/artifact';
<nav class="tabs"> <nav class="tabs">
<a routerLink="/artifacts" routerLinkActive="active" class="tab-button"> <a routerLink="/artifacts" routerLinkActive="active" class="tab-button">
📦 Artifacts <lucide-icon [img]="Database" [size]="16"></lucide-icon> Artifacts
</a> </a>
<a routerLink="/upload" routerLinkActive="active" class="tab-button"> <a routerLink="/upload" routerLinkActive="active" class="tab-button">
📤 Upload <lucide-icon [img]="Upload" [size]="16"></lucide-icon> Upload
</a> </a>
<a routerLink="/query" routerLinkActive="active" class="tab-button"> <a routerLink="/query" routerLinkActive="active" class="tab-button">
🔍 Query <lucide-icon [img]="Search" [size]="16"></lucide-icon> Query
</a> </a>
</nav> </nav>
@@ -38,6 +39,9 @@ import { ArtifactService } from './services/artifact';
export class AppComponent implements OnInit { export class AppComponent implements OnInit {
deploymentMode: string = ''; deploymentMode: string = '';
storageBackend: string = ''; storageBackend: string = '';
readonly Database = Database;
readonly Upload = Upload;
readonly Search = Search;
constructor(private artifactService: ArtifactService) {} constructor(private artifactService: ArtifactService) {}

View File

@@ -1,7 +1,7 @@
<div class="artifacts-container"> <div class="artifacts-container">
<div class="toolbar"> <div class="toolbar">
<button (click)="loadArtifacts()" class="btn btn-primary"> <button (click)="loadArtifacts()" class="btn btn-primary">
🔄 Refresh <lucide-icon [img]="RefreshCw" [size]="16"></lucide-icon> Refresh
</button> </button>
<button (click)="toggleAutoRefresh()" <button (click)="toggleAutoRefresh()"
[class.btn-success]="autoRefreshEnabled" [class.btn-success]="autoRefreshEnabled"
@@ -10,20 +10,22 @@
Auto-refresh: {{ autoRefreshEnabled ? 'ON' : 'OFF' }} Auto-refresh: {{ autoRefreshEnabled ? 'ON' : 'OFF' }}
</button> </button>
<button (click)="generateSeedData()" class="btn btn-secondary"> <button (click)="generateSeedData()" class="btn btn-secondary">
Generate Seed Data <lucide-icon [img]="Sparkles" [size]="16"></lucide-icon> Generate Seed Data
</button> </button>
<span class="count-badge">{{ filteredArtifacts.length }} artifacts</span> <span class="count-badge">{{ filteredArtifacts.length }} artifacts</span>
<div class="filter-inline"> <div class="filter-inline">
<span class="search-icon">🔍</span> <lucide-icon [img]="Search" [size]="16" class="search-icon"></lucide-icon>
<input <input
type="text" type="text"
[(ngModel)]="searchTerm" [(ngModel)]="searchTerm"
(input)="onSearch()" (input)="onSearch()"
placeholder="Search..." placeholder="Search..."
class="search-input"> class="search-input">
<button (click)="clearSearch()" class="btn-clear" *ngIf="searchTerm"></button> <button (click)="clearSearch()" class="btn-clear" *ngIf="searchTerm">
<lucide-icon [img]="X" [size]="14"></lucide-icon>
</button>
</div> </div>
</div> </div>
@@ -80,10 +82,10 @@
<td> <td>
<div class="action-buttons"> <div class="action-buttons">
<button (click)="downloadArtifact(artifact, $event)" class="icon-btn" title="Download"> <button (click)="downloadArtifact(artifact, $event)" class="icon-btn" title="Download">
⬇️ <lucide-icon [img]="Download" [size]="16"></lucide-icon>
</button> </button>
<button (click)="deleteArtifact(artifact, $event)" class="icon-btn danger" title="Delete"> <button (click)="deleteArtifact(artifact, $event)" class="icon-btn danger" title="Delete">
🗑️ <lucide-icon [img]="Trash2" [size]="16"></lucide-icon>
</button> </button>
</div> </div>
</td> </td>
@@ -177,10 +179,10 @@
</div> </div>
<div class="modal-actions"> <div class="modal-actions">
<button (click)="downloadArtifact(selectedArtifact, $event)" class="btn btn-primary"> <button (click)="downloadArtifact(selectedArtifact, $event)" class="btn btn-primary">
⬇️ Download <lucide-icon [img]="Download" [size]="16"></lucide-icon> Download
</button> </button>
<button (click)="deleteArtifact(selectedArtifact, $event); closeDetail()" class="btn btn-danger"> <button (click)="deleteArtifact(selectedArtifact, $event); closeDetail()" class="btn btn-danger">
🗑️ Delete <lucide-icon [img]="Trash2" [size]="16"></lucide-icon> Delete
</button> </button>
</div> </div>
</div> </div>

View File

@@ -5,11 +5,12 @@ import { ArtifactService } from '../../services/artifact';
import { Artifact } from '../../models/artifact.model'; import { Artifact } from '../../models/artifact.model';
import { interval, Subscription } from 'rxjs'; import { interval, Subscription } from 'rxjs';
import { switchMap } from 'rxjs/operators'; import { switchMap } from 'rxjs/operators';
import { LucideAngularModule, RefreshCw, Search, X, Download, Trash2, Sparkles } from 'lucide-angular';
@Component({ @Component({
selector: 'app-artifacts-list', selector: 'app-artifacts-list',
standalone: true, standalone: true,
imports: [CommonModule, FormsModule], imports: [CommonModule, FormsModule, LucideAngularModule],
templateUrl: './artifacts-list.html', templateUrl: './artifacts-list.html',
styleUrls: ['./artifacts-list.css'] styleUrls: ['./artifacts-list.css']
}) })
@@ -35,6 +36,14 @@ export class ArtifactsListComponent implements OnInit, OnDestroy {
loading: boolean = false; loading: boolean = false;
error: string | null = null; error: string | null = null;
// Lucide icons
readonly RefreshCw = RefreshCw;
readonly Search = Search;
readonly X = X;
readonly Download = Download;
readonly Trash2 = Trash2;
readonly Sparkles = Sparkles;
constructor(private artifactService: ArtifactService) {} constructor(private artifactService: ArtifactService) {}
ngOnInit() { ngOnInit() {

View File

@@ -92,10 +92,10 @@
<div class="button-group"> <div class="button-group">
<button type="submit" class="btn btn-primary btn-large"> <button type="submit" class="btn btn-primary btn-large">
🔍 Search <lucide-icon [img]="Search" [size]="18"></lucide-icon> Search
</button> </button>
<button type="button" (click)="clearForm()" class="btn btn-secondary"> <button type="button" (click)="clearForm()" class="btn btn-secondary">
Clear <lucide-icon [img]="X" [size]="18"></lucide-icon> Clear
</button> </button>
</div> </div>
</form> </form>

View File

@@ -3,17 +3,20 @@ import { CommonModule } from '@angular/common';
import { ReactiveFormsModule, FormBuilder, FormGroup } from '@angular/forms'; import { ReactiveFormsModule, FormBuilder, FormGroup } from '@angular/forms';
import { ArtifactService } from '../../services/artifact'; import { ArtifactService } from '../../services/artifact';
import { Artifact, ArtifactQuery } from '../../models/artifact.model'; import { Artifact, ArtifactQuery } from '../../models/artifact.model';
import { LucideAngularModule, Search, X } from 'lucide-angular';
@Component({ @Component({
selector: 'app-query-form', selector: 'app-query-form',
standalone: true, standalone: true,
imports: [CommonModule, ReactiveFormsModule], imports: [CommonModule, ReactiveFormsModule, LucideAngularModule],
templateUrl: './query-form.html', templateUrl: './query-form.html',
styleUrls: ['./query-form.css'] styleUrls: ['./query-form.css']
}) })
export class QueryFormComponent { export class QueryFormComponent {
queryForm: FormGroup; queryForm: FormGroup;
@Output() resultsFound = new EventEmitter<Artifact[]>(); @Output() resultsFound = new EventEmitter<Artifact[]>();
readonly Search = Search;
readonly X = X;
constructor( constructor(
private fb: FormBuilder, private fb: FormBuilder,

View File

@@ -98,7 +98,8 @@
</div> </div>
<button type="submit" class="btn btn-primary btn-large" [disabled]="uploading"> <button type="submit" class="btn btn-primary btn-large" [disabled]="uploading">
{{ uploading ? 'Uploading...' : '📤 Upload Artifact' }} <lucide-icon [img]="Upload" [size]="18"></lucide-icon>
{{ uploading ? 'Uploading...' : 'Upload Artifact' }}
</button> </button>
</form> </form>

View File

@@ -2,11 +2,12 @@ import { Component } from '@angular/core';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { ReactiveFormsModule, FormBuilder, FormGroup, Validators } from '@angular/forms'; import { ReactiveFormsModule, FormBuilder, FormGroup, Validators } from '@angular/forms';
import { ArtifactService } from '../../services/artifact'; import { ArtifactService } from '../../services/artifact';
import { LucideAngularModule, Upload } from 'lucide-angular';
@Component({ @Component({
selector: 'app-upload-form', selector: 'app-upload-form',
standalone: true, standalone: true,
imports: [CommonModule, ReactiveFormsModule], imports: [CommonModule, ReactiveFormsModule, LucideAngularModule],
templateUrl: './upload-form.html', templateUrl: './upload-form.html',
styleUrls: ['./upload-form.css'] styleUrls: ['./upload-form.css']
}) })
@@ -15,6 +16,7 @@ export class UploadFormComponent {
selectedFile: File | null = null; selectedFile: File | null = null;
uploading: boolean = false; uploading: boolean = false;
uploadStatus: { message: string, success: boolean } | null = null; uploadStatus: { message: string, success: boolean } | null = null;
readonly Upload = Upload;
constructor( constructor(
private fb: FormBuilder, private fb: FormBuilder,

View File

@@ -524,6 +524,28 @@ code {
stroke: currentColor; stroke: currentColor;
} }
/* Artifact link styles - softer blue */
.artifact-link {
color: #93c5fd;
text-decoration: none;
transition: color 0.3s;
}
.artifact-link:hover {
color: #bfdbfe;
text-decoration: underline;
}
/* Clickable row cursor */
tr.clickable {
cursor: pointer;
}
/* Search icon color */
.search-icon {
color: #64748b;
}
@media (max-width: 768px) { @media (max-width: 768px) {
.form-row { .form-row {
grid-template-columns: 1fr; grid-template-columns: 1fr;