--- sessionId: session-261002-165538-pjxq --- # Requirements ### Overview & Goals The objective of this initiative is to replace the fragmented, ad-hoc SVG icon implementations in `src/components/icons/` with a high-utility, predictable, and performant Vue 3 icon architecture. Currently, icons in the project are implemented with substantial inconsistencies: - Several icons wrap raw SVG markup inside container `
` tags with hardcoded layout properties (e.g., `class="h-4 w-4 cursor-pointer mx-2"`). - Other icons render raw SVG tags with inconsistent prop contracts (e.g., `:box="96"` vs `:viewBox="36"` vs `:width="20"` vs hardcoded inline styles). - Fills, strokes, and hover behaviors are frequently hardcoded in scoped CSS or inline SVG attributes, preventing utility classes (Tailwind CSS `text-*`, `fill-current`, `stroke-current`, `size-*`) from controlling colors and dimensions naturally. This proposal establishes a standardized, tree-shakeable, and type-safe icon system designed to maximize developer throughput, eliminate styling friction, reduce bundle waste, and ensure complete accessibility compliance. ### Scope #### In Scope - **Foundation Layer**: Create an extensible, typed `IconBase.vue` component and `types.ts` defining standard icon contracts (`IconName`, `IconSize`, sizing scales, accessibility attributes). - **Icon Normalization**: Refactor all 14 existing icon components (`Abstain`, `Arrow`, `Cancel`, `Confirm`, `DownArrow`, `Download`, `Filter`, `Identification`, `Menu`, `Plus`, `SpeechBubbles`, `Stack`, `ThumbsDown`, `ThumbsUp`) into pure SVG components using `currentColor` and consistent viewBox geometries. - **Dynamic Registry**: Create a unified `AppIcon.vue` for dynamic runtime icon rendering and `src/components/icons/index.ts` for clean tree-shakeable named exports. - **Call-Site Migration**: Refactor all 8 consuming components and views (`Sidebar.vue`, `ProposalContainer.vue`, `ProposalDetail.vue`, `ProposalExportCard.vue`, `ProposalVotingCard.vue`, `VotingControls.vue`, `AmendmentCarousel.vue`, `HomeView.vue`) to use the new icon interfaces and standard Tailwind classes. - **Build & Quality Assurance**: Ensure zero TypeScript errors (`vue-tsc`), clean Vite builds, and consistent rendering across light/dark backgrounds and responsive viewport sizes. #### Out of Scope - Introducing external heavyweight icon packages or third-party web font libraries that would increase bundle size or external network dependencies. - Modifying non-icon business logic, wallet integrations, or backend API service definitions. ### User Stories - **As a Developer**, I want all icons to behave as first-class Vue components with uniform props and `currentColor` support so that I can style their size, color, and hover states directly using Tailwind CSS without fighting inner scoped CSS or arbitrary wrapper `
`s. - **As a Developer**, I want autocompletion and type checking when specifying icon names so that runtime icon typos and missing assets are caught at compile time. - **As an End User**, I want all icons to render crisply, scale smoothly across devices, and support screen readers properly so that UI interactions are fast, intuitive, and accessible. ### Functional Requirements - **FR-1: Standardized Root Element**: Every individual icon component must render a semantic `` root element without superfluous wrapper `
` elements. - **FR-2: Sizing Flexibility**: Icons must accept standardized size presets (`'xs' | 'sm' | 'md' | 'lg' | 'xl'`), numerical/pixel dimensions, or inherit sizing directly from standard Tailwind classes (`size-4`, `w-5 h-5`). - **FR-3: Color & Theme Inheritance**: Icons must inherit foreground colors from their parent container by default via `fill="currentColor"` or `stroke="currentColor"`, allowing instant theme adaptations (`text-slate-500`, `hover:text-green-500`, `fill-amber-500`). - **FR-4: Dynamic & Direct Imports**: The system must support direct named component imports (e.g., `import { IconFilter } from '@/components/icons'`) and dynamic component resolution (e.g., ``). - **FR-5: Accessibility Support**: Decorative icons must default to `aria-hidden="true"`, while standalone interactive or informational icons must support customizable `title` and `role="img"` attributes. ### Non-Functional Requirements - **Performance**: Zero runtime overhead from external bundle bloat; SVG trees must remain tree-shakeable and lightweight. - **Type Safety**: Fully typed with TypeScript 5+ and Vue 3 ` ``` ### File Structure & Changes ``` src/ ├── components/ │ ├── icons/ │ │ ├── types.ts # [NEW] IconName, IconSize, Prop interfaces │ │ ├── IconBase.vue # [NEW] Common SVG wrapper component │ │ ├── AppIcon.vue # [NEW] Dynamic icon component resolver │ │ ├── index.ts # [NEW] Centralized export entry point │ │ ├── Abstain.vue # [REFACTORED] Standardized SVG component │ │ ├── Arrow.vue # [REFACTORED] Standardized SVG component │ │ ├── Cancel.vue # [REFACTORED] Standardized SVG component │ │ ├── Confirm.vue # [REFACTORED] Standardized SVG component │ │ ├── DownArrow.vue # [REFACTORED] Removed wrapper div & CSS overrides │ │ ├── Download.vue # [REFACTORED] Standardized SVG component │ │ ├── Filter.vue # [REFACTORED] Removed wrapper div & CSS overrides │ │ ├── Identification.vue # [REFACTORED] Removed wrapper div & standardized viewBox │ │ ├── Menu.vue # [REFACTORED] Removed wrapper div & standardized stroke/fill │ │ ├── Plus.vue # [REFACTORED] Removed wrapper div │ │ ├── SpeechBubbles.vue # [REFACTORED] Removed wrapper div & CSS overrides │ │ ├── Stack.vue # [REFACTORED] Standardized viewBox & removed hardcoded fill │ │ ├── ThumbsDown.vue # [REFACTORED] Standardized SVG component │ │ └── ThumbsUp.vue # [REFACTORED] Standardized SVG component │ ├── AmendmentCarousel.vue # [UPDATED] Clean icon props & Tailwind classes │ ├── ProposalContainer.vue # [UPDATED] Clean icon sizing without wrapper conflicts │ ├── ProposalDetail.vue # [UPDATED] Clean icon sizing without wrapper conflicts │ ├── ProposalExportCard.vue # [UPDATED] Clean icon props & transitions │ ├── ProposalVotingCard.vue # [UPDATED] Removed obsolete :box props; standardized colors │ ├── Sidebar.vue # [UPDATED] Replaced wrapped Filter with clean SVG icon │ └── VotingControls.vue # [UPDATED] Clean Tailwind fill & hover state integration └── views/ └── HomeView.vue # [UPDATED] Clean Stack icon styling ``` ### Risks & Mitigations - **Risk**: Visual regression if existing viewBox ratios or path alignments change during normalization. - *Mitigation*: Preserve the exact vector path strings and original coordinate spaces (`viewBox="0 0 30 30"`, `0 0 96 96"`, etc.) for each respective icon inside its component definition, ensuring 100% pixel-perfect output. - **Risk**: Missing layout spacing when removing wrapper divs (e.g. `mx-2`, `cursor-pointer`). - *Mitigation*: Move layout concerns (`mx-2`, `cursor-pointer`, flex alignments) directly to the consuming container or parent button elements at all call sites. # Testing ### Validation Approach Verification will follow a multi-tier approach to ensure structural, aesthetic, and functional correctness across the application: 1. **Static Type & Lint Validation**: Verify strict type conformity via TypeScript compiler (`vue-tsc -b`) to ensure no broken imports or invalid prop bindings exist. 2. **Component Integration & Build Validation**: Perform full production bundling (`vite build`) to confirm zero asset resolution issues or tree-shaking failures. 3. **Visual & Interaction Verification**: Validate icon rendering across all consuming views, checking sizing, color inheritance, hover states, and responsive behavior. ### Key Scenarios - **Scenario 1: Dynamic Icon Rendering (`AppIcon`)**: - Render `` and ``. - Expected: Correct SVGs render with specified colors, inheriting parent classes properly without extra container nodes. - **Scenario 2: Direct Component Import & Tailwind Utility Sizing**: - Render `` in `Sidebar.vue`. - Expected: Icon scales to 16x16px, displays in white, and transitions to light slate on hover without unwanted wrapper margins. - **Scenario 3: Interactive Voting Controls & Active States**: - In `VotingControls.vue` and `ProposalVotingCard.vue`, trigger approval and rejection vote states. - Expected: `Confirm` and `Cancel` icons respond dynamically to positive/negative vote states (`fill-green-500`, `fill-red-500`) with smooth transitions. - **Scenario 4: Carousel Navigation Chevrons**: - In `AmendmentCarousel.vue`, navigate through amendments using the left and right arrow buttons. - Expected: `Arrow` icon renders crisply, rotates correctly with Tailwind's `rotate-180` for left navigation, and responds to click events. ### Edge Cases - **Custom Dimension Overrides**: Passing explicit numeric `size={28}` or arbitrary Tailwind strings (`class="w-7 h-7"`) must scale SVG viewports smoothly without clipping. - **Accessibility Verification**: When `title` is supplied, `` must render a `` node and set `role="img"`; when omitted, it must set `aria-hidden="true"`. - **Empty or Missing Styling**: Icons with no explicit color class must default to `currentColor`, seamlessly adopting surrounding text color. # Delivery Steps ### ✓ Step 1: Establish IconBase and type system A unified `IconBase.vue` component and type definitions are created to serve as the standardized foundation for all project icons. - Define TypeScript contracts and type definitions in `src/components/icons/types.ts` (`IconName`, `IconSize`, `IconBaseProps`). - Create `src/components/icons/IconBase.vue` rendering a semantic `` root element with default classes (`inline-block shrink-0 align-middle select-none`), standardized sizing mapping (`xs`: 12px, `sm`: 16px, `md`: 20px, `lg`: 24px, `xl`: 32px or custom dimensions), `currentColor` inheritance, and accessibility attributes (`aria-hidden`, `role="img"`, `title`). - Create `src/components/icons/AppIcon.vue` providing dynamic lookup and rendering of icons by name with full type safety and prop forwarding. ### ✓ Step 2: Refactor and normalize all icon components All 14 icon components are refactored into clean, single-element SVG components adhering to the standardized base interface. - Remove extraneous `
` wrapper containers and hardcoded margins (`mx-2`) from `DownArrow.vue`, `Filter.vue`, `Identification.vue`, `Menu.vue`, `Plus.vue`, and `SpeechBubbles.vue`. - Eliminate hardcoded inline styles (`style="fill:#ffffff"`, `style="width: 10px; height: 20px;"`) and scoped hover overrides (`#speech-bubbles:hover`, `#down-arrow:hover`) in favor of standard `currentColor` / Tailwind class pass-through. - Standardize viewBox definitions and geometry across `Abstain.vue`, `Arrow.vue`, `Cancel.vue`, `Confirm.vue`, `Download.vue`, `Stack.vue`, `ThumbsDown.vue`, `ThumbsUp.vue`, and other icons. - Create `src/components/icons/index.ts` exporting all icon components as named exports, the dynamic `AppIcon` component, and relevant TypeScript types for streamlined imports. ### ✓ Step 3: Migrate consuming components to modernized icons All existing UI components and views are updated to consume the normalized icon system cleanly with Tailwind styling. - Update `src/components/Sidebar.vue` to use `` (or ``) cleanly inside navigation buttons without unwanted wrapper margins. - Update `src/components/ProposalContainer.vue` and `src/components/ProposalDetail.vue` to render `Identification` with proper dimensions and colors. - Update `src/components/VotingControls.vue` and `src/components/ProposalVotingCard.vue` to remove obsolete `:box` / `:width` / `:height` props from `Confirm`, `Cancel`, and `Abstain`, styling them with Tailwind classes (`size-5 text-green-500 hover:text-green-600 fill-current`). - Update `src/components/AmendmentCarousel.vue` and `src/components/ProposalExportCard.vue` to use standard arrow and download icons with seamless transition and hover effects. - Update `src/views/HomeView.vue` to replace inline styles on `Stack` with standard component props/classes. ### ✓ Step 4: Verify build integrity, visual fidelity, and accessibility The modernized icon system is validated across TypeScript compilation, build pipeline, and UI rendering. - Execute `vue-tsc -b` and `vite build` to guarantee zero type errors or broken import references across the application. - Verify visual fidelity, color transitions, hover states, and responsive layout scaling across all pages (Home, Proposal Detail, Voting modal, Carousel). - Ensure accessibility tags (`aria-hidden="true"` on decorative icons and appropriate labels on interactive icon buttons) work correctly without DOM nesting violations.