design: итерация критика 1
Штамп первого экрана на непрозрачной подложке, цифры под мягким фильтром, зазор кнопка→фото 40px. Ленты-наклейки сняты, у штампов на этикетках разные повороты и сдвиги. Ряд цифр в «Кто обжаривает» заменён одной tag-строкой. Дескрипторы сортов — поля этикетки, «в месяц» после цены набрано Golos. Дрип-пакеты на десктопе: три зоны по центру с вертикальными линейками. Доставка в колонках 7–12, на мобиле без фото мешка. Интерес в форме — радиокнопки. Хелпер typo: неразрывные пробелы и дефисы. Скрипт скриншотов: кадр 390 со скроллом.
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { keep, typo } from './typo';
|
||||
|
||||
const N = ' ';
|
||||
|
||||
describe('typo', () => {
|
||||
it('короткие слова держатся за следующее', () => {
|
||||
expect(typo('Привозим в пятницу и по Минску')).toBe(`Привозим в${N}пятницу и${N}по${N}Минску`);
|
||||
});
|
||||
it('в начале строки и с заглавной', () => {
|
||||
expect(typo('В пятницу привозим')).toBe(`В${N}пятницу привозим`);
|
||||
});
|
||||
it('число и единица', () => {
|
||||
expect(typo('партиями по 5 кг. Пачка 250 г, цена 32 BYN')).toBe(`партиями по${N}5${N}кг. Пачка 250${N}г, цена 32${N}BYN`);
|
||||
});
|
||||
it('не трогает слова, которые только начинаются как предлог', () => {
|
||||
expect(typo('Иргачеффе вкусный')).toBe('Иргачеффе вкусный');
|
||||
});
|
||||
it('неразрывный дефис в фамилии', () => {
|
||||
expect(typo('Scott Soltys-Curry')).toBe('Scott Soltys‑Curry');
|
||||
});
|
||||
it('keep склеивает фразу', () => {
|
||||
expect(keep('красное яблоко')).toBe(`красное${N}яблоко`);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
// Типографика для вывода: неразрывные пробелы после коротких слов и между числом и единицей,
|
||||
// неразрывный дефис в двойных латинских фамилиях. Смысл текста не меняется.
|
||||
const NBSP = ' ';
|
||||
const SHORT = 'а|в|во|и|к|ко|на|не|но|о|об|от|до|по|с|со|у|за|из|для|как|или';
|
||||
const SHORT_RE = new RegExp(`(^|[\\s(«—–-])(${SHORT}) `, 'giu');
|
||||
const UNIT_RE = /(\d) (кг|г|шт|BYN|мин|дн\.?|день|дня)(?=$|[\s.,:;!?)»])/gu;
|
||||
const NAME_HYPHEN_RE = /([A-Z][a-z]+)-([A-Z][a-z]+)/g;
|
||||
|
||||
export function typo(text: string): string {
|
||||
// дважды: «и в Минске» — после замены первого слова второе стоит уже после NBSP
|
||||
let out = text.replace(SHORT_RE, `$1$2${NBSP}`);
|
||||
out = out.replace(new RegExp(`(${NBSP})(${SHORT}) `, 'giu'), `$1$2${NBSP}`);
|
||||
return out.replace(UNIT_RE, `$1${NBSP}$2`).replace(NAME_HYPHEN_RE, '$1‑$2');
|
||||
}
|
||||
|
||||
/** Склеить фразу целиком, чтобы она не рвалась: «красное яблоко». */
|
||||
export function keep(text: string): string {
|
||||
return text.replace(/ /g, NBSP);
|
||||
}
|
||||
Reference in New Issue
Block a user