Skip to content

Commit 3bb7ac8

Browse files
authored
Merge pull request #87 from bsychen/fix/tabbed-info
Fix/tabbed info
2 parents 6ec2067 + 7726eb9 commit 3bb7ac8

File tree

10 files changed

+293
-255
lines changed

10 files changed

+293
-255
lines changed

src/app/search/page.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,10 @@ const SearchResult = memo(({ product, onSelect }: { product: ProductSearchResult
5353
className="text-xs"
5454
style={{ color: colours.text.muted }}
5555
>
56-
ID: {product.id}
56+
<span className="font-semibold">
57+
{product.brandName}
58+
</span>
59+
5760
</div>
5861
</Link>
5962
);

src/components/CreatePostModal.tsx

Lines changed: 144 additions & 137 deletions
Large diffs are not rendered by default.

src/components/PriceSpectrum.tsx

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ import { colours } from '@/styles/colours';
66
const getPositionColor = (price: number, q1: number, q3: number) => {
77
if (price <= q1) {
88
return {
9-
bg: colours.status.success.background,
9+
bg: `${colours.status.success.border}80`, // Green with transparency
1010
border: colours.status.success.border,
11-
text: colours.status.success.text
11+
text: colours.button.success.text
1212
};
1313
} else if (price >= q3) {
1414
return {
@@ -51,13 +51,11 @@ const PriceSpectrum: React.FC<PriceSpectrumProps> = ({
5151
const getPrice = (p: Product) => p.price || p.expectedPrice || 0;
5252
const productPrice = getPrice(product);
5353

54-
// If no real prices available, use sample data
54+
// If no real prices available, show simple message
5555
if (productPrice === 0) {
5656
return (
57-
<div className="w-full h-24 flex items-center justify-center text-sm rounded-lg" style={{
58-
color: colours.text.muted,
59-
backgroundColor: colours.background.secondary,
60-
border: `1px solid ${colours.card.border}`
57+
<div className="w-full h-24 flex items-center justify-center text-sm" style={{
58+
color: colours.text.secondary
6159
}}>
6260
Price data unavailable
6361
</div>
@@ -125,40 +123,40 @@ const PriceSpectrum: React.FC<PriceSpectrumProps> = ({
125123
}}
126124
>
127125
{/* Product box with shadow and border */}
128-
<div className="rounded-md shadow-xl px-2 py-1 mb-1" style={{
126+
<div className="rounded-full shadow-lg px-2 py-1 mb-1 border-2 border-black" style={{
129127
backgroundColor: colors.bg,
130-
border: `1px solid ${colors.border}`
128+
borderColor: colors.border
131129
}}>
132130
<div className="text-xs font-medium whitespace-nowrap" style={{ color: colors.text }}>
133131
£{productPrice.toFixed(2)}
134132
</div>
135133
</div>
136134
{/* Triangle pointer */}
137135
<div
138-
className="w-0 h-0 border-l-[6px] shadow-xl border-l-transparent border-r-[6px] border-r-transparent border-t-[6px]"
136+
className="w-0 h-0 border-l-[5px] shadow-lg border-l-transparent border-r-[5px] border-r-transparent border-t-[5px]"
139137
style={{ borderTopColor: colors.border }}
140138
/>
141139
</div>
142140
{/* Price labels with buttons */}
143-
<div className="absolute -bottom-6 left-[0%]">
141+
<div className="absolute -bottom-4 left-[0%]">
144142
<button
145-
className="rounded-md shadow-xl px-2 py-1 text-xs font-medium transition-colors"
143+
className="rounded-full shadow-lg px-2 py-1 text-xs font-medium transition-colors border-2 border-dotted"
146144
style={{
147-
backgroundColor: colours.status.success.background,
148-
border: `2px solid ${colours.status.success.border}`,
149-
color: colours.status.success.text
145+
backgroundColor: `${colours.status.success.border}50`, // 30% opacity for transparency
146+
borderColor: colours.status.success.border,
147+
color: colours.button.success.text
150148
}}
151149
onClick={onMinClick}
152150
>
153151
£{priceStats.min.toFixed(2)}
154152
</button>
155153
</div>
156-
<div className="absolute -bottom-6 right-[0%]">
154+
<div className="absolute -bottom-4 right-[0%]">
157155
<button
158-
className="rounded-md shadow-xl px-2 py-1 text-xs font-medium transition-colors"
156+
className="rounded-full shadow-lg px-2 py-1 text-xs font-medium transition-colors border-2 border-dotted"
159157
style={{
160-
backgroundColor: colours.status.error.background,
161-
border: `2px solid ${colours.status.error.border}`,
158+
backgroundColor: `${colours.status.error.background}50`, // 30% opacity for transparency
159+
borderColor: colours.status.error.border,
162160
color: colours.status.error.text
163161
}}
164162
onClick={onMaxClick}

src/components/TabbedInfoBox.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -225,14 +225,14 @@ const TabbedInfoBox: React.FC<TabbedInfoBoxProps> = ({
225225
useEffect(() => {
226226
if (isCollapsed) {
227227
// When collapsed, only show the tabs height (no margin below)
228-
setBoxHeight(30); // Just the tab height without bottom margin
228+
setBoxHeight(28); // Just the tab height without bottom margin
229229
} else if (contentRef.current) {
230230
// When expanded, calculate content height
231231
const newHeight = contentRef.current.scrollHeight;
232232

233233
// Use requestAnimationFrame to ensure smooth height transition
234234
requestAnimationFrame(() => {
235-
setBoxHeight(newHeight + 50); // Add tab height
235+
setBoxHeight(newHeight + 40); // Add tab height
236236
});
237237
}
238238
}, [activeTab, product, reviewSummary, showMinProduct, showMaxProduct, isCollapsed, calculateBrandStats]);
@@ -271,19 +271,19 @@ const TabbedInfoBox: React.FC<TabbedInfoBoxProps> = ({
271271

272272
return (
273273
<div
274-
className="w-full max-w-xl mt-8 rounded-2xl shadow-lg border-2 border-black p-3 transition-colors duration-300"
274+
className="w-full max-w-xl mt-8 rounded-2xl shadow-lg border-2 border-black p-2 transition-colors duration-300"
275275
style={{
276276
backgroundColor: getCategoryBackground(),
277277
border: `2px solid ${colours.content.border}`,
278-
height: boxHeight ? boxHeight + 32 : undefined,
279-
minHeight: isCollapsed ? 40 : 280,
278+
height: boxHeight ? boxHeight + 24 : undefined,
279+
minHeight: isCollapsed ? 36 : 260,
280280
transition: "height 0.4s cubic-bezier(0.4,0,0.2,1), background-color 0.3s ease",
281281
position: "relative"
282282
}}
283283
>
284284
{/* Tab Headers */}
285285
<div
286-
className={`flex ${isCollapsed ? 'mb-0' : 'mb-4'} ${!isCollapsed ? 'border-b' : ''} justify-center gap-2 relative`}
286+
className={`flex ${isCollapsed ? 'mb-0' : 'mb-2'} ${!isCollapsed ? 'border-b' : ''} justify-center gap-2 relative`}
287287
style={{ borderColor: isCollapsed ? 'transparent' : colours.content.border }}
288288
>
289289
{/* Sliding Bar - only show when expanded */}
@@ -327,7 +327,7 @@ const TabbedInfoBox: React.FC<TabbedInfoBoxProps> = ({
327327
{!isCollapsed && (
328328
<div
329329
ref={contentRef}
330-
className="relative px-4 pb-4"
330+
className="relative px-3 pb-3"
331331
style={{
332332
opacity: 1,
333333
transition: 'opacity 0.2s ease-in-out, height 0.3s ease-in-out'

src/components/tabs/BrandTabContent.tsx

Lines changed: 62 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import React from "react";
2+
import Image from "next/image";
23
import { Product } from "@/types/product";
34
import { colours } from "@/styles/colours";
45

@@ -134,41 +135,71 @@ const BrandTabContent: React.FC<BrandTabContentProps> = ({
134135
<div className="w-full">
135136
<div className="space-y-3">
136137
{[
137-
{ label: 'Price', value: calculateBrandStats.price, color: '#ECCC36' },
138-
{ label: 'Quality', value: calculateBrandStats.quality, color: '#D24330' },
139-
{ label: 'Nutrition', value: calculateBrandStats.nutrition, color: '#3b82f6' },
140-
{ label: 'Sustainability', value: calculateBrandStats.sustainability, color: '#309563' }
141-
].map((stat, index) => (
142-
<div key={stat.label} className="flex items-center gap-3">
143-
<span
144-
className="text-xs font-medium w-20 text-right"
145-
style={{ color: colours.text.secondary }}
146-
>
147-
{stat.label}
148-
</span>
149-
<div className="flex-1 max-w-24">
150-
<div
151-
className="flex items-center h-4 rounded-full overflow-hidden"
152-
style={{ backgroundColor: colours.content.surfaceSecondary }}
153-
>
154-
<div
155-
className="h-full rounded-full transition-all duration-1000 ease-out opacity-0 animate-fade-in"
138+
{
139+
label: 'Price',
140+
value: calculateBrandStats.price,
141+
color: '#fef3c7', // yellow-100
142+
svg: '/pound-svgrepo-com.svg'
143+
},
144+
{
145+
label: 'Quality',
146+
value: calculateBrandStats.quality,
147+
color: '#fee2e2', // red-100
148+
svg: '/quality-supervision-svgrepo-com.svg'
149+
},
150+
{
151+
label: 'Nutrition',
152+
value: calculateBrandStats.nutrition,
153+
color: '#dbeafe', // blue-100
154+
svg: '/meal-svgrepo-com.svg'
155+
},
156+
{
157+
label: 'Sustainability',
158+
value: calculateBrandStats.sustainability,
159+
color: '#ecfccb', // lime-100
160+
svg: '/leaf-svgrepo-com.svg'
161+
}
162+
].map((stat, index) => {
163+
const percentage = ((stat.value - 1) / 4) * 100;
164+
return (
165+
<div key={stat.label} className="flex items-center gap-3">
166+
<Image
167+
src={stat.svg}
168+
alt={stat.label}
169+
width={16}
170+
height={16}
171+
className="flex-shrink-0"
172+
style={{ color: colours.text.secondary }}
173+
/>
174+
<div className="flex-1">
175+
<div
176+
className="relative rounded-lg overflow-hidden"
156177
style={{
157-
width: `${(stat.value / 5) * 100}%`,
158-
backgroundColor: stat.color,
159-
animationDelay: `${0.3 + index * 0.1}s`
178+
backgroundColor: colours.bargraph.background,
179+
border: `2px dotted ${colours.card.border}30`,
180+
height: '28px',
160181
}}
161-
/>
182+
>
183+
<div
184+
className="transition-all duration-1000 ease-out absolute inset-0 rounded-lg opacity-0 animate-fade-in"
185+
style={{
186+
width: `${percentage}%`,
187+
backgroundColor: stat.color,
188+
border: `2px solid ${colours.card.border}`,
189+
animationDelay: `${0.3 + index * 0.1}s`
190+
}}
191+
/>
192+
</div>
162193
</div>
194+
<span
195+
className="text-xs font-medium w-8 text-right flex-shrink-0"
196+
style={{ color: colours.text.primary }}
197+
>
198+
{stat.value.toFixed(1)}
199+
</span>
163200
</div>
164-
<span
165-
className="text-xs font-medium w-8"
166-
style={{ color: colours.text.primary }}
167-
>
168-
{stat.value.toFixed(1)}
169-
</span>
170-
</div>
171-
))}
201+
);
202+
})}
172203
</div>
173204
<div
174205
className="text-xs mt-3 text-center"

src/components/tabs/NutritionTabContent.tsx

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,15 @@ const NutritionTabContent: React.FC<NutritionTabContentProps> = ({
4949
borderColor: (() => {
5050
const score = animatedNutrition;
5151
const grade = product.combinedNutritionGrade;
52-
if (!grade) return colours.text.muted; // Grey for missing nutriscore
52+
if (!grade || grade === 'unknown') return colours.text.muted; // Grey for missing/unknown nutriscore
5353
if (score <= 2) return colours.score.low;
5454
if (score <= 3) return colours.score.medium;
5555
return colours.score.high;
5656
})(),
5757
backgroundColor: (() => {
5858
const score = animatedNutrition;
5959
const grade = product.combinedNutritionGrade;
60-
if (!grade) return colours.text.muted + '20'; // Grey for missing nutriscore
60+
if (!grade || grade === 'unknown') return colours.text.muted + '20'; // Grey for missing/unknown nutriscore
6161
if (score <= 2) return colours.score.low + '20'; // 20% opacity
6262
if (score <= 3) return colours.score.medium + '20';
6363
return colours.score.high + '20';
@@ -72,14 +72,18 @@ const NutritionTabContent: React.FC<NutritionTabContentProps> = ({
7272
stroke={(() => {
7373
const score = animatedNutrition;
7474
const grade = product.combinedNutritionGrade;
75-
if (!grade) return colours.text.muted; // Grey for missing nutriscore
75+
if (!grade || grade === 'unknown') return colours.text.muted; // Grey for missing/unknown nutriscore
7676
if (score <= 2) return colours.score.low;
7777
if (score <= 3) return colours.score.medium;
7878
return colours.score.high;
7979
})()}
8080
strokeWidth="3"
8181
strokeDasharray={Math.PI * 2 * 18}
82-
strokeDashoffset={Math.PI * 2 * 18 * (1 - (animatedNutrition / 5))}
82+
strokeDashoffset={Math.PI * 2 * 18 * (1 - (() => {
83+
const grade = product.combinedNutritionGrade;
84+
if (!grade || grade === 'unknown') return 0; // No fill for missing/unknown nutriscore
85+
return animatedNutrition / 5;
86+
})())}
8387
strokeLinecap="round"
8488
style={{
8589
transition: 'stroke-dashoffset 0.7s cubic-bezier(0.4,0,0.2,1), stroke 0.7s cubic-bezier(0.4,0,0.2,1)',
@@ -95,14 +99,18 @@ const NutritionTabContent: React.FC<NutritionTabContentProps> = ({
9599
color: (() => {
96100
const score = animatedNutrition;
97101
const grade = product.combinedNutritionGrade;
98-
if (!grade) return colours.text.muted; // Grey for missing nutriscore
102+
if (!grade || grade === 'unknown') return colours.text.muted; // Grey for missing/unknown nutriscore
99103
if (score <= 2) return colours.score.low;
100104
if (score <= 3) return colours.score.medium;
101105
return colours.score.high;
102106
})()
103107
}}
104108
>
105-
{product.combinedNutritionGrade?.toUpperCase() || '--'}
109+
{(() => {
110+
const grade = product.combinedNutritionGrade;
111+
if (!grade || grade === 'unknown') return '--';
112+
return grade.toUpperCase();
113+
})()}
106114
</span>
107115
</div>
108116
</span>

src/components/tabs/PriceTabContent.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,14 @@ const PriceTabContent: React.FC<PriceTabContentProps> = ({
4545
>
4646
Price Range
4747
</h2>
48-
<div className="w-full opacity-0 animate-slide-in-bottom" style={{ animationDelay: '0.15s' }}>
48+
<div
49+
className="w-full p-4 sm:p-5 rounded-xl border-2 mb-4 opacity-0 animate-slide-in-bottom"
50+
style={{
51+
animationDelay: '0.15s',
52+
backgroundColor: '#f1f5fb', // baby blue
53+
borderColor: colours.content.border
54+
}}
55+
>
4956
<PriceSpectrum
5057
product={product}
5158
priceStats={priceStats}

src/components/tabs/QualityTabContent.tsx

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,13 @@ const QualityTabContent: React.FC<QualityTabContentProps> = ({
3434
className="text-lg font-medium"
3535
style={{ color: colours.text.primary }}
3636
>
37-
Quality Score
37+
Average Score
3838
</span>
3939
<span
4040
className="text-[10px]"
4141
style={{ color: colours.text.muted }}
4242
>
43-
Based on user reviews and ratings
43+
Based on user review ratings
4444
</span>
4545
</div>
4646
<div className="flex-shrink-0">
@@ -124,17 +124,12 @@ const QualityTabContent: React.FC<QualityTabContentProps> = ({
124124
{count}
125125
</span>
126126
<div
127-
className="rounded w-6 transition-all duration-700 animate-bar-grow"
127+
className="rounded w-6 transition-all duration-700 animate-bar-grow border-2"
128128
style={{
129129
height: `${height}px`,
130130
transition: 'height 0.7s cubic-bezier(0.4,0,0.2,1), background-color 0.3s ease',
131-
backgroundColor: colours.score.medium
132-
}}
133-
onMouseEnter={(e) => {
134-
e.currentTarget.style.backgroundColor = colours.score.high
135-
}}
136-
onMouseLeave={(e) => {
137-
e.currentTarget.style.backgroundColor = colours.score.medium
131+
backgroundColor: colours.status.warning.background + '80', // 80% opacity like filled stars
132+
borderColor: colours.status.warning.background,
138133
}}
139134
/>
140135
<span

0 commit comments

Comments
 (0)