Update mobile app to use generic item type icons (#1465)

This commit is contained in:
Leendert de Borst
2026-01-20 21:25:13 +01:00
committed by Leendert de Borst
parent b818876971
commit 2dab52c1b4
9 changed files with 479 additions and 379 deletions

View File

@@ -0,0 +1,95 @@
// <auto-generated />
// This file is auto-generated from core/models/src/icons/ItemTypeIcons.ts
// Do not edit this file directly. Run 'npm run generate:models' to regenerate.
@file:Suppress("MaxLineLength")
package net.aliasvault.app.vaultstore.models
/**
* Centralized SVG icon definitions for item types.
* Single source of truth for all item type icons across platforms.
*/
object ItemTypeIcons {
/**
* Placeholder icon SVG.
*/
val PLACEHOLDER = """
<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="10" cy="10" r="6.5" stroke="#f49541" stroke-width="2.5"/>
<circle cx="10" cy="10" r="2.5" stroke="#ff0000" stroke-width="2"/>
<path d="M15 15L27 27" stroke="#f49541" stroke-width="2.5" stroke-linecap="round"/>
<path d="M19 19L23 15" stroke="#f49541" stroke-width="2.5" stroke-linecap="round"/>
<path d="M24 24L28 20" stroke="#f49541" stroke-width="2.5" stroke-linecap="round"/>
</svg>
""".trimIndent()
/**
* Note icon SVG.
*/
val NOTE = """
<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 4C6.9 4 6 4.9 6 6V26C6 27.1 6.9 28 8 28H24C25.1 28 26 27.1 26 26V11L19 4H8Z" fill="#f49541"/>
<path d="M19 4V11H26L19 4Z" fill="#d68338"/>
<rect x="10" y="14" width="12" height="1.5" rx="0.75" fill="#ffe096"/>
<rect x="10" y="18" width="10" height="1.5" rx="0.75" fill="#ffe096"/>
<rect x="10" y="22" width="8" height="1.5" rx="0.75" fill="#ffe096"/>
</svg>
""".trimIndent()
/**
* CreditCard icon SVG.
*/
val CREDIT_CARD = """
<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="2" y="6" width="28" height="20" rx="3" fill="#f49541"/>
<rect x="2" y="11" width="28" height="4" fill="#d68338"/>
<rect x="5" y="18" width="8" height="2" rx="1" fill="#ffe096"/>
<rect x="5" y="22" width="5" height="1.5" rx="0.75" fill="#fbcb74"/>
</svg>
""".trimIndent()
/**
* Visa icon SVG.
*/
val VISA = """
<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="2" y="6" width="28" height="20" rx="3" fill="#f49541"/>
<path d="M13.5 13L11.5 19H10L8.5 14.5C8.5 14.5 8.35 14 8 14C7.65 14 7 13.8 7 13.8L7.05 13.5H9.5C9.85 13.5 10.15 13.75 10.2 14.1L10.8 17L12.5 13.5H13.5V13ZM15 19H14L15 13H16L15 19ZM20 13.5C20 13.5 19.4 13.3 18.7 13.3C17.35 13.3 16.4 14 16.4 15C16.4 15.8 17.1 16.2 17.65 16.5C18.2 16.8 18.4 17 18.4 17.2C18.4 17.5 18.05 17.7 17.6 17.7C17 17.7 16.5 17.5 16.5 17.5L16.3 18.7C16.3 18.7 16.9 19 17.7 19C19.2 19 20.1 18.2 20.1 17.1C20.1 15.7 18.4 15.6 18.4 15C18.4 14.7 18.7 14.5 19.15 14.5C19.6 14.5 20.1 14.7 20.1 14.7L20.3 13.5H20V13.5ZM24 19L23.1 13.5H22C21.7 13.5 21.45 13.7 21.35 13.95L19 19H20.5L20.8 18H22.7L22.9 19H24ZM21.2 17L22 14.5L22.45 17H21.2Z" fill="#ffe096"/>
</svg>
""".trimIndent()
/**
* Mastercard icon SVG.
*/
val MASTERCARD = """
<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="2" y="6" width="28" height="20" rx="3" fill="#f49541"/>
<circle cx="13" cy="16" r="5" fill="#d68338"/>
<circle cx="19" cy="16" r="5" fill="#ffe096"/>
<path d="M16 12.5C17.1 13.4 17.8 14.6 17.8 16C17.8 17.4 17.1 18.6 16 19.5C14.9 18.6 14.2 17.4 14.2 16C14.2 14.6 14.9 13.4 16 12.5Z" fill="#fbcb74"/>
</svg>
""".trimIndent()
/**
* Amex icon SVG.
*/
val AMEX = """
<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="2" y="6" width="28" height="20" rx="3" fill="#f49541"/>
<text x="16" y="18" text-anchor="middle" fill="#ffe096" font-size="8" font-weight="bold" font-family="Arial, sans-serif">AMEX</text>
</svg>
""".trimIndent()
/**
* Discover icon SVG.
*/
val DISCOVER = """
<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="2" y="6" width="28" height="20" rx="3" fill="#f49541"/>
<circle cx="20" cy="16" r="4" fill="#ffe096"/>
<path d="M7 14H8.5C9.3 14 10 14.7 10 15.5C10 16.3 9.3 17 8.5 17H7V14Z" fill="#ffe096"/>
<rect x="11" y="14" width="1.5" height="3" fill="#ffe096"/>
<path d="M14 15C14 14.4 14.4 14 15 14C15.3 14 15.5 14.1 15.7 14.3L16.5 13.5C16.1 13.2 15.6 13 15 13C13.9 13 13 13.9 13 15C13 16.1 13.9 17 15 17C15.6 17 16.1 16.8 16.5 16.5L15.7 15.7C15.5 15.9 15.3 16 15 16C14.4 16 14 15.6 14 15Z" fill="#ffe096"/>
</svg>
""".trimIndent()
}

View File

@@ -1,14 +1,24 @@
import { Buffer } from 'buffer';
import { Image, ImageStyle, StyleSheet, View } from 'react-native';
import Svg, { Circle, Path, Rect, Text as SvgText } from 'react-native-svg';
import { SvgUri } from 'react-native-svg';
import type { Item } from '@/utils/dist/core/models/vault';
import { ItemTypes, FieldKey } from '@/utils/dist/core/models/vault';
import {
ItemTypes,
FieldKey,
} from '@/utils/dist/core/models/vault';
import servicePlaceholder from '@/assets/images/service-placeholder.webp';
// Import centralized icon components (auto-generated from core/models/src/icons/ItemTypeIcons.ts)
import {
iconComponents,
PlaceholderIcon,
NoteIcon,
type IconKey,
} from './ItemTypeIconComponents';
/**
* Item icon props - supports both legacy logo-only mode and new item-based mode.
*/
@@ -21,179 +31,27 @@ type ItemIconProps = {
};
/**
* Credit card brand type
* Detect credit card brand from card number using BIN prefixes.
*/
type CardBrand = 'visa' | 'mastercard' | 'amex' | 'discover' | 'generic';
const detectCardBrand = (cardNumber: string | undefined): IconKey => {
if (!cardNumber) return 'CreditCard';
/**
* 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
*/
const detectCardBrand = (cardNumber: string | undefined): CardBrand => {
if (!cardNumber) {
return 'generic';
}
// Remove spaces and dashes
const cleaned = cardNumber.replace(/[\s-]/g, '');
if (!/^\d{4,}/.test(cleaned)) return 'CreditCard';
// Must be mostly numeric
if (!/^\d{4,}/.test(cleaned)) {
return 'generic';
}
if (/^4/.test(cleaned)) return 'Visa';
if (/^5[1-5]/.test(cleaned) || /^2[2-7]/.test(cleaned)) return 'Mastercard';
if (/^3[47]/.test(cleaned)) return 'Amex';
if (/^6(?:011|22|4[4-9]|5)/.test(cleaned)) return 'Discover';
// Visa: starts with 4
if (/^4/.test(cleaned)) {
return 'visa';
}
// Mastercard: starts with 51-55 or 2221-2720
if (/^5[1-5]/.test(cleaned) || /^2[2-7]/.test(cleaned)) {
return 'mastercard';
}
// Amex: starts with 34 or 37
if (/^3[47]/.test(cleaned)) {
return 'amex';
}
// Discover: starts with 6011, 622, 644-649, 65
if (/^6(?:011|22|4[4-9]|5)/.test(cleaned)) {
return 'discover';
}
return 'generic';
return 'CreditCard';
};
/**
* Generic credit card icon in AliasVault style
* Get the appropriate icon component for a card number.
*/
const CreditCardIcon = ({ width = 32, height = 32 }: { width?: number; height?: number }) => (
<Svg width={width} height={height} viewBox="0 0 32 32" fill="none">
<Rect x="2" y="6" width="28" height="20" rx="3" fill="#f49541" />
<Rect x="2" y="11" width="28" height="4" fill="#d68338" />
<Rect x="5" y="18" width="8" height="2" rx="1" fill="#ffe096" />
<Rect x="5" y="22" width="5" height="1.5" rx="0.75" fill="#fbcb74" />
</Svg>
);
/**
* Visa card icon in AliasVault style
*/
const VisaIcon = ({ width = 32, height = 32 }: { width?: number; height?: number }) => (
<Svg width={width} height={height} viewBox="0 0 32 32" fill="none">
<Rect x="2" y="6" width="28" height="20" rx="3" fill="#f49541" />
<Path
d="M13.5 13L11.5 19H10L8.5 14.5C8.5 14.5 8.35 14 8 14C7.65 14 7 13.8 7 13.8L7.05 13.5H9.5C9.85 13.5 10.15 13.75 10.2 14.1L10.8 17L12.5 13.5H13.5V13ZM15 19H14L15 13H16L15 19ZM20 13.5C20 13.5 19.4 13.3 18.7 13.3C17.35 13.3 16.4 14 16.4 15C16.4 15.8 17.1 16.2 17.65 16.5C18.2 16.8 18.4 17 18.4 17.2C18.4 17.5 18.05 17.7 17.6 17.7C17 17.7 16.5 17.5 16.5 17.5L16.3 18.7C16.3 18.7 16.9 19 17.7 19C19.2 19 20.1 18.2 20.1 17.1C20.1 15.7 18.4 15.6 18.4 15C18.4 14.7 18.7 14.5 19.15 14.5C19.6 14.5 20.1 14.7 20.1 14.7L20.3 13.5H20V13.5ZM24 19L23.1 13.5H22C21.7 13.5 21.45 13.7 21.35 13.95L19 19H20.5L20.8 18H22.7L22.9 19H24ZM21.2 17L22 14.5L22.45 17H21.2Z"
fill="#ffe096"
/>
</Svg>
);
/**
* Mastercard icon in AliasVault style
*/
const MastercardIcon = ({ width = 32, height = 32 }: { width?: number; height?: number }) => (
<Svg width={width} height={height} viewBox="0 0 32 32" fill="none">
<Rect x="2" y="6" width="28" height="20" rx="3" fill="#f49541" />
<Circle cx="13" cy="16" r="5" fill="#d68338" />
<Circle cx="19" cy="16" r="5" fill="#ffe096" />
<Path
d="M16 12.5C17.1 13.4 17.8 14.6 17.8 16C17.8 17.4 17.1 18.6 16 19.5C14.9 18.6 14.2 17.4 14.2 16C14.2 14.6 14.9 13.4 16 12.5Z"
fill="#fbcb74"
/>
</Svg>
);
/**
* Amex card icon in AliasVault style
*/
const AmexIcon = ({ width = 32, height = 32 }: { width?: number; height?: number }) => (
<Svg width={width} height={height} viewBox="0 0 32 32" fill="none">
<Rect x="2" y="6" width="28" height="20" rx="3" fill="#f49541" />
<SvgText
x="16"
y="18"
textAnchor="middle"
fill="#ffe096"
fontSize="8"
fontWeight="bold"
fontFamily="Arial, sans-serif"
>
AMEX
</SvgText>
</Svg>
);
/**
* Discover card icon in AliasVault style
*/
const DiscoverIcon = ({ width = 32, height = 32 }: { width?: number; height?: number }) => (
<Svg width={width} height={height} viewBox="0 0 32 32" fill="none">
<Rect x="2" y="6" width="28" height="20" rx="3" fill="#f49541" />
<Circle cx="20" cy="16" r="4" fill="#ffe096" />
<Path
d="M7 14H8.5C9.3 14 10 14.7 10 15.5C10 16.3 9.3 17 8.5 17H7V14Z"
fill="#ffe096"
/>
<Rect x="11" y="14" width="1.5" height="3" fill="#ffe096" />
<Path
d="M14 15C14 14.4 14.4 14 15 14C15.3 14 15.5 14.1 15.7 14.3L16.5 13.5C16.1 13.2 15.6 13 15 13C13.9 13 13 13.9 13 15C13 16.1 13.9 17 15 17C15.6 17 16.1 16.8 16.5 16.5L15.7 15.7C15.5 15.9 15.3 16 15 16C14.4 16 14 15.6 14 15Z"
fill="#ffe096"
/>
</Svg>
);
/**
* Note/document icon in AliasVault style
*/
const NoteIcon = ({ width = 32, height = 32 }: { width?: number; height?: number }) => (
<Svg width={width} height={height} viewBox="0 0 32 32" fill="none">
<Path
d="M8 4C6.9 4 6 4.9 6 6V26C6 27.1 6.9 28 8 28H24C25.1 28 26 27.1 26 26V11L19 4H8Z"
fill="#f49541"
/>
<Path d="M19 4V11H26L19 4Z" fill="#d68338" />
<Rect x="10" y="14" width="12" height="1.5" rx="0.75" fill="#ffe096" />
<Rect x="10" y="18" width="10" height="1.5" rx="0.75" fill="#ffe096" />
<Rect x="10" y="22" width="8" height="1.5" rx="0.75" fill="#ffe096" />
</Svg>
);
/**
* Placeholder icon for Login/Alias items - traditional key design with outline style
*/
const PlaceholderIcon = ({ width = 32, height = 32 }: { width?: number; height?: number }) => (
<Svg width={width} height={height} viewBox="0 0 32 32" fill="none">
{/* Key bow (circular head) - positioned top-left */}
<Circle cx="10" cy="10" r="6.5" stroke="#f49541" strokeWidth="2.5" />
{/* Key hole in bow */}
<Circle cx="10" cy="10" r="2.5" stroke="#f49541" strokeWidth="2" />
{/* Key shaft - diagonal */}
<Path d="M15 15L27 27" stroke="#f49541" strokeWidth="2.5" strokeLinecap="round" />
{/* Key teeth - perpendicular to shaft */}
<Path d="M19 19L23 15" stroke="#f49541" strokeWidth="2.5" strokeLinecap="round" />
<Path d="M24 24L28 20" stroke="#f49541" strokeWidth="2.5" strokeLinecap="round" />
</Svg>
);
/**
* Get the appropriate icon component based on card brand
*/
const getCardIcon = (brand: CardBrand) => {
switch (brand) {
case 'visa':
return VisaIcon;
case 'mastercard':
return MastercardIcon;
case 'amex':
return AmexIcon;
case 'discover':
return DiscoverIcon;
default:
return CreditCardIcon;
}
const getCardIconComponent = (cardNumber: string | undefined) => {
return iconComponents[detectCardBrand(cardNumber)];
};
/**
@@ -221,8 +79,7 @@ export function ItemIcon({ logo, item, style }: ItemIconProps) : React.ReactNode
? (Array.isArray(cardNumberField.Value) ? cardNumberField.Value[0] : cardNumberField.Value)
: undefined;
const brand = detectCardBrand(cardNumber);
const CardIcon = getCardIcon(brand);
const CardIcon = getCardIconComponent(cardNumber);
return (
<View style={[styles.iconContainer, style]}>
@@ -418,4 +275,4 @@ const styles = StyleSheet.create({
borderRadius: 4,
overflow: 'hidden',
},
});
});

View File

@@ -0,0 +1,82 @@
// <auto-generated />
// This file is auto-generated from core/models/src/icons/ItemTypeIcons.ts
// Do not edit this file directly. Run 'npm run generate:models' to regenerate.
import React from 'react';
import Svg, { Circle, Path, Rect, Text as SvgText } from 'react-native-svg';
export const PlaceholderIcon = ({ width = 32, height = 32 }: { width?: number; height?: number }): React.ReactElement => (
<Svg width={width} height={height} viewBox="0 0 32 32" fill="none">
<Circle cx="10" cy="10" r="6.5" stroke="#f49541" strokeWidth="2.5" />
<Circle cx="10" cy="10" r="2.5" stroke="#ff0000" strokeWidth="2" />
<Path d="M15 15L27 27" stroke="#f49541" strokeWidth="2.5" strokeLinecap="round" />
<Path d="M19 19L23 15" stroke="#f49541" strokeWidth="2.5" strokeLinecap="round" />
<Path d="M24 24L28 20" stroke="#f49541" strokeWidth="2.5" strokeLinecap="round" />
</Svg>
);
export const NoteIcon = ({ width = 32, height = 32 }: { width?: number; height?: number }): React.ReactElement => (
<Svg width={width} height={height} viewBox="0 0 32 32" fill="none">
<Path d="M8 4C6.9 4 6 4.9 6 6V26C6 27.1 6.9 28 8 28H24C25.1 28 26 27.1 26 26V11L19 4H8Z" fill="#f49541" />
<Path d="M19 4V11H26L19 4Z" fill="#d68338" />
<Rect x="10" y="14" width="12" height="1.5" rx="0.75" fill="#ffe096" />
<Rect x="10" y="18" width="10" height="1.5" rx="0.75" fill="#ffe096" />
<Rect x="10" y="22" width="8" height="1.5" rx="0.75" fill="#ffe096" />
</Svg>
);
export const CreditCardIcon = ({ width = 32, height = 32 }: { width?: number; height?: number }): React.ReactElement => (
<Svg width={width} height={height} viewBox="0 0 32 32" fill="none">
<Rect x="2" y="6" width="28" height="20" rx="3" fill="#f49541" />
<Rect x="2" y="11" width="28" height="4" fill="#d68338" />
<Rect x="5" y="18" width="8" height="2" rx="1" fill="#ffe096" />
<Rect x="5" y="22" width="5" height="1.5" rx="0.75" fill="#fbcb74" />
</Svg>
);
export const VisaIcon = ({ width = 32, height = 32 }: { width?: number; height?: number }): React.ReactElement => (
<Svg width={width} height={height} viewBox="0 0 32 32" fill="none">
<Rect x="2" y="6" width="28" height="20" rx="3" fill="#f49541" />
<Path d="M13.5 13L11.5 19H10L8.5 14.5C8.5 14.5 8.35 14 8 14C7.65 14 7 13.8 7 13.8L7.05 13.5H9.5C9.85 13.5 10.15 13.75 10.2 14.1L10.8 17L12.5 13.5H13.5V13ZM15 19H14L15 13H16L15 19ZM20 13.5C20 13.5 19.4 13.3 18.7 13.3C17.35 13.3 16.4 14 16.4 15C16.4 15.8 17.1 16.2 17.65 16.5C18.2 16.8 18.4 17 18.4 17.2C18.4 17.5 18.05 17.7 17.6 17.7C17 17.7 16.5 17.5 16.5 17.5L16.3 18.7C16.3 18.7 16.9 19 17.7 19C19.2 19 20.1 18.2 20.1 17.1C20.1 15.7 18.4 15.6 18.4 15C18.4 14.7 18.7 14.5 19.15 14.5C19.6 14.5 20.1 14.7 20.1 14.7L20.3 13.5H20V13.5ZM24 19L23.1 13.5H22C21.7 13.5 21.45 13.7 21.35 13.95L19 19H20.5L20.8 18H22.7L22.9 19H24ZM21.2 17L22 14.5L22.45 17H21.2Z" fill="#ffe096" />
</Svg>
);
export const MastercardIcon = ({ width = 32, height = 32 }: { width?: number; height?: number }): React.ReactElement => (
<Svg width={width} height={height} viewBox="0 0 32 32" fill="none">
<Rect x="2" y="6" width="28" height="20" rx="3" fill="#f49541" />
<Circle cx="13" cy="16" r="5" fill="#d68338" />
<Circle cx="19" cy="16" r="5" fill="#ffe096" />
<Path d="M16 12.5C17.1 13.4 17.8 14.6 17.8 16C17.8 17.4 17.1 18.6 16 19.5C14.9 18.6 14.2 17.4 14.2 16C14.2 14.6 14.9 13.4 16 12.5Z" fill="#fbcb74" />
</Svg>
);
export const AmexIcon = ({ width = 32, height = 32 }: { width?: number; height?: number }): React.ReactElement => (
<Svg width={width} height={height} viewBox="0 0 32 32" fill="none">
<Rect x="2" y="6" width="28" height="20" rx="3" fill="#f49541" />
<SvgText x="16" y="18" textAnchor="middle" fill="#ffe096" fontSize="8" fontWeight="bold" fontFamily="Arial, sans-serif">AMEX</SvgText>
</Svg>
);
export const DiscoverIcon = ({ width = 32, height = 32 }: { width?: number; height?: number }): React.ReactElement => (
<Svg width={width} height={height} viewBox="0 0 32 32" fill="none">
<Rect x="2" y="6" width="28" height="20" rx="3" fill="#f49541" />
<Circle cx="20" cy="16" r="4" fill="#ffe096" />
<Path d="M7 14H8.5C9.3 14 10 14.7 10 15.5C10 16.3 9.3 17 8.5 17H7V14Z" fill="#ffe096" />
<Rect x="11" y="14" width="1.5" height="3" fill="#ffe096" />
<Path d="M14 15C14 14.4 14.4 14 15 14C15.3 14 15.5 14.1 15.7 14.3L16.5 13.5C16.1 13.2 15.6 13 15 13C13.9 13 13 13.9 13 15C13 16.1 13.9 17 15 17C15.6 17 16.1 16.8 16.5 16.5L15.7 15.7C15.5 15.9 15.3 16 15 16C14.4 16 14 15.6 14 15Z" fill="#ffe096" />
</Svg>
);
/**
* Map of icon key to React Native SVG component.
*/
export const iconComponents = {
Placeholder: PlaceholderIcon,
Note: NoteIcon,
CreditCard: CreditCardIcon,
Visa: VisaIcon,
Mastercard: MastercardIcon,
Amex: AmexIcon,
Discover: DiscoverIcon,
};
export type IconKey = keyof typeof iconComponents;

View File

@@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 60;
objectVersion = 70;
objects = {
/* Begin PBXBuildFile section */

View File

@@ -0,0 +1,79 @@
// <auto-generated />
// This file is auto-generated from core/models/src/icons/ItemTypeIcons.ts
// Do not edit this file directly. Run 'npm run generate:models' to regenerate.
// swiftlint:disable line_length
import Foundation
/// Centralized SVG icon definitions for item types.
/// Single source of truth for all item type icons across platforms.
public struct ItemTypeIcons {
/// Placeholder icon SVG.
public static let placeholder = """
<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="10" cy="10" r="6.5" stroke="#f49541" stroke-width="2.5"/>
<circle cx="10" cy="10" r="2.5" stroke="#ff0000" stroke-width="2"/>
<path d="M15 15L27 27" stroke="#f49541" stroke-width="2.5" stroke-linecap="round"/>
<path d="M19 19L23 15" stroke="#f49541" stroke-width="2.5" stroke-linecap="round"/>
<path d="M24 24L28 20" stroke="#f49541" stroke-width="2.5" stroke-linecap="round"/>
</svg>
"""
/// Note icon SVG.
public static let note = """
<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 4C6.9 4 6 4.9 6 6V26C6 27.1 6.9 28 8 28H24C25.1 28 26 27.1 26 26V11L19 4H8Z" fill="#f49541"/>
<path d="M19 4V11H26L19 4Z" fill="#d68338"/>
<rect x="10" y="14" width="12" height="1.5" rx="0.75" fill="#ffe096"/>
<rect x="10" y="18" width="10" height="1.5" rx="0.75" fill="#ffe096"/>
<rect x="10" y="22" width="8" height="1.5" rx="0.75" fill="#ffe096"/>
</svg>
"""
/// CreditCard icon SVG.
public static let creditCard = """
<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="2" y="6" width="28" height="20" rx="3" fill="#f49541"/>
<rect x="2" y="11" width="28" height="4" fill="#d68338"/>
<rect x="5" y="18" width="8" height="2" rx="1" fill="#ffe096"/>
<rect x="5" y="22" width="5" height="1.5" rx="0.75" fill="#fbcb74"/>
</svg>
"""
/// Visa icon SVG.
public static let visa = """
<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="2" y="6" width="28" height="20" rx="3" fill="#f49541"/>
<path d="M13.5 13L11.5 19H10L8.5 14.5C8.5 14.5 8.35 14 8 14C7.65 14 7 13.8 7 13.8L7.05 13.5H9.5C9.85 13.5 10.15 13.75 10.2 14.1L10.8 17L12.5 13.5H13.5V13ZM15 19H14L15 13H16L15 19ZM20 13.5C20 13.5 19.4 13.3 18.7 13.3C17.35 13.3 16.4 14 16.4 15C16.4 15.8 17.1 16.2 17.65 16.5C18.2 16.8 18.4 17 18.4 17.2C18.4 17.5 18.05 17.7 17.6 17.7C17 17.7 16.5 17.5 16.5 17.5L16.3 18.7C16.3 18.7 16.9 19 17.7 19C19.2 19 20.1 18.2 20.1 17.1C20.1 15.7 18.4 15.6 18.4 15C18.4 14.7 18.7 14.5 19.15 14.5C19.6 14.5 20.1 14.7 20.1 14.7L20.3 13.5H20V13.5ZM24 19L23.1 13.5H22C21.7 13.5 21.45 13.7 21.35 13.95L19 19H20.5L20.8 18H22.7L22.9 19H24ZM21.2 17L22 14.5L22.45 17H21.2Z" fill="#ffe096"/>
</svg>
"""
/// Mastercard icon SVG.
public static let mastercard = """
<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="2" y="6" width="28" height="20" rx="3" fill="#f49541"/>
<circle cx="13" cy="16" r="5" fill="#d68338"/>
<circle cx="19" cy="16" r="5" fill="#ffe096"/>
<path d="M16 12.5C17.1 13.4 17.8 14.6 17.8 16C17.8 17.4 17.1 18.6 16 19.5C14.9 18.6 14.2 17.4 14.2 16C14.2 14.6 14.9 13.4 16 12.5Z" fill="#fbcb74"/>
</svg>
"""
/// Amex icon SVG.
public static let amex = """
<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="2" y="6" width="28" height="20" rx="3" fill="#f49541"/>
<text x="16" y="18" text-anchor="middle" fill="#ffe096" font-size="8" font-weight="bold" font-family="Arial, sans-serif">AMEX</text>
</svg>
"""
/// Discover icon SVG.
public static let discover = """
<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="2" y="6" width="28" height="20" rx="3" fill="#f49541"/>
<circle cx="20" cy="16" r="4" fill="#ffe096"/>
<path d="M7 14H8.5C9.3 14 10 14.7 10 15.5C10 16.3 9.3 17 8.5 17H7V14Z" fill="#ffe096"/>
<rect x="11" y="14" width="1.5" height="3" fill="#ffe096"/>
<path d="M14 15C14 14.4 14.4 14 15 14C15.3 14 15.5 14.1 15.7 14.3L16.5 13.5C16.1 13.2 15.6 13 15 13C13.9 13 13 13.9 13 15C13 16.1 13.9 17 15 17C15.6 17 16.1 16.8 16.5 16.5L15.7 15.7C15.5 15.9 15.3 16 15 16C14.4 16 14 15.6 14 15Z" fill="#ffe096"/>
</svg>
"""
}

View File

@@ -1,34 +1,56 @@
import SwiftUI
import Macaw
import VaultModels
/// Item logo view - displays logos or type-based icons for items
public struct ItemLogoView: View {
private let placeholderImageBase64 = "UklGRjoEAABXRUJQVlA4IC4EAAAwFwCdASqAAIAAPpFCm0olo6Ihp5IraLASCWUA0eb/0s56RrLtCnYfLPiBshdXWMx8j1Ez65f169iA4xUDBTEV6ylMQeCIj2b7RngGi7gKZ9WjKdSoy9R8JcgOmjCMlDmLG20KhNo/i/Dc/Ah5GAvGfm8kfniV3AkR6fxN6eKwjDc6xrDgSfS48G5uGV6WzQt24YAVlLSK9BMwndzfHnePK1KFchFrL7O3ulB8cGNCeomu4o+l0SrS/JKblJ4WTzj0DAD++lCUEouSfgRKdiV2TiYCD+H+l3tANKSPQFPQuzi7rbvxqGeRmXB9kDwURaoSTTpYjA9REMUi9uA6aV7PWtBNXgUzMLowYMZeos6Xvyhb34GmufswMHA5ZyYpxzjTphOak4ZjNOiz8aScO5ygiTx99SqwX/uL+HSeVOSraHw8IymrMwm+jLxqN8BS8dGcItLlm/ioulqH2j4V8glDgSut+ExkxiD7m8TGPrrjCQNJbRDzpOFsyCyfBZupvp8QjGKW2KGziSZeIWes4aTB9tRmeEBhnUrmTDZQuXcc67Fg82KHrSfaeeOEq6jjuUjQ8wUnzM4Zz3dhrwSyslVz/WvnKqYkr4V/TTXPFF5EjF4rM1bHZ8bK63EfTnK41+n3n4gEFoYP4mXkNH0hntnYcdTqiE7Gn+q0BpRRxnkpBSZlA6Wa70jpW0FGqkw5e591A5/H+OV+60WAo+4Mi+NlsKrvLZ9EiVaPnoEFZlJQx1fA777AJ2MjXJ4KSsrWDWJi1lE8yPs8V6XvcC0chDTYt8456sKXAagCZyY+fzQriFMaddXyKQdG8qBqcdYjAsiIcjzaRFBBoOK9sU+sFY7N6B6+xtrlu3c37rQKkI3O2EoiJOris54EjJ5OFuumA0M6riNUuBf/MEPFBVx1JRcUEs+upEBsCnwYski7FT3TTqHrx7v5AjgFN97xhPTkmVpu6sxRnWBi1fxIRp8eWZeFM6mUcGgVk1WeVb1yhdV9hoMo2TsNEPE0tHo/wvuSJSzbZo7wibeXM9v/rRfKcx7X93rfiXVnyQ9f/5CaAQ4lxedPp/6uzLtOS4FyL0bCNeZ6L5w+AiuyWCTDFIYaUzhwfG+/YTQpWyeZCdQIKzhV+3GeXI2cxoP0ER/DlOKymf1gm+zRU3sqf1lBVQ0y+mK/Awl9bS3uaaQmI0FUyUwHUKP7PKuXnO+LcwDv4OfPT6hph8smc1EtMe5ib/apar/qZ9dyaEaElALJ1KKxnHziuvVl8atk1fINSQh7OtXDyqbPw9o/nGIpTnv5iFmwmWJLis2oyEgPkJqyx0vYI8rjkVEzKc8eQavAJBYSpjMwM193Swt+yJyjvaGYWPnqExxKiNarpB2WSO7soCAZXhS1uEYHryrK47BH6W1dRiruqT0xpLih3MXiwU3VDwAAAA==" // swiftlint:disable:this line_length
/// Credit card brand type for local detection
private enum CardBrand {
case visa
case mastercard
case amex
case discover
case generic
/// Detect credit card brand from card number using BIN prefixes
static func detect(from cardNumber: String?) -> CardBrand {
guard let cardNumber = cardNumber else { return .generic }
let cleaned = cardNumber.replacingOccurrences(of: "[\\s-]", with: "", options: .regularExpression)
guard cleaned.range(of: "^\\d{4,}", options: .regularExpression) != nil else { return .generic }
if cleaned.hasPrefix("4") { return .visa }
if cleaned.range(of: "^5[1-5]", options: .regularExpression) != nil ||
cleaned.range(of: "^2[2-7]", options: .regularExpression) != nil { return .mastercard }
if cleaned.range(of: "^3[47]", options: .regularExpression) != nil { return .amex }
if cleaned.range(of: "^6(?:011|22|4[4-9]|5)", options: .regularExpression) != nil { return .discover }
return .generic
}
/// Get the SVG icon for this card brand from centralized definitions
var icon: String {
switch self {
case .visa: return ItemTypeIcons.visa
case .mastercard: return ItemTypeIcons.mastercard
case .amex: return ItemTypeIcons.amex
case .discover: return ItemTypeIcons.discover
case .generic: return ItemTypeIcons.creditCard
}
}
}
let logoData: Data?
let itemType: String?
let cardNumber: String?
@Environment(\.colorScheme) private var colorScheme
public init(logoData: Data?, itemType: String? = nil, cardNumber: String? = nil) {
self.logoData = logoData
self.itemType = itemType
self.cardNumber = cardNumber
}
private var colors: ColorConstants.Colors.Type {
ColorConstants.colors(for: colorScheme)
}
private var placeholderImage: UIImage? {
if let data = Data(base64Encoded: placeholderImageBase64) {
return UIImage(data: data)
}
return nil
}
private func detectMimeType(_ data: Data) -> String {
// Check for SVG
if let str = String(data: data.prefix(5), encoding: .utf8)?.lowercased(),
@@ -92,20 +114,19 @@ public struct ItemLogoView: View {
private func renderTypeBasedIcon(itemType: String) -> some View {
Group {
// For Note type, always show note icon
if itemType == ItemTypeIcon.ItemType.note.rawValue {
renderSVGIcon(svg: ItemTypeIcon.noteIcon)
if itemType == ItemType.note {
renderSVGIcon(svg: ItemTypeIcons.note)
}
// For CreditCard type, detect brand and show appropriate icon
else if itemType == ItemTypeIcon.ItemType.creditCard.rawValue {
let brand = ItemTypeIcon.CardBrand.detect(from: cardNumber)
let cardIcon = ItemTypeIcon.getCardIcon(for: brand)
renderSVGIcon(svg: cardIcon)
else if itemType == ItemType.creditCard {
let brand = CardBrand.detect(from: cardNumber)
renderSVGIcon(svg: brand.icon)
}
// For Login/Alias types, use Logo if available, otherwise placeholder
else if let logoData = logoData, !logoData.isEmpty {
renderLogo(logoData: logoData)
} else {
renderSVGIcon(svg: ItemTypeIcon.placeholderIcon)
renderSVGIcon(svg: ItemTypeIcons.placeholder)
}
}
}
@@ -113,13 +134,15 @@ public struct ItemLogoView: View {
/// Render an SVG icon from string
private func renderSVGIcon(svg: String) -> some View {
Group {
if let svgData = svg.data(using: .utf8),
let svgNode = try? SVGParser.parse(text: svg) {
if let svgNode = try? SVGParser.parse(text: svg) {
SVGImageView(node: svgNode)
.frame(width: 32, height: 32)
.clipShape(RoundedRectangle(cornerRadius: 4))
} else {
renderPlaceholder()
// Fallback if SVG can't be parsed - simple colored rectangle
RoundedRectangle(cornerRadius: 4)
.fill(Color.gray.opacity(0.3))
.frame(width: 32, height: 32)
}
}
}
@@ -139,39 +162,16 @@ public struct ItemLogoView: View {
.aspectRatio(contentMode: .fit)
.frame(width: 32, height: 32)
.clipShape(RoundedRectangle(cornerRadius: 4))
} else if let placeholder = placeholderImage {
Image(uiImage: placeholder)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 32, height: 32)
.clipShape(RoundedRectangle(cornerRadius: 4))
} else {
// Logo data couldn't be decoded, use centralized placeholder
renderPlaceholder()
}
}
}
/// Render fallback placeholder
/// Render fallback placeholder using centralized SVG icon
private func renderPlaceholder() -> some View {
Group {
if let placeholder = placeholderImage {
Image(uiImage: placeholder)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 32, height: 32)
.clipShape(RoundedRectangle(cornerRadius: 4))
} else {
// Ultimate fallback if placeholder fails to load
Circle()
.fill(colors.accentBackground)
.frame(width: 32, height: 32)
.overlay(
Circle()
.stroke(colors.accentBorder, lineWidth: 1)
)
.clipShape(RoundedRectangle(cornerRadius: 4))
}
}
renderSVGIcon(svg: ItemTypeIcons.placeholder)
}
}

View File

@@ -1,159 +0,0 @@
// swiftlint:disable line_length
import SwiftUI
/// Item type icon helper - provides SVG-based icons for different item types
public struct ItemTypeIcon {
/// Item type enumeration matching the database model
public enum ItemType: String {
case login = "Login"
case alias = "Alias"
case creditCard = "CreditCard"
case note = "Note"
}
/// Credit card brand type
public enum CardBrand {
case visa
case mastercard
case amex
case discover
case generic
/// Detect credit card brand from card number using industry-standard prefixes
public static func detect(from cardNumber: String?) -> CardBrand {
guard let cardNumber = cardNumber else {
return .generic
}
// Remove spaces and dashes
let cleaned = cardNumber.replacingOccurrences(of: "[\\s-]", with: "", options: .regularExpression)
// Must be mostly numeric
guard cleaned.range(of: "^\\d{4,}", options: .regularExpression) != nil else {
return .generic
}
// Visa: starts with 4
if cleaned.hasPrefix("4") {
return .visa
}
// Mastercard: starts with 51-55 or 2221-2720
if cleaned.range(of: "^5[1-5]", options: .regularExpression) != nil ||
cleaned.range(of: "^2[2-7]", options: .regularExpression) != nil {
return .mastercard
}
// Amex: starts with 34 or 37
if cleaned.range(of: "^3[47]", options: .regularExpression) != nil {
return .amex
}
// Discover: starts with 6011, 622, 644-649, 65
if cleaned.range(of: "^6(?:011|22|4[4-9]|5)", options: .regularExpression) != nil {
return .discover
}
return .generic
}
}
/// Generic credit card icon SVG
public static let creditCardIcon = """
<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="2" y="6" width="28" height="20" rx="3" fill="#f49541"/>
<rect x="2" y="11" width="28" height="4" fill="#d68338"/>
<rect x="5" y="18" width="8" height="2" rx="1" fill="#ffe096"/>
<rect x="5" y="22" width="5" height="1.5" rx="0.75" fill="#fbcb74"/>
</svg>
"""
/// Visa card icon SVG
public static let visaIcon = """
<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="2" y="6" width="28" height="20" rx="3" fill="#f49541"/>
<path d="M13.5 13L11.5 19H10L8.5 14.5C8.5 14.5 8.35 14 8 14C7.65 14 7 13.8 7 13.8L7.05 13.5H9.5C9.85 13.5 10.15 13.75 10.2 14.1L10.8 17L12.5 13.5H13.5V13ZM15 19H14L15 13H16L15 19ZM20 13.5C20 13.5 19.4 13.3 18.7 13.3C17.35 13.3 16.4 14 16.4 15C16.4 15.8 17.1 16.2 17.65 16.5C18.2 16.8 18.4 17 18.4 17.2C18.4 17.5 18.05 17.7 17.6 17.7C17 17.7 16.5 17.5 16.5 17.5L16.3 18.7C16.3 18.7 16.9 19 17.7 19C19.2 19 20.1 18.2 20.1 17.1C20.1 15.7 18.4 15.6 18.4 15C18.4 14.7 18.7 14.5 19.15 14.5C19.6 14.5 20.1 14.7 20.1 14.7L20.3 13.5H20V13.5ZM24 19L23.1 13.5H22C21.7 13.5 21.45 13.7 21.35 13.95L19 19H20.5L20.8 18H22.7L22.9 19H24ZM21.2 17L22 14.5L22.45 17H21.2Z" fill="#ffe096"/>
</svg>
"""
/// Mastercard icon SVG
public static let mastercardIcon = """
<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="2" y="6" width="28" height="20" rx="3" fill="#f49541"/>
<circle cx="13" cy="16" r="5" fill="#d68338"/>
<circle cx="19" cy="16" r="5" fill="#ffe096"/>
<path d="M16 12.5C17.1 13.4 17.8 14.6 17.8 16C17.8 17.4 17.1 18.6 16 19.5C14.9 18.6 14.2 17.4 14.2 16C14.2 14.6 14.9 13.4 16 12.5Z" fill="#fbcb74"/>
</svg>
"""
/// Amex card icon SVG
public static let amexIcon = """
<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="2" y="6" width="28" height="20" rx="3" fill="#f49541"/>
<text x="16" y="18" text-anchor="middle" fill="#ffe096" font-size="8" font-weight="bold" font-family="Arial, sans-serif">AMEX</text>
</svg>
"""
/// Discover card icon SVG
public static let discoverIcon = """
<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="2" y="6" width="28" height="20" rx="3" fill="#f49541"/>
<circle cx="20" cy="16" r="4" fill="#ffe096"/>
<path d="M7 14H8.5C9.3 14 10 14.7 10 15.5C10 16.3 9.3 17 8.5 17H7V14Z" fill="#ffe096"/>
<rect x="11" y="14" width="1.5" height="3" fill="#ffe096"/>
<path d="M14 15C14 14.4 14.4 14 15 14C15.3 14 15.5 14.1 15.7 14.3L16.5 13.5C16.1 13.2 15.6 13 15 13C13.9 13 13 13.9 13 15C13 16.1 13.9 17 15 17C15.6 17 16.1 16.8 16.5 16.5L15.7 15.7C15.5 15.9 15.3 16 15 16C14.4 16 14 15.6 14 15Z" fill="#ffe096"/>
</svg>
"""
/// Note/document icon SVG
public static let noteIcon = """
<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 4C6.9 4 6 4.9 6 6V26C6 27.1 6.9 28 8 28H24C25.1 28 26 27.1 26 26V11L19 4H8Z" fill="#f49541"/>
<path d="M19 4V11H26L19 4Z" fill="#d68338"/>
<rect x="10" y="14" width="12" height="1.5" rx="0.75" fill="#ffe096"/>
<rect x="10" y="18" width="10" height="1.5" rx="0.75" fill="#ffe096"/>
<rect x="10" y="22" width="8" height="1.5" rx="0.75" fill="#ffe096"/>
</svg>
"""
/// Placeholder key icon SVG for Login/Alias without logo
public static let placeholderIcon = """
<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="10" cy="10" r="6.5" stroke="#f49541" stroke-width="2.5"/>
<circle cx="10" cy="10" r="2.5" stroke="#f49541" stroke-width="2"/>
<path d="M15 15L27 27" stroke="#f49541" stroke-width="2.5" stroke-linecap="round"/>
<path d="M19 19L23 15" stroke="#f49541" stroke-width="2.5" stroke-linecap="round"/>
<path d="M24 24L28 20" stroke="#f49541" stroke-width="2.5" stroke-linecap="round"/>
</svg>
"""
/// Get the appropriate SVG icon for a credit card brand
public static func getCardIcon(for brand: CardBrand) -> String {
switch brand {
case .visa:
return visaIcon
case .mastercard:
return mastercardIcon
case .amex:
return amexIcon
case .discover:
return discoverIcon
case .generic:
return creditCardIcon
}
}
/// Get the appropriate SVG icon for an item type
public static func getIcon(for itemType: ItemType, cardNumber: String? = nil) -> String {
switch itemType {
case .note:
return noteIcon
case .creditCard:
let brand = CardBrand.detect(from: cardNumber)
return getCardIcon(for: brand)
case .login, .alias:
return placeholderIcon
}
}
}

View File

@@ -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: "<svg viewBox=\"0 0 32 32\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"10\" cy=\"10\" r=\"6.5\" stroke=\"#f49541\" stroke-width=\"2.5\"/>\n <circle cx=\"10\" cy=\"10\" r=\"2.5\" stroke=\"#ff0000\" stroke-width=\"2\"/>\n <path d=\"M15 15L27 27\" stroke=\"#f49541\" stroke-width=\"2.5\" stroke-linecap=\"round\"/>\n <path d=\"M19 19L23 15\" stroke=\"#f49541\" stroke-width=\"2.5\" stroke-linecap=\"round\"/>\n <path d=\"M24 24L28 20\" stroke=\"#f49541\" stroke-width=\"2.5\" stroke-linecap=\"round\"/>\n</svg>";
/**
* Note/document icon with folded corner.
* Used for Note item type.
*/
readonly Note: "<svg viewBox=\"0 0 32 32\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M8 4C6.9 4 6 4.9 6 6V26C6 27.1 6.9 28 8 28H24C25.1 28 26 27.1 26 26V11L19 4H8Z\" fill=\"#f49541\"/>\n <path d=\"M19 4V11H26L19 4Z\" fill=\"#d68338\"/>\n <rect x=\"10\" y=\"14\" width=\"12\" height=\"1.5\" rx=\"0.75\" fill=\"#ffe096\"/>\n <rect x=\"10\" y=\"18\" width=\"10\" height=\"1.5\" rx=\"0.75\" fill=\"#ffe096\"/>\n <rect x=\"10\" y=\"22\" width=\"8\" height=\"1.5\" rx=\"0.75\" fill=\"#ffe096\"/>\n</svg>";
/**
* Generic credit card icon.
* Used when card brand cannot be detected.
*/
readonly CreditCard: "<svg viewBox=\"0 0 32 32\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <rect x=\"2\" y=\"6\" width=\"28\" height=\"20\" rx=\"3\" fill=\"#f49541\"/>\n <rect x=\"2\" y=\"11\" width=\"28\" height=\"4\" fill=\"#d68338\"/>\n <rect x=\"5\" y=\"18\" width=\"8\" height=\"2\" rx=\"1\" fill=\"#ffe096\"/>\n <rect x=\"5\" y=\"22\" width=\"5\" height=\"1.5\" rx=\"0.75\" fill=\"#fbcb74\"/>\n</svg>";
/**
* Visa card icon with brand styling.
*/
readonly Visa: "<svg viewBox=\"0 0 32 32\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <rect x=\"2\" y=\"6\" width=\"28\" height=\"20\" rx=\"3\" fill=\"#f49541\"/>\n <path d=\"M13.5 13L11.5 19H10L8.5 14.5C8.5 14.5 8.35 14 8 14C7.65 14 7 13.8 7 13.8L7.05 13.5H9.5C9.85 13.5 10.15 13.75 10.2 14.1L10.8 17L12.5 13.5H13.5V13ZM15 19H14L15 13H16L15 19ZM20 13.5C20 13.5 19.4 13.3 18.7 13.3C17.35 13.3 16.4 14 16.4 15C16.4 15.8 17.1 16.2 17.65 16.5C18.2 16.8 18.4 17 18.4 17.2C18.4 17.5 18.05 17.7 17.6 17.7C17 17.7 16.5 17.5 16.5 17.5L16.3 18.7C16.3 18.7 16.9 19 17.7 19C19.2 19 20.1 18.2 20.1 17.1C20.1 15.7 18.4 15.6 18.4 15C18.4 14.7 18.7 14.5 19.15 14.5C19.6 14.5 20.1 14.7 20.1 14.7L20.3 13.5H20V13.5ZM24 19L23.1 13.5H22C21.7 13.5 21.45 13.7 21.35 13.95L19 19H20.5L20.8 18H22.7L22.9 19H24ZM21.2 17L22 14.5L22.45 17H21.2Z\" fill=\"#ffe096\"/>\n</svg>";
/**
* Mastercard icon with overlapping circles.
*/
readonly Mastercard: "<svg viewBox=\"0 0 32 32\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <rect x=\"2\" y=\"6\" width=\"28\" height=\"20\" rx=\"3\" fill=\"#f49541\"/>\n <circle cx=\"13\" cy=\"16\" r=\"5\" fill=\"#d68338\"/>\n <circle cx=\"19\" cy=\"16\" r=\"5\" fill=\"#ffe096\"/>\n <path d=\"M16 12.5C17.1 13.4 17.8 14.6 17.8 16C17.8 17.4 17.1 18.6 16 19.5C14.9 18.6 14.2 17.4 14.2 16C14.2 14.6 14.9 13.4 16 12.5Z\" fill=\"#fbcb74\"/>\n</svg>";
/**
* American Express card icon.
*/
readonly Amex: "<svg viewBox=\"0 0 32 32\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <rect x=\"2\" y=\"6\" width=\"28\" height=\"20\" rx=\"3\" fill=\"#f49541\"/>\n <text x=\"16\" y=\"18\" text-anchor=\"middle\" fill=\"#ffe096\" font-size=\"8\" font-weight=\"bold\" font-family=\"Arial, sans-serif\">AMEX</text>\n</svg>";
/**
* Discover card icon with orange circle logo.
*/
readonly Discover: "<svg viewBox=\"0 0 32 32\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <rect x=\"2\" y=\"6\" width=\"28\" height=\"20\" rx=\"3\" fill=\"#f49541\"/>\n <circle cx=\"20\" cy=\"16\" r=\"4\" fill=\"#ffe096\"/>\n <path d=\"M7 14H8.5C9.3 14 10 14.7 10 15.5C10 16.3 9.3 17 8.5 17H7V14Z\" fill=\"#ffe096\"/>\n <rect x=\"11\" y=\"14\" width=\"1.5\" height=\"3\" fill=\"#ffe096\"/>\n <path d=\"M14 15C14 14.4 14.4 14 15 14C15.3 14 15.5 14.1 15.7 14.3L16.5 13.5C16.1 13.2 15.6 13 15 13C13.9 13 13 13.9 13 15C13 16.1 13.9 17 15 17C15.6 17 16.1 16.8 16.5 16.5L15.7 15.7C15.5 15.9 15.3 16 15 16C14.4 16 14 15.6 14 15Z\" fill=\"#ffe096\"/>\n</svg>";
};
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 };

View File

@@ -0,0 +1,82 @@
// <auto-generated>
// 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: `<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="10" cy="10" r="6.5" stroke="#f49541" stroke-width="2.5"/>
<circle cx="10" cy="10" r="2.5" stroke="#ff0000" stroke-width="2"/>
<path d="M15 15L27 27" stroke="#f49541" stroke-width="2.5" stroke-linecap="round"/>
<path d="M19 19L23 15" stroke="#f49541" stroke-width="2.5" stroke-linecap="round"/>
<path d="M24 24L28 20" stroke="#f49541" stroke-width="2.5" stroke-linecap="round"/>
</svg>`,
/**
* Note/document icon with folded corner.
* Used for Note item type.
*/
Note: `<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 4C6.9 4 6 4.9 6 6V26C6 27.1 6.9 28 8 28H24C25.1 28 26 27.1 26 26V11L19 4H8Z" fill="#f49541"/>
<path d="M19 4V11H26L19 4Z" fill="#d68338"/>
<rect x="10" y="14" width="12" height="1.5" rx="0.75" fill="#ffe096"/>
<rect x="10" y="18" width="10" height="1.5" rx="0.75" fill="#ffe096"/>
<rect x="10" y="22" width="8" height="1.5" rx="0.75" fill="#ffe096"/>
</svg>`,
/**
* Generic credit card icon.
* Used when card brand cannot be detected.
*/
CreditCard: `<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="2" y="6" width="28" height="20" rx="3" fill="#f49541"/>
<rect x="2" y="11" width="28" height="4" fill="#d68338"/>
<rect x="5" y="18" width="8" height="2" rx="1" fill="#ffe096"/>
<rect x="5" y="22" width="5" height="1.5" rx="0.75" fill="#fbcb74"/>
</svg>`,
/**
* Visa card icon with brand styling.
*/
Visa: `<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="2" y="6" width="28" height="20" rx="3" fill="#f49541"/>
<path d="M13.5 13L11.5 19H10L8.5 14.5C8.5 14.5 8.35 14 8 14C7.65 14 7 13.8 7 13.8L7.05 13.5H9.5C9.85 13.5 10.15 13.75 10.2 14.1L10.8 17L12.5 13.5H13.5V13ZM15 19H14L15 13H16L15 19ZM20 13.5C20 13.5 19.4 13.3 18.7 13.3C17.35 13.3 16.4 14 16.4 15C16.4 15.8 17.1 16.2 17.65 16.5C18.2 16.8 18.4 17 18.4 17.2C18.4 17.5 18.05 17.7 17.6 17.7C17 17.7 16.5 17.5 16.5 17.5L16.3 18.7C16.3 18.7 16.9 19 17.7 19C19.2 19 20.1 18.2 20.1 17.1C20.1 15.7 18.4 15.6 18.4 15C18.4 14.7 18.7 14.5 19.15 14.5C19.6 14.5 20.1 14.7 20.1 14.7L20.3 13.5H20V13.5ZM24 19L23.1 13.5H22C21.7 13.5 21.45 13.7 21.35 13.95L19 19H20.5L20.8 18H22.7L22.9 19H24ZM21.2 17L22 14.5L22.45 17H21.2Z" fill="#ffe096"/>
</svg>`,
/**
* Mastercard icon with overlapping circles.
*/
Mastercard: `<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="2" y="6" width="28" height="20" rx="3" fill="#f49541"/>
<circle cx="13" cy="16" r="5" fill="#d68338"/>
<circle cx="19" cy="16" r="5" fill="#ffe096"/>
<path d="M16 12.5C17.1 13.4 17.8 14.6 17.8 16C17.8 17.4 17.1 18.6 16 19.5C14.9 18.6 14.2 17.4 14.2 16C14.2 14.6 14.9 13.4 16 12.5Z" fill="#fbcb74"/>
</svg>`,
/**
* American Express card icon.
*/
Amex: `<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="2" y="6" width="28" height="20" rx="3" fill="#f49541"/>
<text x="16" y="18" text-anchor="middle" fill="#ffe096" font-size="8" font-weight="bold" font-family="Arial, sans-serif">AMEX</text>
</svg>`,
/**
* Discover card icon with orange circle logo.
*/
Discover: `<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="2" y="6" width="28" height="20" rx="3" fill="#f49541"/>
<circle cx="20" cy="16" r="4" fill="#ffe096"/>
<path d="M7 14H8.5C9.3 14 10 14.7 10 15.5C10 16.3 9.3 17 8.5 17H7V14Z" fill="#ffe096"/>
<rect x="11" y="14" width="1.5" height="3" fill="#ffe096"/>
<path d="M14 15C14 14.4 14.4 14 15 14C15.3 14 15.5 14.1 15.7 14.3L16.5 13.5C16.1 13.2 15.6 13 15 13C13.9 13 13 13.9 13 15C13 16.1 13.9 17 15 17C15.6 17 16.1 16.8 16.5 16.5L15.7 15.7C15.5 15.9 15.3 16 15 16C14.4 16 14 15.6 14 15Z" fill="#ffe096"/>
</svg>`
};
function getItemTypeIconSvg(key) {
return ItemTypeIconSvgs[key];
}
function getAllIconKeys() {
return Object.keys(ItemTypeIconSvgs);
}
export { ItemTypeIconSvgs, getAllIconKeys, getItemTypeIconSvg };
//# sourceMappingURL=index.js.map
//# sourceMappingURL=index.js.map