diff --git a/apps/browser-extension/src/entrypoints/contentScript/Popup.ts b/apps/browser-extension/src/entrypoints/contentScript/Popup.ts
index 7925843bb..53a694e39 100644
--- a/apps/browser-extension/src/entrypoints/contentScript/Popup.ts
+++ b/apps/browser-extension/src/entrypoints/contentScript/Popup.ts
@@ -2,8 +2,9 @@ import { sendMessage } from 'webext-bridge/content-script';
import { fillItem } from '@/entrypoints/contentScript/Form';
-import { DISABLED_SITES_KEY, TEMPORARY_DISABLED_SITES_KEY, GLOBAL_AUTOFILL_POPUP_ENABLED_KEY, VAULT_LOCKED_DISMISS_UNTIL_KEY, AUTOFILL_MATCHING_MODE_KEY, CUSTOM_EMAIL_HISTORY_KEY, CUSTOM_USERNAME_HISTORY_KEY, PLACEHOLDER_ICON_SVG } from '@/utils/Constants';
+import { DISABLED_SITES_KEY, TEMPORARY_DISABLED_SITES_KEY, GLOBAL_AUTOFILL_POPUP_ENABLED_KEY, VAULT_LOCKED_DISMISS_UNTIL_KEY, AUTOFILL_MATCHING_MODE_KEY, CUSTOM_EMAIL_HISTORY_KEY, CUSTOM_USERNAME_HISTORY_KEY } from '@/utils/Constants';
import { CreateIdentityGenerator, IdentityHelperUtils } from '@/utils/dist/core/identity-generator';
+import { ItemTypeIconSvgs } from '@/utils/dist/core/models/icons';
import type { Item, ItemField } from '@/utils/dist/core/models/vault';
import { ItemTypes, FieldKey, createSystemField } from '@/utils/dist/core/models/vault';
import { CreatePasswordGenerator, PasswordGenerator, PasswordSettings } from '@/utils/dist/core/password-generator';
@@ -627,7 +628,7 @@ function createItemList(items: Item[], input: HTMLInputElement, rootContainer: H
if (logoSrc) {
logoContainer.innerHTML = `
`;
} else {
- logoContainer.innerHTML = PLACEHOLDER_ICON_SVG;
+ logoContainer.innerHTML = ItemTypeIconSvgs.Placeholder;
}
itemInfo.appendChild(logoContainer);
const itemTextContainer = document.createElement('div');
diff --git a/apps/browser-extension/src/entrypoints/popup/components/Items/ItemIcon.tsx b/apps/browser-extension/src/entrypoints/popup/components/Items/ItemIcon.tsx
index fb5482d32..575095ad9 100644
--- a/apps/browser-extension/src/entrypoints/popup/components/Items/ItemIcon.tsx
+++ b/apps/browser-extension/src/entrypoints/popup/components/Items/ItemIcon.tsx
@@ -1,8 +1,12 @@
import React from 'react';
-import { PLACEHOLDER_ICON_SVG } from '@/utils/Constants';
+import type { ItemTypeIconKey } from '@/utils/dist/core/models/icons';
+import { ItemTypeIconSvgs } from '@/utils/dist/core/models/icons';
import type { Item } from '@/utils/dist/core/models/vault';
-import { FieldKey, ItemTypes } from '@/utils/dist/core/models/vault';
+import {
+ FieldKey,
+ ItemTypes,
+} from '@/utils/dist/core/models/vault';
import SqliteClient from '@/utils/SqliteClient';
type ItemIconProps = {
@@ -11,217 +15,50 @@ type ItemIconProps = {
};
/**
- * Credit card brand type
+ * Renders an SVG string as a React component using dangerouslySetInnerHTML.
+ * The SVG is wrapped in a div to apply className for sizing.
*/
-type CardBrand = 'visa' | 'mastercard' | 'amex' | 'discover' | 'generic';
+const SvgIcon: React.FC<{ svg: string; className?: string }> = ({ svg, className = 'w-8 h-8' }) => (
+
+);
/**
- * Detect credit card brand from card number using industry-standard prefixes
- * @param cardNumber - The card number to detect brand from
- * @returns The detected card brand
+ * Detect credit card brand from card number using BIN prefixes.
*/
-const detectCardBrand = (cardNumber: string | undefined): CardBrand => {
+const detectCardBrand = (cardNumber: string | undefined): ItemTypeIconKey => {
if (!cardNumber) {
- return 'generic';
+ return 'CreditCard';
}
- // Remove spaces and dashes
const cleaned = cardNumber.replace(/[\s-]/g, '');
-
- // Must be mostly numeric
if (!/^\d{4,}/.test(cleaned)) {
- return 'generic';
+ return 'CreditCard';
}
- // Visa: starts with 4
if (/^4/.test(cleaned)) {
- return 'visa';
+ return 'Visa';
}
-
- // Mastercard: starts with 51-55 or 2221-2720
if (/^5[1-5]/.test(cleaned) || /^2[2-7]/.test(cleaned)) {
- return 'mastercard';
+ return 'Mastercard';
}
-
- // Amex: starts with 34 or 37
if (/^3[47]/.test(cleaned)) {
- return 'amex';
+ return 'Amex';
}
-
- // Discover: starts with 6011, 622, 644-649, 65
if (/^6(?:011|22|4[4-9]|5)/.test(cleaned)) {
- return 'discover';
+ return 'Discover';
}
- return 'generic';
+ return 'CreditCard';
};
/**
- * Generic credit card icon in AliasVault style
+ * Get the appropriate SVG icon for a credit card brand.
*/
-const CreditCardIcon: React.FC<{ className?: string }> = ({ className = 'w-8 h-8' }) => (
-
-);
-
-/**
- * Visa card icon in AliasVault style
- */
-const VisaIcon: React.FC<{ className?: string }> = ({ className = 'w-8 h-8' }) => (
-
-);
-
-/**
- * Mastercard icon in AliasVault style
- */
-const MastercardIcon: React.FC<{ className?: string }> = ({ className = 'w-8 h-8' }) => (
-
-);
-
-/**
- * Amex card icon in AliasVault style
- */
-const AmexIcon: React.FC<{ className?: string }> = ({ className = 'w-8 h-8' }) => (
-
-);
-
-/**
- * Discover card icon in AliasVault style
- */
-const DiscoverIcon: React.FC<{ className?: string }> = ({ className = 'w-8 h-8' }) => (
-
-);
-
-/**
- * Note/document icon in AliasVault style
- */
-const NoteIcon: React.FC<{ className?: string }> = ({ className = 'w-8 h-8' }) => (
-
-);
-
-/**
- * Placeholder icon for Login/Alias items - traditional key design with outline style
- */
-const PlaceholderIcon: React.FC<{ className?: string }> = ({ className = 'w-8 h-8' }) => (
-
-);
-
-/**
- * Get the appropriate icon component based on card brand
- */
-const getCardIcon = (brand: CardBrand): React.FC<{ className?: string }> => {
- switch (brand) {
- case 'visa':
- return VisaIcon;
- case 'mastercard':
- return MastercardIcon;
- case 'amex':
- return AmexIcon;
- case 'discover':
- return DiscoverIcon;
- default:
- return CreditCardIcon;
- }
+const getCardIconSvg = (cardNumber: string | undefined): string => {
+ return ItemTypeIconSvgs[detectCardBrand(cardNumber)];
};
/**
@@ -234,7 +71,7 @@ const getCardIcon = (brand: CardBrand): React.FC<{ className?: string }> => {
const ItemIcon: React.FC = ({ item, className = 'w-8 h-8' }) => {
// For Note type, always show note icon
if (item.ItemType === ItemTypes.Note) {
- return ;
+ return ;
}
// For CreditCard type, detect card brand and show appropriate icon
@@ -244,10 +81,7 @@ const ItemIcon: React.FC = ({ item, className = 'w-8 h-8' }) => {
? (Array.isArray(cardNumberField.Value) ? cardNumberField.Value[0] : cardNumberField.Value)
: undefined;
- const brand = detectCardBrand(cardNumber);
- const CardIcon = getCardIcon(brand);
-
- return ;
+ return ;
}
// For Login/Alias types, use Logo if available, otherwise placeholder
@@ -267,7 +101,7 @@ const ItemIcon: React.FC = ({ item, className = 'w-8 h-8' }) => {
if (parent) {
const placeholder = document.createElement('div');
placeholder.className = className;
- placeholder.innerHTML = PLACEHOLDER_ICON_SVG;
+ placeholder.innerHTML = ItemTypeIconSvgs.Placeholder;
parent.insertBefore(placeholder, target);
}
}}
@@ -276,20 +110,10 @@ const ItemIcon: React.FC = ({ item, className = 'w-8 h-8' }) => {
}
// Default placeholder for Login/Alias without logo
- return ;
+ return ;
};
export default ItemIcon;
-// Export individual icons for direct use if needed
-export {
- CreditCardIcon,
- VisaIcon,
- MastercardIcon,
- AmexIcon,
- DiscoverIcon,
- NoteIcon,
- PlaceholderIcon,
- detectCardBrand
-};
-export type { CardBrand };
+// Export the SvgIcon component and icon utilities for direct use if needed
+export { SvgIcon, getCardIconSvg };
diff --git a/apps/browser-extension/src/utils/Constants.ts b/apps/browser-extension/src/utils/Constants.ts
index 3ccd3bb91..61f51a305 100644
--- a/apps/browser-extension/src/utils/Constants.ts
+++ b/apps/browser-extension/src/utils/Constants.ts
@@ -14,9 +14,3 @@ export const PENDING_REDIRECT_URL_KEY = 'session:pendingRedirectUrl';
export const CUSTOM_EMAIL_HISTORY_KEY = 'local:aliasvault_custom_email_history';
export const CUSTOM_USERNAME_HISTORY_KEY = 'local:aliasvault_custom_username_history';
export const SKIP_FORM_RESTORE_KEY = 'local:aliasvault_skip_form_restore';
-
-/**
- * Placeholder SVG for items without a logo (key icon).
- * Used by both ItemIcon.tsx (React) and Popup.ts (content script).
- */
-export const PLACEHOLDER_ICON_SVG = ``;
diff --git a/apps/browser-extension/src/utils/dist/core/models/icons/index.d.ts b/apps/browser-extension/src/utils/dist/core/models/icons/index.d.ts
new file mode 100644
index 000000000..ce141ca8a
--- /dev/null
+++ b/apps/browser-extension/src/utils/dist/core/models/icons/index.d.ts
@@ -0,0 +1,64 @@
+/**
+ * Centralized icon definitions for item types.
+ * This is the single source of truth for all item type icons across platforms.
+ *
+ * Generated platform-specific files:
+ * - C# (Blazor): apps/server/Databases/AliasClientDb/Models/ItemTypeIcons.cs
+ * - Swift (iOS): apps/mobile-app/ios/VaultModels/ItemTypeIcons.swift
+ * - Kotlin (Android): apps/mobile-app/android/.../vaultstore/models/ItemTypeIcons.kt
+ * - TypeScript: distributed via build.sh to browser-extension and mobile-app
+ *
+ * Color scheme used in icons:
+ * - Primary orange: #f49541
+ * - Dark orange: #d68338
+ * - Light yellow: #ffe096
+ * - Lighter yellow: #fbcb74
+ */
+/**
+ * SVG icon definitions for each item type and card brand.
+ * All icons use a 32x32 viewBox for consistency.
+ */
+declare const ItemTypeIconSvgs: {
+ /**
+ * Placeholder key icon for Login/Alias items without a logo.
+ * Traditional key design with outline style.
+ */
+ readonly Placeholder: "";
+ /**
+ * Note/document icon with folded corner.
+ * Used for Note item type.
+ */
+ readonly Note: "";
+ /**
+ * Generic credit card icon.
+ * Used when card brand cannot be detected.
+ */
+ readonly CreditCard: "";
+ /**
+ * Visa card icon with brand styling.
+ */
+ readonly Visa: "";
+ /**
+ * Mastercard icon with overlapping circles.
+ */
+ readonly Mastercard: "";
+ /**
+ * American Express card icon.
+ */
+ readonly Amex: "";
+ /**
+ * Discover card icon with orange circle logo.
+ */
+ readonly Discover: "";
+};
+type ItemTypeIconKey = keyof typeof ItemTypeIconSvgs;
+/**
+ * Get SVG string for an item type icon.
+ */
+declare function getItemTypeIconSvg(key: ItemTypeIconKey): string;
+/**
+ * Get all available icon keys.
+ */
+declare function getAllIconKeys(): ItemTypeIconKey[];
+
+export { type ItemTypeIconKey, ItemTypeIconSvgs, getAllIconKeys, getItemTypeIconSvg };
diff --git a/apps/browser-extension/src/utils/dist/core/models/icons/index.js b/apps/browser-extension/src/utils/dist/core/models/icons/index.js
new file mode 100644
index 000000000..5d1390408
--- /dev/null
+++ b/apps/browser-extension/src/utils/dist/core/models/icons/index.js
@@ -0,0 +1,82 @@
+//
+// This file was automatically generated. Do not edit manually.
+
+
+// src/icons/ItemTypeIcons.ts
+var ItemTypeIconSvgs = {
+ /**
+ * Placeholder key icon for Login/Alias items without a logo.
+ * Traditional key design with outline style.
+ */
+ Placeholder: ``,
+ /**
+ * Note/document icon with folded corner.
+ * Used for Note item type.
+ */
+ Note: ``,
+ /**
+ * Generic credit card icon.
+ * Used when card brand cannot be detected.
+ */
+ CreditCard: ``,
+ /**
+ * Visa card icon with brand styling.
+ */
+ Visa: ``,
+ /**
+ * Mastercard icon with overlapping circles.
+ */
+ Mastercard: ``,
+ /**
+ * American Express card icon.
+ */
+ Amex: ``,
+ /**
+ * Discover card icon with orange circle logo.
+ */
+ Discover: ``
+};
+function getItemTypeIconSvg(key) {
+ return ItemTypeIconSvgs[key];
+}
+function getAllIconKeys() {
+ return Object.keys(ItemTypeIconSvgs);
+}
+
+export { ItemTypeIconSvgs, getAllIconKeys, getItemTypeIconSvg };
+//# sourceMappingURL=index.js.map
+//# sourceMappingURL=index.js.map
\ No newline at end of file