This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

test: image card

+288
+212
src/webapp/features/cards/components/imageCard/ImageCard.stories.tsx
··· 1 + import type { Meta, StoryObj } from '@storybook/nextjs-vite'; 2 + import { CollectionAccessType } from '@semble/types'; 3 + import type { Collection } from '@semble/types'; 4 + import ImageCard from './ImageCard'; 5 + import { AuthContext } from '@/hooks/useAuth'; 6 + import type { AuthContextType } from '@/hooks/useAuth'; 7 + 8 + const mockAuthUser = { 9 + id: 'did:plc:mock123', 10 + name: 'Test User', 11 + handle: 'test.user', 12 + avatarUrl: 'https://i.pravatar.cc/150?u=testuser', 13 + }; 14 + 15 + const mockAuthValue: AuthContextType = { 16 + user: mockAuthUser as any, 17 + isAuthenticated: true, 18 + isLoading: false, 19 + refreshAuth: async () => {}, 20 + logout: async () => {}, 21 + }; 22 + 23 + const cardAuthor = { 24 + id: 'did:plc:author456', 25 + name: 'Jane Researcher', 26 + handle: 'jane.researcher', 27 + avatarUrl: 'https://i.pravatar.cc/150?u=jane', 28 + description: 'Science writer and open-access advocate.', 29 + followerCount: 214, 30 + followingCount: 63, 31 + }; 32 + 33 + const baseCollection: Collection = { 34 + id: 'col-story-001', 35 + uri: 'at://did:plc:colauthor789/app.semble.collection/3juzt2xkr5c2a', 36 + name: 'Photography Inspiration', 37 + author: { 38 + id: 'did:plc:colauthor789', 39 + name: 'Alex Curator', 40 + handle: 'alex.curator', 41 + avatarUrl: 'https://i.pravatar.cc/150?u=alex', 42 + }, 43 + description: 'A curated collection of inspiring photography.', 44 + accessType: CollectionAccessType.CLOSED, 45 + cardCount: 18, 46 + createdAt: '2024-09-15T12:00:00.000Z', 47 + updatedAt: '2025-06-20T09:30:00.000Z', 48 + isFollowing: false, 49 + followerCount: 31, 50 + }; 51 + 52 + const baseCardContent = { 53 + url: 'https://example.com/photo-1', 54 + title: 'Golden Hour Over the Mountains', 55 + description: 'A breathtaking landscape captured during golden hour.', 56 + imageUrl: 'https://picsum.photos/seed/imagecard1/800/600', 57 + siteName: 'Unsplash', 58 + type: 'article', 59 + retrievedAt: '2025-06-01T10:00:00.000Z', 60 + }; 61 + 62 + const meta: Meta<typeof ImageCard> = { 63 + title: 'Features/Cards/ImageCard', 64 + component: ImageCard, 65 + decorators: [ 66 + (Story) => ( 67 + <AuthContext.Provider value={mockAuthValue}> 68 + <div style={{ maxWidth: 360 }}> 69 + <Story /> 70 + </div> 71 + </AuthContext.Provider> 72 + ), 73 + ], 74 + args: { 75 + id: 'card-img-001', 76 + cardContent: baseCardContent, 77 + urlLibraryCount: 5, 78 + urlIsInLibrary: false, 79 + urlConnectionCount: 2, 80 + urlIsConnected: false, 81 + }, 82 + }; 83 + 84 + export default meta; 85 + 86 + type Story = StoryObj<typeof ImageCard>; 87 + 88 + export const Default: Story = {}; 89 + 90 + export const LongTitle: Story = { 91 + args: { 92 + id: 'card-img-longtitle', 93 + cardContent: { 94 + ...baseCardContent, 95 + url: 'https://example.com/photo-long-title', 96 + title: 97 + 'An Incredibly Long Title That Should Be Truncated After Two Lines Because It Contains Way Too Much Text For a Card Header', 98 + imageUrl: 'https://picsum.photos/seed/imagecard-long/800/600', 99 + }, 100 + }, 101 + }; 102 + 103 + export const InLibrary: Story = { 104 + args: { 105 + id: 'card-img-library', 106 + urlIsInLibrary: true, 107 + urlLibraryCount: 42, 108 + cardContent: { 109 + ...baseCardContent, 110 + url: 'https://example.com/photo-library', 111 + title: 'Misty Forest Path', 112 + imageUrl: 'https://picsum.photos/seed/imagecard2/800/1000', 113 + siteName: 'Pexels', 114 + }, 115 + }, 116 + }; 117 + 118 + export const Connected: Story = { 119 + args: { 120 + id: 'card-img-connected', 121 + urlIsConnected: true, 122 + urlConnectionCount: 8, 123 + cardContent: { 124 + ...baseCardContent, 125 + url: 'https://example.com/photo-connected', 126 + title: 'Urban Architecture at Night', 127 + imageUrl: 'https://picsum.photos/seed/imagecard3/800/500', 128 + siteName: 'Flickr', 129 + }, 130 + }, 131 + }; 132 + 133 + export const WithNote: Story = { 134 + args: { 135 + id: 'card-img-note', 136 + note: { 137 + id: 'note-img-001', 138 + text: 'Love the composition in this shot. The leading lines draw you right into the frame.', 139 + }, 140 + cardContent: { 141 + ...baseCardContent, 142 + url: 'https://example.com/photo-noted', 143 + title: 'Desert Dunes at Sunset', 144 + imageUrl: 'https://picsum.photos/seed/imagecard4/800/600', 145 + }, 146 + }, 147 + }; 148 + 149 + export const WithCollection: Story = { 150 + args: { 151 + id: 'card-img-collection', 152 + currentCollection: baseCollection, 153 + cardAuthor: cardAuthor, 154 + authorHandle: cardAuthor.handle, 155 + cardContent: { 156 + ...baseCardContent, 157 + url: 'https://example.com/photo-collection', 158 + title: 'Coastal Cliffs of Ireland', 159 + imageUrl: 'https://picsum.photos/seed/imagecard5/800/550', 160 + siteName: 'National Geographic', 161 + }, 162 + }, 163 + }; 164 + 165 + export const HighCounts: Story = { 166 + args: { 167 + id: 'card-img-highcounts', 168 + urlLibraryCount: 1523, 169 + urlIsInLibrary: true, 170 + urlConnectionCount: 347, 171 + urlIsConnected: true, 172 + cardAuthor: cardAuthor, 173 + authorHandle: cardAuthor.handle, 174 + note: { 175 + id: 'note-img-002', 176 + text: 'One of the most shared images on the platform. The colors are unreal.', 177 + }, 178 + cardContent: { 179 + ...baseCardContent, 180 + url: 'https://example.com/photo-viral', 181 + title: 'Aurora Borealis Over Iceland', 182 + imageUrl: 'https://picsum.photos/seed/imagecard6/800/600', 183 + siteName: 'Earth Porn', 184 + }, 185 + }, 186 + }; 187 + 188 + export const WideImage: Story = { 189 + args: { 190 + id: 'card-img-wide', 191 + cardContent: { 192 + ...baseCardContent, 193 + url: 'https://example.com/photo-panoramic', 194 + title: 'Panoramic View of the Grand Canyon', 195 + imageUrl: 'https://picsum.photos/seed/imagecard7/1200/400', 196 + siteName: 'Panoramics', 197 + }, 198 + }, 199 + }; 200 + 201 + export const TallImage: Story = { 202 + args: { 203 + id: 'card-img-tall', 204 + cardContent: { 205 + ...baseCardContent, 206 + url: 'https://example.com/photo-portrait', 207 + title: 'Narrow Alley in Venice', 208 + imageUrl: 'https://picsum.photos/seed/imagecard8/400/900', 209 + siteName: 'Travel Blog', 210 + }, 211 + }, 212 + };
+76
src/webapp/features/cards/components/imageCard/ImageCard.tsx
··· 1 + 'use client'; 2 + 3 + import type { UrlCard, Collection, User } from '@/api-client'; 4 + import { Card, Image, Stack, Text } from '@mantine/core'; 5 + import UrlCardActions from '../urlCardActions/UrlCardActions'; 6 + import { CardSaveAnalyticsContext } from '@/features/analytics/types'; 7 + 8 + interface Props { 9 + id: string; 10 + cardContent: UrlCard['cardContent']; 11 + note?: UrlCard['note']; 12 + currentCollection?: Collection; 13 + urlLibraryCount: number; 14 + urlIsInLibrary?: boolean; 15 + urlConnectionCount: number; 16 + urlIsConnected?: boolean; 17 + authorHandle?: string; 18 + cardAuthor?: User; 19 + viaCardId?: string; 20 + analyticsContext?: CardSaveAnalyticsContext; 21 + onClick?: (e: React.MouseEvent<HTMLElement>) => void; 22 + } 23 + 24 + export default function ImageCard(props: Props) { 25 + return ( 26 + <Card 27 + component="article" 28 + radius="lg" 29 + p="sm" 30 + flex={1} 31 + h="100%" 32 + withBorder 33 + style={{ cursor: 'pointer' }} 34 + onClick={props.onClick} 35 + > 36 + <Stack gap="xs" justify="space-between" flex={1}> 37 + <Stack gap="xs"> 38 + {props.cardContent.title && ( 39 + <Text fz="sm" c="gray" lineClamp={2}> 40 + {props.cardContent.title} 41 + </Text> 42 + )} 43 + 44 + {props.cardContent.imageUrl && ( 45 + <Image 46 + src={props.cardContent.imageUrl} 47 + alt={props.cardContent.title || 'Card image'} 48 + w="100%" 49 + mah={400} 50 + radius="md" 51 + fit="cover" 52 + /> 53 + )} 54 + </Stack> 55 + 56 + <Stack gap="xs" pt={0}> 57 + <UrlCardActions 58 + cardAuthor={props.cardAuthor} 59 + cardContent={props.cardContent} 60 + cardCount={props.urlLibraryCount} 61 + id={props.id} 62 + authorHandle={props.authorHandle} 63 + note={props.note} 64 + currentCollection={props.currentCollection} 65 + urlLibraryCount={props.urlLibraryCount} 66 + urlIsInLibrary={props.urlIsInLibrary ?? false} 67 + urlConnectionCount={props.urlConnectionCount} 68 + urlIsConnected={props.urlIsConnected} 69 + viaCardId={props.viaCardId} 70 + analyticsContext={props.analyticsContext} 71 + /> 72 + </Stack> 73 + </Stack> 74 + </Card> 75 + ); 76 + }