components/explorer/FeedCardCollection.tsx

component·mobile·4.5 KB · 156 lignes· Voir l'itinéraire
Annotation non disponible

Lance npm run annotate (nécessite ANTHROPIC_API_KEY dans .env.local) pour générer une annotation française par Claude Haiku 4.5.

1 export

FeedCardCollection

Code source· tsx

import React, { useMemo } from 'react';
import { View, Text, StyleSheet, TouchableOpacity, ImageBackground } from 'react-native';
import { router } from 'expo-router';
import { useTheme } from '@/hooks/useTheme';
import { FONTS, SPACING, RADIUS } from '@/lib/constants';
import type { CollectionSummary } from '@/types/api';
import { haptics } from '@/lib/haptics';
import { ArrowRight } from '@/lib/icons';

// Sprint Explorer Feed Algorithmique — 2026-05-18
// Hero card collection éditoriale : bannière + emoji + nom + CTA Explorer.

type Props = { collection: CollectionSummary };

export function FeedCardCollection({ collection }: Props) {
  const { colors } = useTheme();
  const styles = useMemo(() => makeStyles(colors), [colors]);

  const onPress = () => {
    haptics.selection();
    router.push((`/explorer/collection/${collection.slug}`) as any);
  };

  const subtitle =
    collection.nbItems > 0
      ? `${collection.nbItems} item${collection.nbItems > 1 ? 's' : ''}`
      : 'Collection éditoriale';

  return (
    <TouchableOpacity
      style={styles.card}
      activeOpacity={0.85}
      onPress={onPress}
      accessibilityRole="button"
      accessibilityLabel={`Collection ${collection.nom}, ${subtitle}`}
      accessibilityHint="Appuie pour explorer la collection"
    >
      {collection.imageUrl ? (
        <ImageBackground
          source={{ uri: collection.imageUrl }}
          style={styles.bg}
          imageStyle={styles.bgImage}
        >
          <View style={styles.overlay}>
            <Inner collection={collection} subtitle={subtitle} colors={colors} />
          </View>
        </ImageBackground>
      ) : (
        <View style={[styles.bg, { backgroundColor: colors.bgElevated }]}>
          <Inner collection={collection} subtitle={subtitle} colors={colors} />
        </View>
      )}
    </TouchableOpacity>
  );
}

function Inner({
  collection,
  subtitle,
  colors,
}: {
  collection: CollectionSummary;
  subtitle: string;
  colors: ReturnType<typeof useTheme>['colors'];
}) {
  return (
    <View style={{ padding: SPACING.lg, flex: 1, justifyContent: 'space-between' }}>
      <View style={{ flexDirection: 'row', alignItems: 'center', gap: SPACING.sm }}>
        {collection.emoji ? (
          <Text style={{ fontSize: 36 }}>{collection.emoji}</Text>
        ) : null}
        <View style={{ flex: 1 }}>
          <Text
            style={{
              color: '#fff',
              fontSize: FONTS.lg,
              fontWeight: FONTS.bold,
              textShadowColor: 'rgba(0,0,0,0.6)',
              textShadowRadius: 4,
            }}
            numberOfLines={2}
          >
            {collection.nom}
          </Text>
          <Text
            style={{
              color: '#fff',
              fontSize: FONTS.xs,
              opacity: 0.9,
              marginTop: 2,
              textShadowColor: 'rgba(0,0,0,0.6)',
              textShadowRadius: 4,
            }}
          >
            {subtitle}
          </Text>
        </View>
      </View>

      <View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between' }}>
        {collection.description ? (
          <Text
            style={{
              color: '#fff',
              fontSize: FONTS.sm,
              opacity: 0.92,
              flex: 1,
              marginRight: SPACING.sm,
              textShadowColor: 'rgba(0,0,0,0.6)',
              textShadowRadius: 4,
            }}
            numberOfLines={2}
          >
            {collection.description}
          </Text>
        ) : <View style={{ flex: 1 }} />}
        <View
          style={{
            flexDirection: 'row',
            alignItems: 'center',
            gap: 4,
            paddingHorizontal: SPACING.md,
            paddingVertical: SPACING.sm,
            backgroundColor: colors.primary,
            borderRadius: RADIUS.full,
          }}
        >
          <Text style={{ color: '#fff', fontSize: FONTS.sm, fontWeight: FONTS.bold }}>
            Explorer
          </Text>
          <ArrowRight size={14} color="#fff" weight="bold" />
        </View>
      </View>
    </View>
  );
}

function makeStyles(colors: ReturnType<typeof useTheme>['colors']) {
  return StyleSheet.create({
    card: {
      width: '100%',
      height: 160,
      borderRadius: RADIUS.lg,
      overflow: 'hidden',
      backgroundColor: colors.bgCard,
      marginBottom: SPACING.md,
    },
    bg: { flex: 1 },
    bgImage: { borderRadius: RADIUS.lg },
    overlay: {
      flex: 1,
      backgroundColor: 'rgba(0,0,0,0.42)',
    },
  });
}