diff --git a/src/app/features/admin/products/components/admin-product-form.component.html b/src/app/features/admin/products/components/admin-product-form.component.html index 7131bda..43935d0 100644 --- a/src/app/features/admin/products/components/admin-product-form.component.html +++ b/src/app/features/admin/products/components/admin-product-form.component.html @@ -231,8 +231,30 @@ - - + +
+ @if (product.badges.length > 0) { +
+ @for (badge of product.badges; track badge) { + + {{ badge }} + + + } +
+ } +
+ @for (known of knownBadges; track known) { + @if (!product.badges.includes(known)) { + + } + } +
+
+ + {{ 'adminProducts.addBadge' | translate }} +
+
} diff --git a/src/app/features/admin/products/components/admin-product-form.component.scss b/src/app/features/admin/products/components/admin-product-form.component.scss index e590eab..d0b9f17 100644 --- a/src/app/features/admin/products/components/admin-product-form.component.scss +++ b/src/app/features/admin/products/components/admin-product-form.component.scss @@ -105,3 +105,18 @@ input[type='checkbox'] { width: auto; } color: var(--text-secondary, #6b7280); font-size: 0.85rem; } +.badge-manager { display: grid; gap: 10px; } +.badge-manager__current, .badge-manager__known { display: flex; flex-wrap: wrap; gap: 6px; } +.badge-chip { + display: inline-flex; align-items: center; gap: 4px; + min-height: 24px; padding: 3px 10px; border-radius: 999px; + color: #fff; font-size: 0.75rem; font-weight: 700; text-transform: uppercase; + border: none; +} +.badge-chip--add { cursor: pointer; opacity: 0.55; &:hover { opacity: 1; } &:focus-visible { outline: 2px solid var(--color-primary, #2f8f5b); outline-offset: 2px; opacity: 1; } } +.badge-chip__remove { + border: none; background: transparent; color: inherit; cursor: pointer; + font-size: 0.9rem; line-height: 1; padding: 0 0 0 2px; + &:focus-visible { outline: 2px solid #fff; outline-offset: 1px; } +} +.badge-manager__custom { display: flex; gap: 8px; align-items: center; app-input { flex: 1; max-width: 260px; } } diff --git a/src/app/features/admin/products/components/admin-product-form.component.ts b/src/app/features/admin/products/components/admin-product-form.component.ts index 5dc6d21..392726e 100644 --- a/src/app/features/admin/products/components/admin-product-form.component.ts +++ b/src/app/features/admin/products/components/admin-product-form.component.ts @@ -140,8 +140,34 @@ export class AdminProductFormComponent { }); } - updateBadges(value: string): void { - this.productChange.emit({ badges: value.split(',').map(item => item.trim()).filter(Boolean) }); + /** Storefront badge vocabulary from getBadgeClass (item.utils.ts) - same colors the customer sees. */ + readonly knownBadges = ['new', 'sale', 'exclusive', 'hot', 'limited', 'bestseller', 'featured']; + private readonly badgeColors: Record = { + new: '#4caf50', sale: '#f44336', exclusive: '#9c27b0', hot: '#ff5722', + limited: '#ff9800', bestseller: '#2196f3', featured: '#607d8b', + }; + + customBadge = ''; + + badgeColor(badge: string): string { + return this.badgeColors[badge.toLowerCase()] ?? '#78909c'; + } + + addBadge(badge: string): void { + const value = badge.trim(); + if (!value || this.product.badges.includes(value)) { + return; + } + this.productChange.emit({ badges: [...this.product.badges, value] }); + } + + addCustomBadge(): void { + this.addBadge(this.customBadge); + this.customBadge = ''; + } + + removeBadge(badge: string): void { + this.productChange.emit({ badges: this.product.badges.filter(item => item !== badge) }); } readonly createSpecRow = () => ({ key: '', value: '' }); diff --git a/src/app/i18n/en.ts b/src/app/i18n/en.ts index 166ebba..347ab34 100644 --- a/src/app/i18n/en.ts +++ b/src/app/i18n/en.ts @@ -1546,6 +1546,10 @@ export const en: Translations = { seoGenerate: 'Fill from product details', seoGenerateHint: 'Fills empty fields from the product name and short description. Your existing text is kept.', translationsHint: 'The main fields above are shown in your default store language. Add translations here for other languages - if a translation is empty, customers see the default text instead.', + badgesHint: 'Badges are the small colored labels customers see on the product photo. Pick from the standard set or add your own.', + addBadge: 'Add', + removeBadge: 'Remove badge', + customBadgePlaceholder: 'Your own badge text…', seoExplain: 'This is what shows up in search results — a clear title and description help customers find this product.', searchTitle: 'Search title', searchTitleHint: 'The headline shown in search results. Keep it short and descriptive.', diff --git a/src/app/i18n/hy.ts b/src/app/i18n/hy.ts index 1a1bd9b..130dda0 100644 --- a/src/app/i18n/hy.ts +++ b/src/app/i18n/hy.ts @@ -1541,6 +1541,10 @@ export const hy: Translations = { seoGenerate: 'Լրացնել ապրանքի տվյալներից', seoGenerateHint: 'Լրացնում է դատարկ դաշտերը անունից և կարճ նկարագրությունից։ Ձեր տեքստը չի փոխվում։', translationsHint: 'Վերևի հիմնական դաշտերը ցուցադրվում են խանութի հիմնական լեզվով։ Այստեղ ավելացրեք թարգմանություններ այլ լեզուների համար — եթե թարգմանությունը դատարկ է, գնորդները կտեսնեն հիմնական տեքստը։', + badgesHint: 'Բեյջերը փոքր գունավոր պիտակներ են, որոնք գնորդները տեսնում են ապրանքի նկարի վրա։ Ընտրեք ստանդարտներից կամ ավելացրեք ձերը։', + addBadge: 'Ավելացնել', + removeBadge: 'Հեռացնել բեյջը', + customBadgePlaceholder: 'Ձեր բեյջի տեքստը…', seoExplain: 'Սա այն է, ինչ երևում է որոնման արդյունքներում․ հստակ վերնագիրն ու նկարագրությունը օգնում են գտնել այս ապրանքը։', searchTitle: 'Որոնման վերնագիր', searchTitleHint: 'Վերնագիրը, որ երևում է որոնման արդյունքներում։ Պահեք կարճ։', diff --git a/src/app/i18n/ru.ts b/src/app/i18n/ru.ts index fefdcd9..0840872 100644 --- a/src/app/i18n/ru.ts +++ b/src/app/i18n/ru.ts @@ -1541,6 +1541,10 @@ export const ru: Translations = { seoGenerate: 'Заполнить из данных товара', seoGenerateHint: 'Заполняет пустые поля из названия и краткого описания. Ваш текст не перезаписывается.', translationsHint: 'Основные поля выше отображаются на языке магазина по умолчанию. Здесь добавьте переводы для других языков — если перевод пуст, покупатели увидят текст по умолчанию.', + badgesHint: 'Бейджи — небольшие цветные ярлыки, которые покупатели видят на фото товара. Выберите из стандартных или добавьте свой.', + addBadge: 'Добавить', + removeBadge: 'Убрать бейдж', + customBadgePlaceholder: 'Текст своего бейджа…', seoExplain: 'Это то, что видно в результатах поиска — понятные заголовок и описание помогают найти товар.', searchTitle: 'Заголовок для поиска', searchTitleHint: 'Заголовок, показываемый в результатах поиска. Делайте его коротким.', diff --git a/src/app/i18n/translations.ts b/src/app/i18n/translations.ts index 2a319ee..9843855 100644 --- a/src/app/i18n/translations.ts +++ b/src/app/i18n/translations.ts @@ -1553,6 +1553,10 @@ export interface Translations { seoGenerate: string; seoGenerateHint: string; translationsHint: string; + badgesHint: string; + addBadge: string; + removeBadge: string; + customBadgePlaceholder: string; seoExplain: string; searchTitle: string; searchTitleHint: string;