feat: modernize search filters & intelligent label shortening
- Introduced shortenCategory utility to strip redundant terms from labels - Refactored BottleGrid filters into a compact, collapsible layout - Added filter count indicator and improved chip styling - Fully localized new filter UI elements
This commit is contained in:
@@ -7,6 +7,7 @@ import { getStorageUrl } from '@/lib/supabase';
|
|||||||
import { useSearchParams } from 'next/navigation';
|
import { useSearchParams } from 'next/navigation';
|
||||||
import { validateSession } from '@/services/validate-session';
|
import { validateSession } from '@/services/validate-session';
|
||||||
import { useI18n } from '@/i18n/I18nContext';
|
import { useI18n } from '@/i18n/I18nContext';
|
||||||
|
import { shortenCategory } from '@/lib/format';
|
||||||
|
|
||||||
interface Bottle {
|
interface Bottle {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -94,7 +95,7 @@ function BottleCard({ bottle, sessionId }: BottleCardProps) {
|
|||||||
|
|
||||||
<div className="flex flex-wrap gap-1.5 md:gap-2">
|
<div className="flex flex-wrap gap-1.5 md:gap-2">
|
||||||
<span className="px-2 py-0.5 md:px-2.5 md:py-1 bg-zinc-100 dark:bg-zinc-800 text-zinc-600 dark:text-zinc-400 text-[9px] md:text-[10px] font-black uppercase tracking-widest rounded-lg border border-zinc-200/50 dark:border-zinc-700/50">
|
<span className="px-2 py-0.5 md:px-2.5 md:py-1 bg-zinc-100 dark:bg-zinc-800 text-zinc-600 dark:text-zinc-400 text-[9px] md:text-[10px] font-black uppercase tracking-widest rounded-lg border border-zinc-200/50 dark:border-zinc-700/50">
|
||||||
{bottle.category}
|
{shortenCategory(bottle.category)}
|
||||||
</span>
|
</span>
|
||||||
<span className="px-2 py-0.5 md:px-2.5 md:py-1 bg-amber-50 dark:bg-amber-900/20 text-amber-700 dark:text-amber-400 text-[9px] md:text-[10px] font-black uppercase tracking-widest rounded-lg border border-amber-200/50 dark:border-amber-800/20">
|
<span className="px-2 py-0.5 md:px-2.5 md:py-1 bg-amber-50 dark:bg-amber-900/20 text-amber-700 dark:text-amber-400 text-[9px] md:text-[10px] font-black uppercase tracking-widest rounded-lg border border-amber-200/50 dark:border-amber-800/20">
|
||||||
{bottle.abv}% VOL
|
{bottle.abv}% VOL
|
||||||
@@ -188,6 +189,8 @@ export default function BottleGrid({ bottles }: BottleGridProps) {
|
|||||||
});
|
});
|
||||||
}, [bottles, searchQuery, selectedCategory, selectedDistillery, selectedStatus, sortBy]);
|
}, [bottles, searchQuery, selectedCategory, selectedDistillery, selectedStatus, sortBy]);
|
||||||
|
|
||||||
|
const [isFiltersOpen, setIsFiltersOpen] = useState(false);
|
||||||
|
|
||||||
if (!bottles || bottles.length === 0) {
|
if (!bottles || bottles.length === 0) {
|
||||||
return (
|
return (
|
||||||
<div className="text-center py-12 p-8 bg-zinc-50 dark:bg-zinc-900/50 rounded-3xl border-2 border-dashed border-zinc-200 dark:border-zinc-800">
|
<div className="text-center py-12 p-8 bg-zinc-50 dark:bg-zinc-900/50 rounded-3xl border-2 border-dashed border-zinc-200 dark:border-zinc-800">
|
||||||
@@ -196,117 +199,157 @@ export default function BottleGrid({ bottles }: BottleGridProps) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const activeFiltersCount = (selectedCategory ? 1 : 0) + (selectedDistillery ? 1 : 0) + (selectedStatus ? 1 : 0);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full space-y-8">
|
<div className="w-full space-y-8">
|
||||||
{/* Search and Filters */}
|
{/* Search and Filters */}
|
||||||
<div className="w-full max-w-6xl mx-auto px-4 space-y-6">
|
<div className="w-full max-w-6xl mx-auto px-4 space-y-4">
|
||||||
<div className="flex flex-col md:flex-row gap-4">
|
<div className="flex flex-col md:flex-row gap-3">
|
||||||
<div className="relative flex-1">
|
<div className="relative flex-1 group">
|
||||||
<Search className="absolute left-3 top-1/2 -translate-y-1/2 text-zinc-400" size={18} />
|
<Search className="absolute left-4 top-1/2 -translate-y-1/2 text-zinc-400 group-focus-within:text-amber-600 transition-colors" size={18} />
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder={t('grid.searchPlaceholder')}
|
placeholder={t('grid.searchPlaceholder')}
|
||||||
value={searchQuery}
|
value={searchQuery}
|
||||||
onChange={(e) => setSearchQuery(e.target.value)}
|
onChange={(e) => setSearchQuery(e.target.value)}
|
||||||
className="w-full pl-10 pr-4 py-3 bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-xl focus:ring-2 focus:ring-amber-500 outline-none transition-all"
|
className="w-full pl-12 pr-12 py-3.5 bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-[1.25rem] focus:ring-2 focus:ring-amber-500/20 focus:border-amber-500/50 outline-none transition-all shadow-sm"
|
||||||
/>
|
/>
|
||||||
{searchQuery && (
|
{searchQuery && (
|
||||||
<button
|
<button
|
||||||
onClick={() => setSearchQuery('')}
|
onClick={() => setSearchQuery('')}
|
||||||
className="absolute right-3 top-1/2 -translate-y-1/2 text-zinc-400 hover:text-zinc-600"
|
className="absolute right-4 top-1/2 -translate-y-1/2 text-zinc-400 hover:text-amber-600 transition-colors"
|
||||||
>
|
>
|
||||||
<X size={16} />
|
<X size={18} />
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<select
|
<div className="flex gap-3">
|
||||||
value={sortBy}
|
<select
|
||||||
onChange={(e) => setSortBy(e.target.value as any)}
|
value={sortBy}
|
||||||
className="px-4 py-3 bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-xl text-sm font-medium focus:ring-2 focus:ring-amber-500 outline-none cursor-pointer"
|
onChange={(e) => setSortBy(e.target.value as any)}
|
||||||
|
className="flex-1 md:flex-none px-4 py-3.5 bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-[1.25rem] text-sm font-bold focus:ring-2 focus:ring-amber-500/20 outline-none cursor-pointer appearance-none text-zinc-700 dark:text-zinc-300 shadow-sm"
|
||||||
|
>
|
||||||
|
<option value="created_at">{t('grid.sortBy.createdAt')}</option>
|
||||||
|
<option value="last_tasted">{t('grid.sortBy.lastTasted')}</option>
|
||||||
|
<option value="name">{t('grid.sortBy.name')}</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={() => setIsFiltersOpen(!isFiltersOpen)}
|
||||||
|
className={`px-5 py-3.5 rounded-[1.25rem] text-sm font-bold flex items-center gap-2 transition-all border shadow-sm ${isFiltersOpen || activeFiltersCount > 0
|
||||||
|
? 'bg-amber-600 border-amber-600 text-white'
|
||||||
|
: 'bg-white dark:bg-zinc-900 border-zinc-200 dark:border-zinc-800 text-zinc-700 dark:text-zinc-300'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<Filter size={18} />
|
||||||
|
<span className="hidden sm:inline">{t('grid.filters')}</span>
|
||||||
|
{activeFiltersCount > 0 && (
|
||||||
|
<span className="bg-white text-amber-600 w-5 h-5 rounded-full flex items-center justify-center text-[10px] font-black">
|
||||||
|
{activeFiltersCount}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Category Quick Filter (Always visible row) */}
|
||||||
|
<div className="flex gap-2 overflow-x-auto pb-2 -mx-4 px-4 scrollbar-hide touch-pan-x">
|
||||||
|
<button
|
||||||
|
onClick={() => setSelectedCategory(null)}
|
||||||
|
className={`px-4 py-2 rounded-xl text-xs font-black whitespace-nowrap transition-all border ${selectedCategory === null
|
||||||
|
? 'bg-zinc-900 dark:bg-white text-white dark:text-zinc-900 border-zinc-900 dark:border-white'
|
||||||
|
: 'bg-white dark:bg-zinc-900 border-zinc-200 dark:border-zinc-800 text-zinc-500 hover:border-zinc-300'
|
||||||
|
}`}
|
||||||
>
|
>
|
||||||
<option value="created_at">{t('grid.sortBy.createdAt')}</option>
|
{t('common.all').toUpperCase()}
|
||||||
<option value="last_tasted">{t('grid.sortBy.lastTasted')}</option>
|
</button>
|
||||||
<option value="name">{t('grid.sortBy.name')}</option>
|
{categories.map((cat) => (
|
||||||
</select>
|
<button
|
||||||
|
key={cat}
|
||||||
|
onClick={() => setSelectedCategory(selectedCategory === cat ? null : cat)}
|
||||||
|
className={`px-4 py-2 rounded-xl text-xs font-black whitespace-nowrap transition-all border ${selectedCategory === cat
|
||||||
|
? 'bg-amber-600 border-amber-600 text-white shadow-lg shadow-amber-600/20'
|
||||||
|
: 'bg-white dark:bg-zinc-900 border-zinc-200 dark:border-zinc-800 text-zinc-500 hover:border-zinc-300'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{shortenCategory(cat).toUpperCase()}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-6">
|
{/* Collapsible Advanced Filters */}
|
||||||
{/* Category Filter */}
|
{isFiltersOpen && (
|
||||||
<div className="flex flex-col gap-2">
|
<div className="p-6 bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-[2rem] space-y-6 shadow-xl animate-in fade-in slide-in-from-top-4 duration-300">
|
||||||
<span className="text-[10px] font-black uppercase tracking-widest text-zinc-400 px-1">{t('grid.filter.category')}</span>
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||||
<div className="flex gap-2 overflow-x-auto -mx-4 px-4 pb-2 scrollbar-hide touch-pan-x">
|
<div className="space-y-3">
|
||||||
<button
|
<label className="text-[10px] font-black uppercase tracking-[0.2em] text-zinc-400 px-1">{t('grid.filter.distillery')}</label>
|
||||||
onClick={() => setSelectedCategory(null)}
|
<div className="flex flex-wrap gap-2">
|
||||||
className={`px-3 py-1.5 md:px-4 md:py-2 rounded-xl text-[10px] md:text-xs font-bold whitespace-nowrap transition-all border ${selectedCategory === null
|
<button
|
||||||
? 'bg-amber-600 border-amber-600 text-white shadow-lg shadow-amber-600/20'
|
onClick={() => setSelectedDistillery(null)}
|
||||||
: 'bg-white dark:bg-zinc-900 border-zinc-200 dark:border-zinc-800 text-zinc-600 dark:text-zinc-400'
|
className={`px-3 py-1.5 rounded-xl text-[10px] font-black transition-all border ${selectedDistillery === null
|
||||||
}`}
|
? 'bg-zinc-900 dark:bg-white text-white dark:text-zinc-900'
|
||||||
>
|
: 'bg-zinc-50 dark:bg-zinc-800 border-zinc-200 dark:border-zinc-700 text-zinc-500'
|
||||||
{t('common.all').toUpperCase()}
|
}`}
|
||||||
</button>
|
>
|
||||||
{categories.map((cat) => (
|
{t('common.all').toUpperCase()}
|
||||||
<button
|
</button>
|
||||||
key={cat}
|
{distilleries.map((dist) => (
|
||||||
onClick={() => setSelectedCategory(cat)}
|
<button
|
||||||
className={`px-3 py-1.5 md:px-4 md:py-2 rounded-xl text-[10px] md:text-xs font-bold whitespace-nowrap transition-all border ${selectedCategory === cat
|
key={dist}
|
||||||
? 'bg-amber-600 border-amber-600 text-white shadow-lg shadow-amber-600/20'
|
onClick={() => setSelectedDistillery(selectedDistillery === dist ? null : dist)}
|
||||||
: 'bg-white dark:bg-zinc-900 border-zinc-200 dark:border-zinc-800 text-zinc-600 dark:text-zinc-400'
|
className={`px-3 py-1.5 rounded-xl text-[10px] font-black transition-all border ${selectedDistillery === dist
|
||||||
}`}
|
? 'bg-amber-600 border-amber-600 text-white'
|
||||||
>
|
: 'bg-zinc-50 dark:bg-zinc-800 border-zinc-200 dark:border-zinc-700 text-zinc-500'
|
||||||
{cat.toUpperCase()}
|
}`}
|
||||||
</button>
|
>
|
||||||
))}
|
{dist.toUpperCase()}
|
||||||
</div>
|
</button>
|
||||||
</div>
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Distillery Filter */}
|
<div className="space-y-3">
|
||||||
<div className="flex flex-col gap-2">
|
<label className="text-[10px] font-black uppercase tracking-[0.2em] text-zinc-400 px-1">{t('grid.filter.status')}</label>
|
||||||
<span className="text-[10px] font-black uppercase tracking-widest text-zinc-400 px-1">{t('grid.filter.distillery')}</span>
|
<div className="flex flex-wrap gap-2">
|
||||||
<div className="flex gap-2 overflow-x-auto -mx-4 px-4 pb-2 scrollbar-hide touch-pan-x">
|
{['sealed', 'open', 'sampled', 'empty'].map((status) => (
|
||||||
<button
|
<button
|
||||||
onClick={() => setSelectedDistillery(null)}
|
key={status}
|
||||||
className={`px-3 py-1.5 md:px-4 md:py-2 rounded-xl text-[10px] md:text-xs font-bold whitespace-nowrap transition-all border ${selectedDistillery === null
|
onClick={() => setSelectedStatus(selectedStatus === status ? null : status)}
|
||||||
? 'bg-zinc-900 dark:bg-white text-white dark:text-zinc-900 border-zinc-900 dark:border-white'
|
className={`px-3 py-1.5 rounded-xl text-[10px] font-black transition-all border ${selectedStatus === status
|
||||||
: 'bg-white dark:bg-zinc-900 border-zinc-200 dark:border-zinc-800 text-zinc-600 dark:text-zinc-400'
|
? status === 'open' ? 'bg-amber-500 border-amber-500 text-white' : status === 'sampled' ? 'bg-purple-500 border-purple-500 text-white' : status === 'empty' ? 'bg-zinc-500 border-zinc-500 text-white' : 'bg-blue-600 border-blue-600 text-white'
|
||||||
}`}
|
: 'bg-zinc-50 dark:bg-zinc-800 border-zinc-200 dark:border-zinc-700 text-zinc-500'
|
||||||
>
|
}`}
|
||||||
{t('common.all').toUpperCase()}
|
>
|
||||||
</button>
|
{t(`bottle.status.${status}`).toUpperCase()}
|
||||||
{distilleries.map((dist) => (
|
</button>
|
||||||
<button
|
))}
|
||||||
key={dist}
|
</div>
|
||||||
onClick={() => setSelectedDistillery(dist)}
|
</div>
|
||||||
className={`px-3 py-1.5 md:px-4 md:py-2 rounded-xl text-[10px] md:text-xs font-bold whitespace-nowrap transition-all border ${selectedDistillery === dist
|
|
||||||
? 'bg-zinc-900 dark:bg-white text-white dark:text-zinc-900 border-zinc-900 dark:border-white'
|
|
||||||
: 'bg-white dark:bg-zinc-900 border-zinc-200 dark:border-zinc-800 text-zinc-600 dark:text-zinc-400'
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{dist.toUpperCase()}
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Status Filter */}
|
<div className="pt-4 border-t border-zinc-100 dark:border-zinc-800 flex justify-between items-center">
|
||||||
<div className="flex flex-col gap-2">
|
<button
|
||||||
<span className="text-[10px] font-black uppercase tracking-widest text-zinc-400 px-1">{t('grid.filter.status')}</span>
|
onClick={() => {
|
||||||
<div className="flex gap-2 overflow-x-auto -mx-4 px-4 pb-2 scrollbar-hide touch-pan-x">
|
setSelectedCategory(null);
|
||||||
{['sealed', 'open', 'sampled', 'empty'].map((status) => (
|
setSelectedDistillery(null);
|
||||||
<button
|
setSelectedStatus(null);
|
||||||
key={status}
|
setSearchQuery('');
|
||||||
onClick={() => setSelectedStatus(selectedStatus === status ? null : status)}
|
}}
|
||||||
className={`px-3 py-1.5 md:px-4 md:py-2 rounded-xl text-[10px] md:text-xs font-bold whitespace-nowrap transition-all border ${selectedStatus === status
|
className="text-[10px] font-black text-red-500 uppercase tracking-widest hover:underline"
|
||||||
? status === 'open' ? 'bg-amber-500 border-amber-500 text-white' : status === 'sampled' ? 'bg-purple-500 border-purple-500 text-white' : status === 'empty' ? 'bg-zinc-500 border-zinc-500 text-white' : 'bg-blue-600 border-blue-600 text-white'
|
>
|
||||||
: 'bg-white dark:bg-zinc-900 border-zinc-200 dark:border-zinc-800 text-zinc-600 dark:text-zinc-400'
|
{t('grid.resetAll')}
|
||||||
}`}
|
</button>
|
||||||
>
|
<button
|
||||||
{t(`bottle.status.${status}`).toUpperCase()}
|
onClick={() => setIsFiltersOpen(false)}
|
||||||
</button>
|
className="px-6 py-2 bg-zinc-900 dark:bg-white text-white dark:text-zinc-900 text-[10px] font-black rounded-xl uppercase tracking-widest transition-transform active:scale-95"
|
||||||
))}
|
>
|
||||||
|
{t('grid.close')}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Grid */}
|
{/* Grid */}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { discoverWhiskybaseId } from '@/services/discover-whiskybase';
|
|||||||
import { updateBottle } from '@/services/update-bottle';
|
import { updateBottle } from '@/services/update-bottle';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { useI18n } from '@/i18n/I18nContext';
|
import { useI18n } from '@/i18n/I18nContext';
|
||||||
|
import { shortenCategory } from '@/lib/format';
|
||||||
|
|
||||||
interface CameraCaptureProps {
|
interface CameraCaptureProps {
|
||||||
onImageCaptured?: (base64Image: string) => void;
|
onImageCaptured?: (base64Image: string) => void;
|
||||||
@@ -457,7 +458,7 @@ export default function CameraCapture({ onImageCaptured, onAnalysisComplete, onS
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex justify-between text-sm">
|
<div className="flex justify-between text-sm">
|
||||||
<span className="text-zinc-500">{t('bottle.categoryLabel')}:</span>
|
<span className="text-zinc-500">{t('bottle.categoryLabel')}:</span>
|
||||||
<span className="font-semibold">{analysisResult.category || '-'}</span>
|
<span className="font-semibold">{shortenCategory(analysisResult.category || '-')}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-between text-sm">
|
<div className="flex justify-between text-sm">
|
||||||
<span className="text-zinc-500">{t('bottle.abvLabel')}:</span>
|
<span className="text-zinc-500">{t('bottle.abvLabel')}:</span>
|
||||||
|
|||||||
@@ -58,6 +58,9 @@ export const de: TranslationKeys = {
|
|||||||
addedOn: 'Hinzugefügt am',
|
addedOn: 'Hinzugefügt am',
|
||||||
reviewRequired: 'REVIEW',
|
reviewRequired: 'REVIEW',
|
||||||
unknownBottle: 'Unbekannte Flasche',
|
unknownBottle: 'Unbekannte Flasche',
|
||||||
|
filters: 'Filter',
|
||||||
|
resetAll: 'Alle Filter zurücksetzen',
|
||||||
|
close: 'Schließen',
|
||||||
},
|
},
|
||||||
bottle: {
|
bottle: {
|
||||||
details: 'Details',
|
details: 'Details',
|
||||||
|
|||||||
@@ -58,6 +58,9 @@ export const en: TranslationKeys = {
|
|||||||
addedOn: 'Added on',
|
addedOn: 'Added on',
|
||||||
reviewRequired: 'REVIEW',
|
reviewRequired: 'REVIEW',
|
||||||
unknownBottle: 'Unknown Bottle',
|
unknownBottle: 'Unknown Bottle',
|
||||||
|
filters: 'Filters',
|
||||||
|
resetAll: 'Reset all filters',
|
||||||
|
close: 'Close',
|
||||||
},
|
},
|
||||||
bottle: {
|
bottle: {
|
||||||
details: 'Details',
|
details: 'Details',
|
||||||
|
|||||||
@@ -56,6 +56,9 @@ export type TranslationKeys = {
|
|||||||
addedOn: string;
|
addedOn: string;
|
||||||
reviewRequired: string;
|
reviewRequired: string;
|
||||||
unknownBottle: string;
|
unknownBottle: string;
|
||||||
|
filters: string;
|
||||||
|
resetAll: string;
|
||||||
|
close: string;
|
||||||
};
|
};
|
||||||
bottle: {
|
bottle: {
|
||||||
details: string;
|
details: string;
|
||||||
|
|||||||
33
src/lib/format.ts
Normal file
33
src/lib/format.ts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/**
|
||||||
|
* Shortens a whisky category label by removing redundant common terms.
|
||||||
|
* Example: "Single Malt Scotch Whisky" -> "Single Malt"
|
||||||
|
*/
|
||||||
|
export const shortenCategory = (label: string): string => {
|
||||||
|
if (!label) return '';
|
||||||
|
|
||||||
|
const replacements: [string, string][] = [
|
||||||
|
['Single Malt Scotch Whisky', 'Single Malt'],
|
||||||
|
['Blended Malt Scotch Whisky', 'Blended Malt'],
|
||||||
|
['Single Grain Scotch Whisky', 'Single Grain'],
|
||||||
|
['Blended Scotch Whisky', 'Blended'],
|
||||||
|
['Kentucky Straight Bourbon Whiskey', 'Bourbon'],
|
||||||
|
['Straight Bourbon Whiskey', 'Bourbon'],
|
||||||
|
['Tennessee Whiskey', 'Tennessee'],
|
||||||
|
['Japanese Whisky', 'Japanese'],
|
||||||
|
['Irish Whiskey', 'Irish'],
|
||||||
|
['Canadian Whisky', 'Canadian'],
|
||||||
|
['American Whiskey', 'American'],
|
||||||
|
['Rye Whiskey', 'Rye'],
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const [full, short] of replacements) {
|
||||||
|
if (label === full) return short;
|
||||||
|
}
|
||||||
|
|
||||||
|
return label
|
||||||
|
.replace(/ Scotch Whisky/gi, '')
|
||||||
|
.replace(/ Scotch/gi, '')
|
||||||
|
.replace(/ Whisky/gi, '')
|
||||||
|
.replace(/ Whiskey/gi, '')
|
||||||
|
.trim();
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user