chore: fix hardcoded URL, add comprehensive docs
All checks were successful
armco-org/icon-spot/pipeline/head This commit was not built
All checks were successful
armco-org/icon-spot/pipeline/head This commit was not built
- Fix hardcoded ML service URL in IconController.tsx (now uses API_CONFIG) - Add docs/SPECS.md, DESIGN.md, DEBT.md, READINESS.md - Update README.md with comprehensive documentation
This commit is contained in:
130
README.md
130
README.md
@@ -1 +1,129 @@
|
||||
# Armco Template for the tech stack: React, TS, Dart Sass, Redux Tookkit, react-redux, react browser routing, TS based plop generator
|
||||
# @armco/icon-spot
|
||||
|
||||
> Icon Management UI for Armco Platform
|
||||
|
||||
icon-spot is a React-based icon browser and editor that provides browsing, searching, styling, and downloading capabilities for the Armco icon library.
|
||||
|
||||
## Features
|
||||
|
||||
- **Icon Browser**: Paginated grid with search and tag filtering
|
||||
- **View Modes**: Comfy, Compact, and List layouts
|
||||
- **Style Editor**: Customize fill, stroke, background colors
|
||||
- **SVG Download**: Export styled icons as SVG files
|
||||
- **Favorites**: Mark icons for quick access
|
||||
- **Selection Mode**: Multi-select for batch operations
|
||||
- **Similar Icons**: ML-powered icon recommendations
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pnpm add @armco/icon-spot
|
||||
```
|
||||
|
||||
## Peer Dependencies
|
||||
|
||||
```json
|
||||
{
|
||||
"@armco/components": "^0.0.60",
|
||||
"@armco/configs": "^0.0.11",
|
||||
"@armco/icon": "^0.0.10",
|
||||
"@armco/types": "^0.0.18",
|
||||
"@armco/utils": "^0.0.29",
|
||||
"@reduxjs/toolkit": "^1.8.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-redux": "^8.0.1",
|
||||
"react-router-dom": "^6.13.0"
|
||||
}
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Import
|
||||
|
||||
```tsx
|
||||
import Icons from "@armco/icon-spot"
|
||||
import { IconInfo, IconsMerge, Clusters } from "@armco/icon-spot"
|
||||
```
|
||||
|
||||
### With Redux Setup
|
||||
|
||||
```tsx
|
||||
import { configureStore } from "@reduxjs/toolkit"
|
||||
import { Provider } from "react-redux"
|
||||
import { BrowserRouter, Routes, Route } from "react-router-dom"
|
||||
import Icons, { IconInfo, IconsMerge } from "@armco/icon-spot"
|
||||
|
||||
// Import reducers from icon-spot
|
||||
import iconsReducer from "@armco/icon-spot/Icons.slice"
|
||||
import iconInfoReducer from "@armco/icon-spot/IconInfo.slice"
|
||||
|
||||
const store = configureStore({
|
||||
reducer: {
|
||||
icons: iconsReducer,
|
||||
iconInfo: iconInfoReducer,
|
||||
},
|
||||
})
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<Provider store={store}>
|
||||
<BrowserRouter>
|
||||
<Routes>
|
||||
<Route path="/" element={<Icons />} />
|
||||
<Route path="/icon/:group/:name" element={<IconInfo />} />
|
||||
<Route path="/icons/merge-icons" element={<IconsMerge />} />
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
</Provider>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
## Exported Components
|
||||
|
||||
| Component | Description |
|
||||
|-----------|-------------|
|
||||
| `Icons` | Main icon browser with filters and grid |
|
||||
| `IconInfo` | Icon detail page with editor |
|
||||
| `IconsMerge` | Multi-icon merge tool |
|
||||
| `Clusters` | ML-generated cluster visualization |
|
||||
|
||||
## Development
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
pnpm install
|
||||
|
||||
# Start development server
|
||||
pnpm dev
|
||||
|
||||
# Build library
|
||||
pnpm build
|
||||
```
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
src/
|
||||
├── index.tsx # Exports
|
||||
├── store.ts # Redux store
|
||||
├── Icons.tsx # Main browser
|
||||
├── IconsList.tsx # Icon grid
|
||||
├── IconTile.tsx # Icon card
|
||||
├── IconInfo.tsx # Detail view
|
||||
├── IconController.tsx # Detail controls
|
||||
├── IconEditor.tsx # Style editor
|
||||
└── helper.ts # Utilities
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
- [SPECS.md](docs/SPECS.md) - Feature specifications
|
||||
- [DESIGN.md](docs/DESIGN.md) - Architecture diagrams
|
||||
- [DEBT.md](docs/DEBT.md) - Technical debt register
|
||||
- [READINESS.md](docs/READINESS.md) - Production checklist
|
||||
|
||||
## License
|
||||
|
||||
ISC
|
||||
|
||||
242
docs/DEBT.md
Normal file
242
docs/DEBT.md
Normal file
@@ -0,0 +1,242 @@
|
||||
# icon-spot - Technical Debt Register
|
||||
|
||||
## ✅ Recently Fixed
|
||||
|
||||
### 1. ~~Hardcoded ML Service URL~~ (FIXED)
|
||||
**Location:** `src/IconController.tsx` (Line ~52)
|
||||
**Issue:** ~~ML service URL was hardcoded~~
|
||||
**Resolution:** ✅ Changed to use `API_CONFIG.TASKER[process.env.NODE_ENV]` for environment-aware configuration.
|
||||
**Date Fixed:** Session
|
||||
|
||||
---
|
||||
|
||||
## 🔴 Critical (Must Fix Before Production)
|
||||
|
||||
### 2. Console.log in Production Code
|
||||
**Locations:** Multiple files
|
||||
| File | Line | Usage |
|
||||
|------|------|-------|
|
||||
| `IconsList.tsx` | ~65 | `console.error(error)` |
|
||||
| `IconMergeContainer.tsx` | ~118 | `console.log(pathList)` |
|
||||
| `IconMergeContainer.tsx` | ~122 | `console.log(e)` (drag event) |
|
||||
|
||||
**Risk:** Pollutes browser console, exposes internal data
|
||||
**Resolution:** Remove or replace with proper logging/error handling
|
||||
**Effort:** Low (1 hour)
|
||||
|
||||
---
|
||||
|
||||
### 3. Missing Error Boundaries
|
||||
**Issue:** No React error boundaries around components
|
||||
**Risk:** Single component error crashes entire app
|
||||
**Resolution:** Add error boundaries at route level
|
||||
**Effort:** Medium (4-6 hours)
|
||||
|
||||
---
|
||||
|
||||
### 4. No Loading States for Icon Controller
|
||||
**Location:** `src/IconController.tsx`
|
||||
**Issue:** Similar icons fetch has no loading indicator
|
||||
**Risk:** User sees empty space while loading
|
||||
**Resolution:** Add loading state for ML results
|
||||
**Effort:** Low (2 hours)
|
||||
|
||||
---
|
||||
|
||||
## 🟠 High Priority
|
||||
|
||||
### 5. TypeScript `any` Types
|
||||
**Locations:** Various
|
||||
| File | Issue |
|
||||
|------|-------|
|
||||
| `Icons.slice.ts` | `state: any` in selectors |
|
||||
| `IconInfo.slice.ts` | `state: any` in selectors |
|
||||
| `Icons.tsx` | `clickHandler(e: any)` |
|
||||
| `IconTile.tsx` | `navigate` param typing |
|
||||
|
||||
**Resolution:** Define proper RootState type and use throughout
|
||||
**Effort:** Medium (4-6 hours)
|
||||
|
||||
---
|
||||
|
||||
### 6. Incomplete Favorites Implementation
|
||||
**Location:** `Icons.slice.ts`
|
||||
**Issue:** `removeFavorite` has incorrect splice logic
|
||||
```typescript
|
||||
removeFavorite: (state, action: PayloadAction<IconTileProps>) => {
|
||||
state.favorites.splice(state.favorites.indexOf(action.payload))
|
||||
// Missing second argument to splice!
|
||||
}
|
||||
```
|
||||
**Risk:** Removes from wrong index to end
|
||||
**Resolution:** Fix splice or use filter
|
||||
**Effort:** Low (30 minutes)
|
||||
|
||||
---
|
||||
|
||||
### 7. Favorites Not Persisted
|
||||
**Issue:** Favorites stored only in Redux, lost on refresh
|
||||
**Resolution:** Sync to localStorage or backend
|
||||
**Effort:** Medium (4-6 hours)
|
||||
|
||||
---
|
||||
|
||||
### 8. Dead/Commented Code
|
||||
**Locations:**
|
||||
| File | Lines | Description |
|
||||
|------|-------|-------------|
|
||||
| `IconTile.tsx` | 41-82 | `generateTools` function |
|
||||
| `IconTile.tsx` | 100-103 | `iconTools` variable |
|
||||
| `IconController.tsx` | 37 | `getSuggestions` commented |
|
||||
|
||||
**Resolution:** Remove or complete implementation
|
||||
**Effort:** Low (1-2 hours)
|
||||
|
||||
---
|
||||
|
||||
### 9. Test Data in Production Code
|
||||
**Location:** `src/IconMergeContainer.tsx`
|
||||
**Issue:** 100+ lines of hardcoded `iconTest` array
|
||||
```typescript
|
||||
const iconTest = [
|
||||
{ name: "CiAlignBottom", icon: "...", ... },
|
||||
// 3 full icon objects
|
||||
]
|
||||
```
|
||||
**Risk:** Shipped to production, increases bundle size
|
||||
**Resolution:** Move to test file or mock data folder
|
||||
**Effort:** Low (1 hour)
|
||||
|
||||
---
|
||||
|
||||
## 🟡 Medium Priority
|
||||
|
||||
### 10. Missing Accessibility
|
||||
**Issue:** No ARIA labels, keyboard navigation incomplete
|
||||
| Component | Issue |
|
||||
|-----------|-------|
|
||||
| `IconTile` | No `role` attribute |
|
||||
| `IconStyleSelector` | Color pickers need labels |
|
||||
| `FavoritesList` | No keyboard navigation |
|
||||
|
||||
**Resolution:** Add ARIA attributes and keyboard handlers
|
||||
**Effort:** Medium (8-12 hours)
|
||||
|
||||
---
|
||||
|
||||
### 11. No Unit Tests
|
||||
**Issue:** 0% test coverage
|
||||
**Files needing tests:**
|
||||
- `helper.ts` - `downloadSvg()`, `complement()`
|
||||
- `Icons.slice.ts` - Reducer actions
|
||||
- `IconInfo.slice.ts` - Reducer actions
|
||||
- `IconTile.tsx` - Click handlers
|
||||
|
||||
**Resolution:** Add Vitest tests
|
||||
**Effort:** High (16-24 hours)
|
||||
|
||||
---
|
||||
|
||||
### 12. Inconsistent File Naming
|
||||
**Issue:** Mixed naming conventions
|
||||
- Some: `IconsList.component.scss`
|
||||
- Some: `IconController.component.scss`
|
||||
- Index: `IconInfo.slice.ts` vs folder `IconInfoSlice/`
|
||||
|
||||
**Root level folders unused:** `IconController/`, `IconEditor/`, `IconInfo/`, `IconInfoSlice/`, `IconStyleSelector/`, `IconTile/`, `Icons/`, `IconsMerge/`
|
||||
|
||||
**Resolution:** Choose convention, refactor file structure
|
||||
**Effort:** Medium (4-6 hours)
|
||||
|
||||
---
|
||||
|
||||
### 13. Large Initial Fetch
|
||||
**Location:** `src/IconsList.tsx`
|
||||
**Issue:** Fetches 2000 icons on load
|
||||
```typescript
|
||||
fetchIconsPage(2000, 0, filters, ...)
|
||||
```
|
||||
**Risk:** Slow initial load, high memory usage
|
||||
**Resolution:** Implement true pagination or virtual scrolling
|
||||
**Effort:** Medium (6-8 hours)
|
||||
|
||||
---
|
||||
|
||||
### 14. Missing Loading Skeleton
|
||||
**Issue:** Only spinner shown during load
|
||||
**Resolution:** Add skeleton components matching grid layout
|
||||
**Effort:** Low (3-4 hours)
|
||||
|
||||
---
|
||||
|
||||
## 🟢 Low Priority
|
||||
|
||||
### 15. Upload Button Non-functional
|
||||
**Location:** `src/IconsList.tsx`
|
||||
**Issue:** Upload button exists but has no handler
|
||||
```tsx
|
||||
<Button content="Upload" ... />
|
||||
```
|
||||
**Resolution:** Implement or remove
|
||||
**Effort:** High to implement (16+ hours)
|
||||
|
||||
---
|
||||
|
||||
### 16. Categories Menu Non-functional
|
||||
**Location:** `src/IconsList.tsx`
|
||||
**Issue:** Categories dropdown with hardcoded items
|
||||
```tsx
|
||||
splitOptions={[
|
||||
{ label: "All" },
|
||||
{ label: "Business" },
|
||||
{ label: "Medical" },
|
||||
]}
|
||||
```
|
||||
**Resolution:** Wire to actual category data
|
||||
**Effort:** Medium (4-6 hours)
|
||||
|
||||
---
|
||||
|
||||
### 17. Empty Top-Level Folders
|
||||
**Location:** Root directory
|
||||
**Issue:** Multiple empty folders from old structure:
|
||||
```
|
||||
IconController/
|
||||
IconEditor/
|
||||
IconInfo/
|
||||
IconInfoSlice/
|
||||
IconStyleSelector/
|
||||
IconTile/
|
||||
Icons/
|
||||
IconsMerge/
|
||||
Clusters/
|
||||
helper/
|
||||
```
|
||||
**Resolution:** Remove or migrate files into them
|
||||
**Effort:** Low (1 hour)
|
||||
|
||||
---
|
||||
|
||||
### 18. Outdated README
|
||||
**Location:** `README.md`
|
||||
**Issue:** Single line, no setup instructions
|
||||
**Resolution:** Update with proper documentation
|
||||
**Effort:** Low (2-3 hours)
|
||||
|
||||
---
|
||||
|
||||
## Debt Resolution Priority Matrix
|
||||
|
||||
| Priority | Items | Total Effort |
|
||||
|----------|-------|--------------|
|
||||
| 🔴 Critical | 4 items | 8-12 hours |
|
||||
| 🟠 High | 5 items | 11-16 hours |
|
||||
| 🟡 Medium | 5 items | 37-54 hours |
|
||||
| 🟢 Low | 4 items | 23-30 hours |
|
||||
|
||||
**Recommended Sprint 1 Focus:**
|
||||
1. Fix hardcoded ML service URL
|
||||
2. Remove console.log statements
|
||||
3. Fix removeFavorite splice bug
|
||||
4. Remove test data from IconMergeContainer
|
||||
5. Add RootState typing to Redux selectors
|
||||
219
docs/DESIGN.md
Normal file
219
docs/DESIGN.md
Normal file
@@ -0,0 +1,219 @@
|
||||
# icon-spot - Design Documentation
|
||||
|
||||
## Component Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ icon-spot Application │
|
||||
│ │
|
||||
│ ┌────────────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ Redux Store (store.ts) │ │
|
||||
│ │ ┌─────────────────────────┐ ┌─────────────────────────┐ │ │
|
||||
│ │ │ Icons.slice.ts │ │ IconInfo.slice.ts │ │ │
|
||||
│ │ │ - favorites │ │ - iconStyles │ │ │
|
||||
│ │ │ - selectedTag │ │ (fill, stroke, bg) │ │ │
|
||||
│ │ └─────────────────────────┘ └─────────────────────────┘ │ │
|
||||
│ └────────────────────────────────────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ┌──────────────┴──────────────┐ │
|
||||
│ ▼ ▼ │
|
||||
│ ┌──────────────────────────────┐ ┌──────────────────────────────┐ │
|
||||
│ │ Icons.tsx │ │ IconInfo.tsx │ │
|
||||
│ │ (Main Browser Container) │ │ (Detail View Container) │ │
|
||||
│ └─────────────┬────────────────┘ └─────────────┬────────────────┘ │
|
||||
│ │ │ │
|
||||
│ ┌────────┴────────┐ ┌───────┴───────┐ │
|
||||
│ ▼ ▼ ▼ ▼ │
|
||||
│ ┌──────────┐ ┌──────────────┐ ┌────────────┐ ┌──────────────┐ │
|
||||
│ │ Filters │ │ IconsList │ │IconController│ │ IconEditor │ │
|
||||
│ │ (Sidebar)│ │ (Grid) │ │ (Main) │ │ (Panel) │ │
|
||||
│ └──────────┘ └──────┬───────┘ └──────┬──────┘ └──────────────┘ │
|
||||
│ │ │ │
|
||||
│ ┌────────┼────────┐ │ │
|
||||
│ ▼ ▼ ▼ ▼ │
|
||||
│ ┌────────┐ ┌────────┐ ┌────────────────────┐ │
|
||||
│ │IconTile│ │IconTile│ │IconStyleSelector │ │
|
||||
│ └────────┘ └────────┘ └────────────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Data Flow: Icon Browser
|
||||
|
||||
```
|
||||
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
|
||||
│ User Action │────▶│ Component │────▶│ API Call │
|
||||
│ │ │ useState │ │ getStatic │
|
||||
└───────────────┘ └───────────────┘ └───────┬───────┘
|
||||
│
|
||||
▼
|
||||
┌───────────────┐
|
||||
│ ArmoryStatic │
|
||||
│ Backend │
|
||||
└───────┬───────┘
|
||||
│
|
||||
┌──────────────────────────────┘
|
||||
▼
|
||||
┌───────────────┐ ┌───────────────┐
|
||||
│ Response Body │────▶│ setIcons │
|
||||
│ IconResponse[]│ │ setPage │
|
||||
└───────────────┘ └───────┬───────┘
|
||||
│
|
||||
▼
|
||||
┌───────────────┐
|
||||
│ IconTile x N │
|
||||
│ (Grid) │
|
||||
└───────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Data Flow: Icon Style Update
|
||||
|
||||
```
|
||||
┌───────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Style Update Flow │
|
||||
│ │
|
||||
│ ┌────────────────┐ ┌────────────────┐ ┌────────────────┐ │
|
||||
│ │AdvancedColor │───▶│setIconStyles │───▶│ iconInfoSlice │ │
|
||||
│ │Picker onChange │ │ (local state) │ │ (Redux action) │ │
|
||||
│ └────────────────┘ └────────────────┘ └───────┬────────┘ │
|
||||
│ │ │
|
||||
│ ┌──────────────────────────────┘ │
|
||||
│ ▼ │
|
||||
│ ┌────────────────┐ ┌────────────────┐ │
|
||||
│ │ iconInfo.state │───▶│ useSelector │ │
|
||||
│ │ { iconStyles } │ │ getIconStyles │ │
|
||||
│ └────────────────┘ └───────┬────────┘ │
|
||||
│ │ │
|
||||
│ ┌─────────────────────┼─────────────────────┐ │
|
||||
│ ▼ ▼ ▼ │
|
||||
│ ┌────────────────┐ ┌────────────────┐ ┌────────────────┐ │
|
||||
│ │ IconTile │ │ IconController │ │ Icon Preview │ │
|
||||
│ │ (fillColor) │ │ (all styles) │ │ (all styles) │ │
|
||||
│ └────────────────┘ └────────────────┘ └────────────────┘ │
|
||||
└───────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Data Flow: Icon Download
|
||||
|
||||
```
|
||||
User clicks Download
|
||||
│
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ IconController │
|
||||
│ onClick handler │
|
||||
└────────┬────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────┐ ┌─────────────────┐
|
||||
│ downloadSvg() │───▶│ applyStyles() │
|
||||
│ helper.ts │ │ @armco/icon │
|
||||
└────────┬────────┘ └─────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────┐ ┌─────────────────┐
|
||||
│ DOMParser │───▶│ btoa() encode │
|
||||
│ Parse SVG │ │ Base64 string │
|
||||
└─────────────────┘ └────────┬────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ Create <a> tag │
|
||||
│ Trigger download│
|
||||
└─────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Feature Completion Matrix
|
||||
|
||||
| Feature | Status | What's Done | What's Pending | Potential Additions |
|
||||
|---------|--------|-------------|----------------|---------------------|
|
||||
| **Icon Grid** | ✅ Complete | Pagination, search, filters | - | Infinite scroll |
|
||||
| **View Modes** | ✅ Complete | Comfy, Compact, List | - | Custom grid size |
|
||||
| **Tag Filtering** | ✅ Complete | Sidebar filter, tag click | - | Multi-tag select |
|
||||
| **Search** | ✅ Complete | Debounced text search | - | Fuzzy matching |
|
||||
| **Icon Preview** | ✅ Complete | Multi-size display | - | Custom size input |
|
||||
| **Style Editor** | ✅ Complete | Fill, stroke, bg, width | - | Gradients, shadows |
|
||||
| **SVG Download** | ✅ Complete | Styled SVG download | - | PNG/WebP export |
|
||||
| **Favorites** | ⚠️ Partial | Add to favorites | Persist to backend | Sync with account |
|
||||
| **Selection Mode** | ✅ Complete | Multi-select UI | - | Bulk operations |
|
||||
| **Icon Merge** | ❌ Incomplete | SVG parsing, UI shell | Drag/drop, save | Path editing |
|
||||
| **Similar Icons** | ⚠️ Partial | ML integration | Requires local service | Pre-computed cache |
|
||||
| **Clusters** | ⚠️ Partial | Display only | Cluster navigation | Click to filter |
|
||||
| **Animation** | ⚠️ Route only | Navigation exists | Separate module | Integrate inline |
|
||||
| **Categories** | ❌ Stub | Menu button exists | Category data | Category pages |
|
||||
| **Upload** | ❌ Stub | Button exists | Upload flow | Validation, preview |
|
||||
|
||||
---
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
icon-spot/
|
||||
├── src/
|
||||
│ ├── index.tsx # Exports
|
||||
│ ├── store.ts # Redux store config
|
||||
│ ├── types.ts # TypeScript types
|
||||
│ ├── helper.ts # Utility functions
|
||||
│ │
|
||||
│ ├── Icons.tsx # Main browser container
|
||||
│ ├── Icons.slice.ts # Icons Redux slice
|
||||
│ ├── IconsList.tsx # Icon grid component
|
||||
│ ├── IconsList.component.scss # Grid styles
|
||||
│ │
|
||||
│ ├── IconInfo.tsx # Detail view container
|
||||
│ ├── IconInfo.slice.ts # Icon info Redux slice
|
||||
│ │
|
||||
│ ├── IconTile.tsx # Icon card component
|
||||
│ ├── IconTile.component.scss # Card styles
|
||||
│ │
|
||||
│ ├── IconController.tsx # Detail view main
|
||||
│ ├── IconController.component.scss
|
||||
│ │
|
||||
│ ├── IconEditor.tsx # Style editor wrapper
|
||||
│ ├── IconStyleSelector.tsx # Color/stroke controls
|
||||
│ │
|
||||
│ ├── FavoritesList.tsx # Favorites panel
|
||||
│ ├── FavoritesList.component.scss
|
||||
│ │
|
||||
│ ├── IconsMerge.tsx # Merge container
|
||||
│ ├── IconMergeContainer.tsx # Merge implementation
|
||||
│ ├── IconMergeContainer.component.scss
|
||||
│ │
|
||||
│ └── Clusters.tsx # ML clusters view
|
||||
│
|
||||
├── build-tools/
|
||||
│ ├── build.sh # Build script
|
||||
│ ├── generate-module.js # Module generator
|
||||
│ └── post-processor.js # Build post-processing
|
||||
│
|
||||
├── vite.config.ts # Library build config
|
||||
├── vite-dev.config.ts # Dev server config
|
||||
├── vite-run.config.ts # Standalone run config
|
||||
├── tsconfig.json # TypeScript config
|
||||
└── package.json # Package definition
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Component Props Summary
|
||||
|
||||
| Component | Key Props |
|
||||
|-----------|-----------|
|
||||
| `Icons` | None (self-contained) |
|
||||
| `IconInfo` | Route params: `group`, `name` |
|
||||
| `IconsList` | `filters?`, `tags?` |
|
||||
| `IconTile` | `icon`, `onClick?`, `selectable?`, `type?`, `iconSize?` |
|
||||
| `IconController` | `group?`, `icon?`, `name?` |
|
||||
| `IconEditor` | `layout?` |
|
||||
| `IconStyleSelector` | `iconStyles?`, `setIconStyles`, `layout?` |
|
||||
| `FavoritesList` | `classes?` |
|
||||
| `IconsMerge` | Location state: `icons` |
|
||||
| `Clusters` | None |
|
||||
249
docs/READINESS.md
Normal file
249
docs/READINESS.md
Normal file
@@ -0,0 +1,249 @@
|
||||
# icon-spot - Production Readiness Checklist
|
||||
|
||||
## Overview
|
||||
|
||||
This document tracks production readiness for icon-spot as a standalone application and as an npm package consumed by other Armco applications.
|
||||
|
||||
---
|
||||
|
||||
## 1. Build & Packaging
|
||||
|
||||
| Item | Status | Notes |
|
||||
|------|--------|-------|
|
||||
| ESM Build | ✅ | `build/es/` output |
|
||||
| CJS Build | ✅ | `build/cjs/` output |
|
||||
| Type Definitions | ✅ | `build/types/` output |
|
||||
| CSS Injection | ✅ | Using `vite-plugin-lib-inject-css` |
|
||||
| Tree Shaking | ✅ | Configured in rollup |
|
||||
| External Dependencies | ✅ | React, armco libs externalized |
|
||||
| Source Maps | ❌ | Not generated in production build |
|
||||
| Bundle Size Analysis | ❌ | No bundle analyzer configured |
|
||||
|
||||
### Actions Required:
|
||||
- [ ] Enable source maps for debugging
|
||||
- [ ] Add bundle size analysis to CI
|
||||
|
||||
---
|
||||
|
||||
## 2. Code Quality
|
||||
|
||||
| Item | Status | Notes |
|
||||
|------|--------|-------|
|
||||
| TypeScript Strict Mode | ⚠️ | Some `any` types present |
|
||||
| ESLint Configured | ✅ | Via eslintConfig in package.json |
|
||||
| Prettier Configured | ✅ | Using prettier-config-nick |
|
||||
| No Console Statements | ❌ | console.log/error in code |
|
||||
| Error Boundaries | ❌ | No React error boundaries |
|
||||
| PropTypes/Type Safety | ⚠️ | Types defined but not strict |
|
||||
|
||||
### Actions Required:
|
||||
- [ ] Remove all console.log/error statements
|
||||
- [ ] Add error boundaries at route level
|
||||
- [ ] Enforce strict TypeScript
|
||||
|
||||
---
|
||||
|
||||
## 3. Testing
|
||||
|
||||
| Item | Status | Notes |
|
||||
|------|--------|-------|
|
||||
| Unit Tests | ❌ | 0% coverage |
|
||||
| Component Tests | ❌ | No tests |
|
||||
| Integration Tests | ❌ | No tests |
|
||||
| Visual Regression | ❌ | No Storybook/Chromatic |
|
||||
| Accessibility Tests | ❌ | No a11y testing |
|
||||
|
||||
### Actions Required:
|
||||
- [ ] Add Vitest configuration
|
||||
- [ ] Write tests for helper functions
|
||||
- [ ] Write tests for Redux slices
|
||||
- [ ] Add component tests for IconTile, IconsList
|
||||
|
||||
---
|
||||
|
||||
## 4. Accessibility
|
||||
|
||||
| Item | Status | Notes |
|
||||
|------|--------|-------|
|
||||
| Semantic HTML | ⚠️ | Basic semantics |
|
||||
| ARIA Labels | ❌ | Missing throughout |
|
||||
| Keyboard Navigation | ⚠️ | Partial support |
|
||||
| Focus Management | ❌ | Not implemented |
|
||||
| Screen Reader Testing | ❌ | Not tested |
|
||||
| Color Contrast | ⚠️ | Not verified |
|
||||
|
||||
### Actions Required:
|
||||
- [ ] Add ARIA labels to interactive elements
|
||||
- [ ] Implement keyboard navigation for icon grid
|
||||
- [ ] Add focus ring styles
|
||||
- [ ] Test with screen reader
|
||||
|
||||
---
|
||||
|
||||
## 5. Performance
|
||||
|
||||
| Item | Status | Notes |
|
||||
|------|--------|-------|
|
||||
| Code Splitting | ⚠️ | All exports in single chunk |
|
||||
| Lazy Loading | ❌ | All components loaded eagerly |
|
||||
| Virtual Scrolling | ❌ | Loads all 2000 icons |
|
||||
| Memoization | ⚠️ | Minimal use of useMemo/useCallback |
|
||||
| Image Optimization | ⚠️ | Base64 SVGs (reasonable) |
|
||||
| Bundle Size | ⚠️ | Not optimized |
|
||||
|
||||
### Actions Required:
|
||||
- [ ] Implement virtual scrolling for icon grid
|
||||
- [ ] Add React.lazy for route components
|
||||
- [ ] Profile and optimize re-renders
|
||||
- [ ] Reduce initial fetch size
|
||||
|
||||
---
|
||||
|
||||
## 6. State Management
|
||||
|
||||
| Item | Status | Notes |
|
||||
|------|--------|-------|
|
||||
| Redux DevTools | ✅ | Configured with name |
|
||||
| State Persistence | ❌ | Lost on refresh |
|
||||
| Error State | ❌ | No error handling in slices |
|
||||
| Loading State | ⚠️ | Local component state only |
|
||||
| Typed Selectors | ❌ | Uses `any` |
|
||||
|
||||
### Actions Required:
|
||||
- [ ] Add RootState type to store
|
||||
- [ ] Implement redux-persist for favorites
|
||||
- [ ] Add error and loading states to slices
|
||||
|
||||
---
|
||||
|
||||
## 7. API Integration
|
||||
|
||||
| Item | Status | Notes |
|
||||
|------|--------|-------|
|
||||
| Error Handling | ❌ | No user-facing error messages |
|
||||
| Retry Logic | ❌ | No retry on failure |
|
||||
| Loading States | ⚠️ | Basic spinner only |
|
||||
| Caching | ❌ | No response caching |
|
||||
| Offline Support | ❌ | Not considered |
|
||||
|
||||
### Actions Required:
|
||||
- [ ] Add error toasts for failed requests
|
||||
- [ ] Implement retry logic for transient failures
|
||||
- [ ] Add response caching (react-query or SWR)
|
||||
|
||||
---
|
||||
|
||||
## 8. Environment Configuration
|
||||
|
||||
| Item | Status | Notes |
|
||||
|------|--------|-------|
|
||||
| Environment Variables | ⚠️ | .env exists |
|
||||
| Config Validation | ❌ | No validation |
|
||||
| API URL Configuration | ✅ | Now uses `API_CONFIG.TASKER[process.env.NODE_ENV]` |
|
||||
| Feature Flags | ❌ | Not implemented |
|
||||
|
||||
### Actions Required:
|
||||
- [x] ~~Move all URLs to environment config~~ ✅ DONE
|
||||
- [ ] Add config validation on startup
|
||||
- [ ] Implement feature flags for incomplete features
|
||||
|
||||
---
|
||||
|
||||
## 9. Documentation
|
||||
|
||||
| Item | Status | Notes |
|
||||
|------|--------|-------|
|
||||
| README | ✅ | Updated with comprehensive docs |
|
||||
| API Documentation | ❌ | No docs |
|
||||
| Component Storybook | ❌ | Not set up |
|
||||
| Usage Examples | ✅ | Provided in README |
|
||||
| Changelog | ❌ | Not maintained |
|
||||
|
||||
### Actions Required:
|
||||
- [ ] Write comprehensive README
|
||||
- [ ] Add JSDoc comments to exports
|
||||
- [ ] Consider Storybook setup
|
||||
- [ ] Maintain CHANGELOG.md
|
||||
|
||||
---
|
||||
|
||||
## 10. Security
|
||||
|
||||
| Item | Status | Notes |
|
||||
|------|--------|-------|
|
||||
| XSS Prevention | ⚠️ | React escapes by default |
|
||||
| SVG Sanitization | ❌ | Direct innerHTML via dangerouslySetInnerHTML |
|
||||
| CORS Handling | ⚠️ | Backend configured |
|
||||
| Dependency Audit | ⚠️ | Needs `npm audit` |
|
||||
|
||||
### Actions Required:
|
||||
- [ ] Sanitize SVG content before rendering
|
||||
- [ ] Run `npm audit fix`
|
||||
- [ ] Review third-party dependencies
|
||||
|
||||
---
|
||||
|
||||
## Production Readiness Score
|
||||
|
||||
| Category | Score | Max |
|
||||
|----------|-------|-----|
|
||||
| Build & Packaging | 5 | 8 |
|
||||
| Code Quality | 2 | 6 |
|
||||
| Testing | 0 | 5 |
|
||||
| Accessibility | 1 | 5 |
|
||||
| Performance | 1 | 6 |
|
||||
| State Management | 1 | 5 |
|
||||
| API Integration | 0.5 | 5 |
|
||||
| Environment Config | 1 | 4 |
|
||||
| Documentation | 0 | 5 |
|
||||
| Security | 1.5 | 4 |
|
||||
| **Total** | **13** | **53** |
|
||||
|
||||
**Readiness Level: 25% - NOT READY FOR PRODUCTION**
|
||||
|
||||
---
|
||||
|
||||
## Minimum Viable Production Checklist
|
||||
|
||||
### Week 1: Critical Fixes
|
||||
- [ ] Remove hardcoded ML service URL
|
||||
- [ ] Remove console.log statements
|
||||
- [ ] Fix removeFavorite splice bug
|
||||
- [ ] Add error boundaries
|
||||
|
||||
### Week 2: Quality & Stability
|
||||
- [ ] Add RootState typing
|
||||
- [ ] Remove test data from production code
|
||||
- [ ] Clean up unused folders
|
||||
- [ ] Update README
|
||||
|
||||
### Week 3: UX Improvements
|
||||
- [ ] Add error toasts for failed requests
|
||||
- [ ] Implement loading skeletons
|
||||
- [ ] Reduce initial fetch size (500 max)
|
||||
|
||||
### Week 4: Testing & Polish
|
||||
- [ ] Add unit tests for helpers
|
||||
- [ ] Add tests for Redux slices
|
||||
- [ ] Run accessibility audit
|
||||
- [ ] Run npm audit
|
||||
|
||||
---
|
||||
|
||||
## Package Consumption Checklist
|
||||
|
||||
For apps consuming `@armco/icon-spot`:
|
||||
|
||||
| Requirement | Provided |
|
||||
|-------------|----------|
|
||||
| Peer dependencies documented | ✅ |
|
||||
| Type definitions | ✅ |
|
||||
| CSS bundled | ✅ |
|
||||
| Tree-shakeable | ✅ |
|
||||
| Redux store required | ⚠️ Needs documentation |
|
||||
| Router required | ⚠️ Needs documentation |
|
||||
|
||||
### Integration Requirements:
|
||||
1. Wrap with Redux Provider containing `icons` and `iconInfo` reducers
|
||||
2. Wrap with BrowserRouter
|
||||
3. Configure ArmoryStatic API endpoint in environment
|
||||
223
docs/SPECS.md
Normal file
223
docs/SPECS.md
Normal file
@@ -0,0 +1,223 @@
|
||||
# icon-spot - Feature Specifications
|
||||
|
||||
## Overview
|
||||
|
||||
**icon-spot** is a React-based icon management application that provides browsing, searching, editing, and downloading capabilities for the Armco icon library. It consumes the ArmoryStatic backend API.
|
||||
|
||||
---
|
||||
|
||||
## Technology Stack
|
||||
|
||||
| Component | Technology | Version |
|
||||
|-----------|------------|---------|
|
||||
| UI Framework | React | 18/19 |
|
||||
| State Management | Redux Toolkit | 2.x |
|
||||
| Routing | react-router-dom | 6.x |
|
||||
| Build Tool | Vite | 5.x |
|
||||
| Styling | SCSS (Dart Sass) | 1.x |
|
||||
| Language | TypeScript | 5.x |
|
||||
| Package Format | ESM + CJS | - |
|
||||
|
||||
---
|
||||
|
||||
## Exported Components
|
||||
|
||||
### Primary Exports
|
||||
|
||||
| Component | Description | Export Path |
|
||||
|-----------|-------------|-------------|
|
||||
| `Icons` | Main icon browser with filters, search, pagination | `@armco/icon-spot` (default) |
|
||||
| `IconInfo` | Individual icon detail page with editor | `@armco/icon-spot/IconInfo` |
|
||||
| `IconsMerge` | Multi-icon selection and merge tool | `@armco/icon-spot/IconsMerge` |
|
||||
| `Clusters` | ML-generated icon cluster visualization | `@armco/icon-spot/Clusters` |
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
### 1. Icon Browser (`Icons.tsx` → `IconsList.tsx`)
|
||||
|
||||
**Description:** Main grid view for browsing all available icons
|
||||
|
||||
**Capabilities:**
|
||||
- Paginated icon grid (2000 icons per fetch, 100 per page)
|
||||
- Tag-based filtering via sidebar
|
||||
- Text search with debounce (1 second)
|
||||
- Multiple view modes: Comfy, Compact, List
|
||||
- Icon style customization (fill, stroke, background)
|
||||
- Selection mode for multi-icon operations
|
||||
|
||||
**API Integration:**
|
||||
- `GET /icon/tag/all?variants=gt100` - Fetch tags
|
||||
- `GET /icon/page?pageSize=2000&from=0` - Fetch icons
|
||||
|
||||
**State Management:**
|
||||
- `Icons.slice.ts` - Manages favorites and selected tag
|
||||
- `IconInfo.slice.ts` - Manages icon styles
|
||||
|
||||
---
|
||||
|
||||
### 2. Icon Detail View (`IconInfo.tsx` → `IconController.tsx`)
|
||||
|
||||
**Description:** Detailed view for individual icon with download and styling
|
||||
|
||||
**Capabilities:**
|
||||
- Icon preview at multiple sizes (3rem, 7rem)
|
||||
- Real-time style editing (fill, stroke, background, stroke-width)
|
||||
- SVG download with applied styles
|
||||
- Navigate to animation editor
|
||||
- Similar icon suggestions via ML service
|
||||
- Tag display and editing
|
||||
- Breadcrumb navigation
|
||||
|
||||
**API Integration:**
|
||||
- `GET /static/{group}_{name}-black.png` - Get PNG for ML
|
||||
- `POST http://localhost:5002/api/similar-icon-paths` - Get similar icons
|
||||
- `POST /icon/png-to-svg` - Convert similar PNGs to SVG
|
||||
|
||||
**Helper Functions:**
|
||||
- `downloadSvg()` - Generate styled SVG download
|
||||
- `complement()` - Calculate complementary color for contrast
|
||||
|
||||
---
|
||||
|
||||
### 3. Icon Style Selector (`IconStyleSelector.tsx`)
|
||||
|
||||
**Description:** Color picker panel for customizing icon appearance
|
||||
|
||||
**Properties:**
|
||||
- `fillColor` - Interior color
|
||||
- `strokeColor` - Border/outline color
|
||||
- `strokeWidth` - Stroke thickness (1-10)
|
||||
- `bgColor` - Background color
|
||||
|
||||
**Components Used:**
|
||||
- `AdvancedColorPicker` - Color selection
|
||||
- `Slider` - Stroke width adjustment
|
||||
|
||||
---
|
||||
|
||||
### 4. Icon Tile (`IconTile.tsx`)
|
||||
|
||||
**Description:** Individual icon card component
|
||||
|
||||
**Display Modes:**
|
||||
- `comfy` - Large grid cells
|
||||
- `compact` - Small grid cells
|
||||
- `list` - Horizontal list layout
|
||||
|
||||
**Interactions:**
|
||||
- Click → Navigate to icon detail
|
||||
- Hover → Change fill color
|
||||
- Footer click → Copy icon link to clipboard
|
||||
- Selectable mode → Checkbox selection
|
||||
|
||||
---
|
||||
|
||||
### 5. Favorites List (`FavoritesList.tsx`)
|
||||
|
||||
**Description:** Right panel showing user's favorited icons
|
||||
|
||||
**Features:**
|
||||
- Login state awareness
|
||||
- Sync warning for anonymous users
|
||||
- Animated add/remove transitions
|
||||
- Login prompt for guests
|
||||
|
||||
**State Source:** `Icons.slice.ts` → `getFavorites`
|
||||
|
||||
---
|
||||
|
||||
### 6. Icon Merge (`IconsMerge.tsx` → `IconMergeContainer.tsx`)
|
||||
|
||||
**Description:** Tool for combining multiple icons
|
||||
|
||||
**Current Status:** Partial implementation
|
||||
- SVG parsing and display
|
||||
- Path extraction from SVGs
|
||||
- Drag-and-drop started (incomplete)
|
||||
|
||||
---
|
||||
|
||||
### 7. Clusters (`Clusters.tsx`)
|
||||
|
||||
**Description:** Visualization of ML-generated icon clusters
|
||||
|
||||
**API Integration:**
|
||||
- `GET /icon/clusters` - Fetch cluster data
|
||||
|
||||
**Display:** Grid of cluster groups with PNG thumbnails
|
||||
|
||||
---
|
||||
|
||||
## Redux Store Structure
|
||||
|
||||
```typescript
|
||||
{
|
||||
icons: {
|
||||
favorites: IconTileProps[], // Favorited icons
|
||||
selectedTag?: string // Currently selected filter tag
|
||||
},
|
||||
iconInfo: {
|
||||
iconStyles?: {
|
||||
fillColor?: string,
|
||||
strokeColor?: string,
|
||||
bgColor?: string,
|
||||
strokeWidth?: string
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Route Structure
|
||||
|
||||
| Route | Component | Description |
|
||||
|-------|-----------|-------------|
|
||||
| `/` | `Icons` | Main icon browser |
|
||||
| `/icon/:group/:name` | `IconInfo` | Icon detail page |
|
||||
| `/icons/merge-icons` | `IconsMerge` | Multi-icon merge tool |
|
||||
| `/icon/animate` | External | Animation editor |
|
||||
|
||||
---
|
||||
|
||||
## Peer Dependencies
|
||||
|
||||
```json
|
||||
{
|
||||
"@armco/components": "^0.0.60",
|
||||
"@armco/configs": "^0.0.11",
|
||||
"@armco/icon": "^0.0.10",
|
||||
"@armco/types": "^0.0.18",
|
||||
"@armco/utils": "^0.0.29",
|
||||
"@reduxjs/toolkit": "^1.8.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-redux": "^8.0.1",
|
||||
"react-router-dom": "^6.13.0"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Build Output
|
||||
|
||||
```
|
||||
build/
|
||||
├── cjs/ # CommonJS modules
|
||||
├── es/ # ES modules
|
||||
└── types/ # TypeScript declarations
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Configuration Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `vite.config.ts` | Library build configuration |
|
||||
| `vite-dev.config.ts` | Development server |
|
||||
| `vite-run.config.ts` | Standalone run mode |
|
||||
| `tsconfig.json` | TypeScript configuration |
|
||||
| `.env` | Environment variables |
|
||||
102
package-lock.json
generated
102
package-lock.json
generated
@@ -9,7 +9,8 @@
|
||||
"version": "0.0.6",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"bootstrap": "^5.3.8"
|
||||
"bootstrap": "^5.3.8",
|
||||
"react-router": "^6.22.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@armco/components": "^0.0.60",
|
||||
@@ -31,7 +32,7 @@
|
||||
"react": "^19.2.3",
|
||||
"react-dom": "^19.2.3",
|
||||
"react-redux": "^9.2.0",
|
||||
"react-router-dom": "^7.11.0",
|
||||
"react-router-dom": "^6.22.3",
|
||||
"sass-embedded": "^1.97.1",
|
||||
"typescript": "^5.9.3",
|
||||
"uuid": "^13.0.0",
|
||||
@@ -156,40 +157,6 @@
|
||||
"react": "^18.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@armco/shared-components/node_modules/react-router": {
|
||||
"version": "6.30.2",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.2.tgz",
|
||||
"integrity": "sha512-H2Bm38Zu1bm8KUE5NVWRMzuIyAV8p/JrOaBJAwVmp37AXG72+CZJlEBw6pdn9i5TBgLMhNDgijS4ZlblpHyWTA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@remix-run/router": "1.23.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@armco/shared-components/node_modules/react-router-dom": {
|
||||
"version": "6.30.2",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.2.tgz",
|
||||
"integrity": "sha512-l2OwHn3UUnEVUqc6/1VMmR1cvZryZ3j3NzapC2eUXO1dB0sYp5mvwdjiXhpUbRb21eFow3qSxpP8Yv6oAU824Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@remix-run/router": "1.23.1",
|
||||
"react-router": "6.30.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8",
|
||||
"react-dom": ">=16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@armco/shared-components/node_modules/scheduler": {
|
||||
"version": "0.23.2",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
|
||||
@@ -1920,10 +1887,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@remix-run/router": {
|
||||
"version": "1.23.1",
|
||||
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.1.tgz",
|
||||
"integrity": "sha512-vDbaOzF7yT2Qs4vO6XV1MHcJv+3dgR1sT+l3B8xxOVhUC336prMvqrvsLL/9Dnw2xr6Qhz4J0dmS0llNAbnUmQ==",
|
||||
"dev": true,
|
||||
"version": "1.15.3",
|
||||
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.15.3.tgz",
|
||||
"integrity": "sha512-Oy8rmScVrVxWZVOpEF57ovlnhpZ8CCPlnIIumVcV9nFdiSIrus99+Lw78ekXyGvVDlIsFJbSfmSovJUhCWYV3w==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
@@ -3450,20 +3416,6 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cookie": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz",
|
||||
"integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/core-js": {
|
||||
"version": "3.47.0",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.47.0.tgz",
|
||||
@@ -6079,43 +6031,36 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-router": {
|
||||
"version": "7.11.0",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.11.0.tgz",
|
||||
"integrity": "sha512-uI4JkMmjbWCZc01WVP2cH7ZfSzH91JAZUDd7/nIprDgWxBV1TkkmLToFh7EbMTcMak8URFRa2YoBL/W8GWnCTQ==",
|
||||
"dev": true,
|
||||
"version": "6.22.3",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.22.3.tgz",
|
||||
"integrity": "sha512-dr2eb3Mj5zK2YISHK++foM9w4eBnO23eKnZEDs7c880P6oKbrjz/Svg9+nxqtHQK+oMW4OtjZca0RqPglXxguQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cookie": "^1.0.1",
|
||||
"set-cookie-parser": "^2.6.0"
|
||||
"@remix-run/router": "1.15.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=18",
|
||||
"react-dom": ">=18"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
"react": ">=16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/react-router-dom": {
|
||||
"version": "7.11.0",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.11.0.tgz",
|
||||
"integrity": "sha512-e49Ir/kMGRzFOOrYQBdoitq3ULigw4lKbAyKusnvtDu2t4dBX4AGYPrzNvorXmVuOyeakai6FUPW5MmibvVG8g==",
|
||||
"version": "6.22.3",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.22.3.tgz",
|
||||
"integrity": "sha512-7ZILI7HjcE+p31oQvwbokjk6OA/bnFxrhJ19n82Ex9Ph8fNAq+Hm/7KchpMGlTgWhUxRHMMCut+vEtNpWpowKw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"react-router": "7.11.0"
|
||||
"@remix-run/router": "1.15.3",
|
||||
"react-router": "6.22.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=18",
|
||||
"react-dom": ">=18"
|
||||
"react": ">=16.8",
|
||||
"react-dom": ">=16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/react-transition-group": {
|
||||
@@ -6843,13 +6788,6 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/set-cookie-parser": {
|
||||
"version": "2.7.2",
|
||||
"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz",
|
||||
"integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/shebang-command": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
"react": "^19.2.3",
|
||||
"react-dom": "^19.2.3",
|
||||
"react-redux": "^9.2.0",
|
||||
"react-router-dom": "^7.11.0",
|
||||
"react-router-dom": "^6.22.3",
|
||||
"sass-embedded": "^1.97.1",
|
||||
"typescript": "^5.9.3",
|
||||
"uuid": "^13.0.0",
|
||||
@@ -86,6 +86,7 @@
|
||||
"vitest": "^4.0.8"
|
||||
},
|
||||
"dependencies": {
|
||||
"bootstrap": "^5.3.8"
|
||||
"bootstrap": "^5.3.8",
|
||||
"react-router": "^6.22.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ const IconController = (props: IconControllerProps): JSX.Element => {
|
||||
formData.append("file", file)
|
||||
formData.append("count", "20")
|
||||
post(
|
||||
"http://localhost:5002/api/similar-icon-paths",
|
||||
`${API_CONFIG.TASKER[process.env.NODE_ENV]}/similar-icon-paths`,
|
||||
formData,
|
||||
undefined,
|
||||
{ headers: { "Content-Type": "multipart/form-data" } },
|
||||
|
||||
@@ -116,8 +116,8 @@ const IconsList = (props: IconsListProps): JSX.Element => {
|
||||
}, [selectedTag, searchText])
|
||||
|
||||
const onIconTileClick = (iconProps: IconResponse) => {
|
||||
isSelectMode
|
||||
? setSelectedIcons((currentIcons) => {
|
||||
if (isSelectMode) {
|
||||
setSelectedIcons((currentIcons) => {
|
||||
currentIcons = [...(currentIcons || [])]
|
||||
const existingIconIndex = currentIcons?.findIndex(
|
||||
(currentIcon) => currentIcon.name === iconProps.name,
|
||||
@@ -129,12 +129,11 @@ const IconsList = (props: IconsListProps): JSX.Element => {
|
||||
}
|
||||
return currentIcons
|
||||
})
|
||||
: view?.name === ArIconTileTypes.COMPACT &&
|
||||
notify({
|
||||
show: true,
|
||||
message: `Icon link for ${iconProps.name} copied`,
|
||||
uid: uuid(),
|
||||
} else {
|
||||
navigate(`/icon/${iconProps.group}/${iconProps.name}`, {
|
||||
state: iconProps,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -24,6 +24,8 @@ export function downloadSvg(
|
||||
}
|
||||
|
||||
export const complement = (hex?: string) => {
|
||||
if (hex === "white") return "#000000"
|
||||
if (hex === "black") return "#ffffff"
|
||||
if (hex) {
|
||||
const hexParts = hex.substring(1).toLowerCase().split("")
|
||||
const hexMap = { a: 10, b: 11, c: 12, d: 13, e: 14, f: 15 }
|
||||
|
||||
Reference in New Issue
Block a user