11import React from 'react' ;
22import { Link } from 'react-router-dom' ;
3+ import { ArrowRight , Star , CalendarBlank } from '@phosphor-icons/react' ;
4+ import { motion } from 'framer-motion' ;
5+ import GenerativeArt from './GenerativeArt' ;
36import colors from '../config/colors' ;
4- import {
5- BookOpenIcon ,
6- FilmStripIcon ,
7- GameControllerIcon ,
8- ArticleIcon ,
9- MusicNoteIcon ,
10- TelevisionIcon ,
11- ForkKnifeIcon ,
12- GlobeIcon ,
13- StarIcon ,
14- WrenchIcon ,
15- CalendarBlankIcon ,
16- } from '@phosphor-icons/react' ;
17-
18- const categoryIcons = {
19- Book : < BookOpenIcon weight = "duotone" /> ,
20- Movie : < FilmStripIcon weight = "duotone" /> ,
21- Game : < GameControllerIcon weight = "duotone" /> ,
22- Article : < ArticleIcon weight = "duotone" /> ,
23- Music : < MusicNoteIcon weight = "duotone" /> ,
24- Series : < TelevisionIcon weight = "duotone" /> ,
25- Food : < ForkKnifeIcon weight = "duotone" /> ,
26- Websites : < GlobeIcon weight = "duotone" /> ,
27- Tools : < WrenchIcon weight = "duotone" /> ,
28- Event : < CalendarBlankIcon weight = "duotone" /> ,
29- } ;
30-
31- const categoryColors = {
32- Book : colors . book ,
33- Movie : colors . movie ,
34- Game : colors . game ,
35- Article : colors . article ,
36- Music : colors . music ,
37- Series : colors . series ,
38- Food : colors . food ,
39- Websites : colors . websites ,
40- Tools : colors . tools ,
41- Event : colors . event ,
42- } ;
437
448const LogCard = ( { log, index, totalLogs } ) => {
459 const {
@@ -48,146 +12,101 @@ const LogCard = ({ log, index, totalLogs }) => {
4812 author,
4913 by,
5014 director,
51- platform,
52- source,
5315 artist,
54- year,
5516 creator,
5617 date,
5718 rating,
5819 slug,
59- updated,
60- album,
61- releaseDate,
6220 image,
21+ platform,
22+ source
6323 } = log ;
6424
65- const accentColor = categoryColors [ category ] || colors . primary [ 400 ] ;
66- const Icon = categoryIcons [ category ] || < ArticleIcon /> ;
67-
68- const renderStars = ( rating ) => {
69- const stars = [ ] ;
70- for ( let i = 0 ; i < 5 ; i ++ ) {
71- stars . push (
72- < StarIcon
73- key = { i }
74- size = { 14 }
75- weight = "fill"
76- className = { i < rating ? '' : 'opacity-30' }
77- style = { { color : i < rating ? accentColor : '#9ca3af' } }
78- /> ,
79- ) ;
80- }
81- return < div className = "flex gap-0.5" > { stars } </ div > ;
82- } ;
83-
84- // Metadata helper to avoid rendering empty fields
85- const MetadataItem = ( { label, value } ) =>
86- value ? (
87- < div
88- className = "flex items-center gap-1 text-xs text-gray-300 px-2 py-1 rounded-md border border-gray-500/50"
89- style = { { backgroundColor : `${ accentColor } 20` } }
90- >
91- < span className = "font-semibold text-gray-400" > { label } :</ span >
92- < span className = "truncate max-w-[150px]" > { value } </ span >
93- </ div >
94- ) : null ;
25+ // Resolve the primary creator/source
26+ const creatorName = by || author || artist || creator || director ;
27+ const sourceName = platform || source ;
28+ const categoryColor = colors [ category . toLowerCase ( ) ] || colors . primary [ 400 ] ;
9529
9630 return (
97- < Link
98- to = { `/logs/ ${ log . category . toLowerCase ( ) } / ${ slug } ` }
99- className = "block h-full group "
31+ < motion . div
32+ whileHover = { { y : - 5 } }
33+ className = "group relative flex flex-col overflow-hidden rounded-sm bg-zinc-900 border border-white/10 h-full"
10034 >
101- < div
102- className = "relative h-full border border-gray-800 rounded-xl overflow-hidden transition-all duration-300 hover:-translate-y-1 hover:shadow-xl hover:border-gray-700 flex flex-col"
103- style = { { backgroundColor : `${ accentColor } 30` } }
104- >
105- { /* Left Border Accent */ }
106- < div
107- className = "absolute top-0 bottom-0 left-0 w-1 transition-all duration-300 group-hover:w-1.5"
108- style = { { backgroundColor : accentColor } }
109- />
110- { /* Dotted Background */ }
111- < div
112- className = "absolute inset-0 opacity-10 group-hover:opacity-20 transition-opacity duration-300 pointer-events-none"
113- style = { {
114- backgroundImage : `radial-gradient(circle, ${ accentColor } 1px, transparent 1px)` ,
115- backgroundSize : '15px 15px' , // Adjust size for desired density
116- } }
117- > </ div >
35+ < Link to = { `/logs/${ category . toLowerCase ( ) } /${ slug } ` } className = "flex flex-col h-full" >
36+ { /* Visual Header */ }
37+ < div className = "relative h-40 w-full overflow-hidden border-b border-white/5" >
38+ { image ? (
39+ < div className = "w-full h-full relative" >
40+ < img src = { image } alt = { title } className = "w-full h-full object-cover transition-transform duration-700 ease-out group-hover:scale-110 opacity-60" />
41+ < div className = "absolute inset-0 bg-zinc-900/40 mix-blend-multiply" />
42+ </ div >
43+ ) : (
44+ < GenerativeArt
45+ seed = { title + category }
46+ className = "w-full h-full opacity-40 transition-transform duration-700 ease-out group-hover:scale-110"
47+ />
48+ ) }
11849
119- { image && (
120- < div className = "absolute bottom-0 right-0 w-28 h-28 overflow-hidden translate-x-4 translate-y-5 rotate-12 z-10 opacity-60 border-0 rounded-xl" >
121- < img src = { image } alt = "log overlay" className = "w-full h-full object-cover opacity-30 grayscale" />
50+ < div className = "absolute inset-0 bg-gradient-to-t from-zinc-900 to-transparent" />
51+
52+ { /* Category Badge */ }
53+ < div className = "absolute top-3 left-3" >
54+ < span
55+ className = "px-2 py-1 text-[9px] font-mono font-bold uppercase tracking-widest border rounded-sm backdrop-blur-md"
56+ style = { {
57+ color : categoryColor ,
58+ backgroundColor : `${ categoryColor } 10` ,
59+ borderColor : `${ categoryColor } 20`
60+ } }
61+ >
62+ { category }
63+ </ span >
12264 </ div >
123- ) }
12465
125- < div className = "p-5 flex flex-col h-full ml-1" >
126- { ' ' }
127- { /* ml-1 to account for border */ }
128- { /* Header: Icon, Index */ }
129- < div className = "flex justify-between items-start mb-3" >
130- < div
131- className = "p-2 rounded-lg text-white"
132- style = { {
133- color : accentColor ,
134- backgroundColor : `${ accentColor } 30` ,
135- } }
136- >
137- < span className = "text-2xl" > { Icon } </ span >
138- </ div >
139- < span className = "text-xs font-mono text-gray-400 group-hover:text-gray-400 transition-colors" >
140- #{ totalLogs - index }
141- </ span >
66+ { /* Rating Badge */ }
67+ { rating > 0 && (
68+ < div className = "absolute bottom-2 right-3 flex items-center gap-1 bg-black/60 backdrop-blur-md px-2 py-1 rounded-full border border-white/10" >
69+ < span className = "font-mono text-xs font-bold text-white" > { rating } </ span >
70+ < Star weight = "fill" size = { 10 } className = "text-yellow-500" />
71+ </ div >
72+ ) }
73+ </ div >
74+
75+ { /* Content */ }
76+ < div className = "flex flex-col flex-grow p-5" >
77+ < div className = "flex items-center gap-2 mb-3" >
78+ < span className = "font-mono text-[9px] text-gray-500 uppercase tracking-widest flex items-center gap-1" >
79+ < CalendarBlank size = { 12 } />
80+ { date }
81+ </ span >
82+ < span className = "text-gray-700 text-[9px]" > •</ span >
83+ < span className = "font-mono text-[9px] text-gray-500 uppercase tracking-widest" >
84+ #{ String ( totalLogs - index ) . padStart ( 3 , '0' ) }
85+ </ span >
14286 </ div >
143- { /* Title */ }
144- < h3 className = "font-mono text-lg font-bold text-gray-100 mb-2 leading-snug group-hover:text-white transition-colors" >
87+
88+ < h3 className = "text-lg font-medium font-sans uppercase text-white mb-2 group-hover:text-emerald-400 transition-colors line-clamp-2 leading-tight " >
14589 { title }
14690 </ h3 >
147- { /* Metadata Grid */ }
148- < div className = "flex flex-wrap gap-2 mb-4" >
149- < MetadataItem
150- label = "By"
151- value = { by || author || artist || creator || director }
152- />
153- < MetadataItem label = "On" value = { platform || source } />
154- < MetadataItem
155- label = "Year"
156- value = { year || ( releaseDate ? releaseDate . split ( '-' ) [ 0 ] : null ) }
157- />
158- { album && < MetadataItem label = "Album" value = { album } /> }
91+
92+ < div className = "mb-4" >
93+ { creatorName && (
94+ < p className = "text-xs text-gray-400 font-mono truncate" > By { creatorName } </ p >
95+ ) }
96+ { sourceName && (
97+ < p className = "text-[10px] text-gray-600 font-mono truncate uppercase mt-1" > On { sourceName } </ p >
98+ ) }
15999 </ div >
160- { /* Spacer */ }
161- < div className = "flex-grow" />
162- { /* Footer: Rating & Date */ }
163- < div
164- className = { `flex items-end justify-between mt-4 pt-4 border-t` }
165- style = { { borderColor : `${ accentColor } 50` } }
166- >
167- < div className = "flex flex-col gap-1" >
168- { renderStars ( rating ) }
169- { rating > 0 && (
170- < span className = "text-xs text-gray-400 font-mono" >
171- ({ rating } /5)
172- </ span >
173- ) }
174- </ div >
175100
176- < div className = "text-right flex flex-col items-end" >
177- { updated && (
178- < span className = "text-[10px] text-rose-400 font-mono mb-0.5" >
179- Updated
180- </ span >
181- ) }
182- < div className = "flex items-center gap-1 text-xs text-gray-400 font-mono" >
183- < CalendarBlankIcon size = { 12 } />
184- { date }
185- </ div >
186- </ div >
101+ < div className = "mt-auto pt-4 flex items-center justify-between border-t border-white/5" >
102+ < span className = "text-[10px] font-mono font-bold uppercase tracking-widest text-gray-500 group-hover:text-white transition-colors" >
103+ View Log
104+ </ span >
105+ < ArrowRight weight = "bold" size = { 14 } className = "text-emerald-500 transform -translate-x-2 opacity-0 transition-all duration-300 group-hover:translate-x-0 group-hover:opacity-100" />
187106 </ div >
188107 </ div >
189- </ div >
190- </ Link >
108+ </ Link >
109+ </ motion . div >
191110 ) ;
192111} ;
193112
0 commit comments