mirror of
https://github.com/aliasvault/aliasvault.git
synced 2026-02-02 02:13:48 -05:00
Update mobile app to use generic item type icons (#1465)
This commit is contained in:
committed by
Leendert de Borst
parent
b818876971
commit
2dab52c1b4
@@ -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()
|
||||
}
|
||||
@@ -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',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
82
apps/mobile-app/components/items/ItemTypeIconComponents.tsx
Normal file
82
apps/mobile-app/components/items/ItemTypeIconComponents.tsx
Normal 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;
|
||||
@@ -3,7 +3,7 @@
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 60;
|
||||
objectVersion = 70;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
|
||||
79
apps/mobile-app/ios/VaultModels/ItemTypeIcons.swift
Normal file
79
apps/mobile-app/ios/VaultModels/ItemTypeIcons.swift
Normal 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>
|
||||
"""
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
64
apps/mobile-app/utils/dist/core/models/icons/index.d.ts
vendored
Normal file
64
apps/mobile-app/utils/dist/core/models/icons/index.d.ts
vendored
Normal 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 };
|
||||
82
apps/mobile-app/utils/dist/core/models/icons/index.js
vendored
Normal file
82
apps/mobile-app/utils/dist/core/models/icons/index.js
vendored
Normal 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
|
||||
Reference in New Issue
Block a user