Livrare Lot 3 (Frontend): aplicație web, aplicație mobilă Android, extensie browser

- Surse complete web (React/Vite) + mobil (React Native/Expo) + extensie (MV3)
- Documentație de livrare: ghid utilizare, matrice trasabilitate cerințe, raport testare furnizor
- Artefacte binare: imagine Docker didi-frontend:lot3-1.0, APK, extensie v3.2.6 + SHA256SUMS
- Configurare adresă platformă externalizată (build args / .env / config.js)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Top Clossers 2026-07-17 12:33:59 +03:00
commit cec967f953
321 changed files with 80506 additions and 0 deletions

View file

@ -0,0 +1,105 @@
import React from 'react';
import { View, TouchableOpacity, Text, StyleSheet, ViewStyle } from 'react-native';
import { LinearGradient } from 'expo-linear-gradient';
import { COLORS, SPACING, RADIUS, FONT_SIZES, FONT_WEIGHTS, LAYOUT } from '../theme/colors';
interface GlassCardProps {
title: string;
subtitle: string;
iconLabel?: string;
iconColors?: readonly [string, string];
onPress?: () => void;
style?: ViewStyle;
borderColor?: string;
}
export default function GlassCard({
title,
subtitle,
iconLabel,
iconColors,
onPress,
style,
borderColor,
}: GlassCardProps) {
const Wrapper = onPress ? TouchableOpacity : View;
return (
<Wrapper
activeOpacity={0.7}
onPress={onPress}
accessibilityRole={onPress ? 'button' : undefined}
accessibilityLabel={onPress ? `${title}. ${subtitle}` : undefined}
style={[
styles.card,
borderColor ? { borderColor } : undefined,
style,
]}
>
<View style={styles.content}>
{iconLabel && (
<LinearGradient
colors={iconColors ? [...iconColors] as [string, string] : [COLORS.brand.primary, COLORS.brand.accentMagenta]}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 1 }}
style={styles.iconCircle}
>
<Text style={styles.iconText}>{iconLabel}</Text>
</LinearGradient>
)}
<View style={styles.textContainer}>
<Text style={styles.title}>{title}</Text>
<Text style={styles.subtitle}>{subtitle}</Text>
</View>
{onPress && <Text style={styles.arrow}></Text>}
</View>
</Wrapper>
);
}
const styles = StyleSheet.create({
card: {
backgroundColor: COLORS.bg.card,
borderWidth: 1,
borderColor: COLORS.border.accent,
borderRadius: RADIUS.xxl,
padding: SPACING.lg,
marginBottom: SPACING.sm + 4,
},
content: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
},
iconCircle: {
width: LAYOUT.ICON_CIRCLE_SIZE,
height: LAYOUT.ICON_CIRCLE_SIZE,
borderRadius: RADIUS.full,
justifyContent: 'center',
alignItems: 'center',
marginRight: SPACING.md,
},
iconText: {
color: COLORS.text.primary,
fontSize: FONT_SIZES.lg,
fontWeight: FONT_WEIGHTS.bold,
},
textContainer: {
flex: 1,
},
title: {
color: COLORS.text.primary,
fontSize: FONT_SIZES.base,
fontWeight: FONT_WEIGHTS.bold,
},
subtitle: {
color: COLORS.text.secondary,
fontSize: FONT_SIZES.sm,
marginTop: 2,
},
arrow: {
color: COLORS.text.hint,
fontSize: FONT_SIZES.xxl,
fontWeight: FONT_WEIGHTS.bold,
},
});