@pushwoosh/brand-book 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/DeriveThemeSection/DeriveThemeSection.d.ts +3 -0
  2. package/DeriveThemeSection/DeriveThemeSection.js +459 -0
  3. package/DeriveThemeSection/index.d.ts +1 -0
  4. package/DeriveThemeSection/index.js +1 -0
  5. package/DeriveThemeSection/polyglot/index.d.ts +2 -0
  6. package/DeriveThemeSection/polyglot/index.js +33 -0
  7. package/DeriveThemeSection/polyglot/messages_ar.d.ts +3 -0
  8. package/DeriveThemeSection/polyglot/messages_ar.js +29 -0
  9. package/DeriveThemeSection/polyglot/messages_bn.d.ts +3 -0
  10. package/DeriveThemeSection/polyglot/messages_bn.js +29 -0
  11. package/DeriveThemeSection/polyglot/messages_de.d.ts +3 -0
  12. package/DeriveThemeSection/polyglot/messages_de.js +29 -0
  13. package/DeriveThemeSection/polyglot/messages_en.d.ts +3 -0
  14. package/DeriveThemeSection/polyglot/messages_en.js +29 -0
  15. package/DeriveThemeSection/polyglot/messages_es.d.ts +3 -0
  16. package/DeriveThemeSection/polyglot/messages_es.js +29 -0
  17. package/DeriveThemeSection/polyglot/messages_fr.d.ts +3 -0
  18. package/DeriveThemeSection/polyglot/messages_fr.js +29 -0
  19. package/DeriveThemeSection/polyglot/messages_he.d.ts +3 -0
  20. package/DeriveThemeSection/polyglot/messages_he.js +29 -0
  21. package/DeriveThemeSection/polyglot/messages_hi.d.ts +3 -0
  22. package/DeriveThemeSection/polyglot/messages_hi.js +29 -0
  23. package/DeriveThemeSection/polyglot/messages_ja.d.ts +3 -0
  24. package/DeriveThemeSection/polyglot/messages_ja.js +29 -0
  25. package/DeriveThemeSection/polyglot/messages_ko.d.ts +3 -0
  26. package/DeriveThemeSection/polyglot/messages_ko.js +29 -0
  27. package/DeriveThemeSection/polyglot/messages_pt.d.ts +3 -0
  28. package/DeriveThemeSection/polyglot/messages_pt.js +29 -0
  29. package/DeriveThemeSection/polyglot/messages_ru.d.ts +3 -0
  30. package/DeriveThemeSection/polyglot/messages_ru.js +29 -0
  31. package/DeriveThemeSection/polyglot/messages_th.d.ts +3 -0
  32. package/DeriveThemeSection/polyglot/messages_th.js +29 -0
  33. package/DeriveThemeSection/polyglot/messages_zh.d.ts +3 -0
  34. package/DeriveThemeSection/polyglot/messages_zh.js +29 -0
  35. package/DeriveThemeSection/polyglot/types.d.ts +44 -0
  36. package/DeriveThemeSection/polyglot/types.js +1 -0
  37. package/DeriveThemeSection/useExtractTheme.d.ts +19 -0
  38. package/DeriveThemeSection/useExtractTheme.js +44 -0
  39. package/brandModel.d.ts +23 -0
  40. package/brandModel.js +125 -0
  41. package/brandStore.d.ts +5 -0
  42. package/brandStore.js +56 -0
  43. package/defaults.d.ts +14 -0
  44. package/defaults.js +189 -0
  45. package/fonts.d.ts +29 -0
  46. package/fonts.js +140 -0
  47. package/index.d.ts +7 -0
  48. package/index.js +7 -0
  49. package/package.json +34 -3
  50. package/sources.d.ts +21 -0
  51. package/sources.js +110 -0
  52. package/types.d.ts +102 -0
  53. package/types.js +1 -0
  54. package/README.md +0 -3
@@ -0,0 +1,3 @@
1
+ import type { DeriveThemeSectionProps } from '../types';
2
+ /** Derives a brand from a site URL, or from attached materials plus the written voice; the caller applies it. */
3
+ export declare function DeriveThemeSection({ application, extractTheme, logoSrc, disabled, onTheme, voice, onVoice, onLogo, }: DeriveThemeSectionProps): import("react").JSX.Element;
@@ -0,0 +1,459 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useRef, useState } from 'react';
3
+ import { Button } from '@pushwoosh/dumb-components';
4
+ import { Color } from '@pushwoosh/kit-constants';
5
+ import { useLang } from './polyglot';
6
+ import { useExtractTheme } from './useExtractTheme';
7
+ import { ACCEPTED_IMAGE_TYPES, ACCEPTED_SOURCE_ACCEPT, fileToReferenceImage, fileToSource } from '../sources';
8
+ const HINT = {
9
+ fontSize: 12,
10
+ color: Color.LOCKED,
11
+ marginBottom: 8
12
+ };
13
+ const LABEL = {
14
+ fontSize: 12,
15
+ fontWeight: 600,
16
+ color: Color.MAIN,
17
+ marginBottom: 6
18
+ };
19
+ const INPUT = {
20
+ width: '100%',
21
+ fontSize: 13,
22
+ padding: '8px 10px',
23
+ borderRadius: 6,
24
+ border: `1px solid ${Color.FORM}`,
25
+ color: Color.MAIN,
26
+ boxSizing: 'border-box',
27
+ fontFamily: 'inherit'
28
+ };
29
+ const TEXTAREA = {
30
+ ...INPUT,
31
+ resize: 'vertical',
32
+ minHeight: 72
33
+ };
34
+ const SITE_BLOCK = {
35
+ border: `1px solid ${Color.FORM}`,
36
+ background: Color.BRIGHT_LIGHT,
37
+ borderRadius: 8,
38
+ padding: 12
39
+ };
40
+ const FOUND = {
41
+ marginTop: 10,
42
+ border: `1px solid ${Color.FORM}`,
43
+ background: Color.CLEAR,
44
+ borderRadius: 8,
45
+ padding: '8px 10px',
46
+ fontSize: 12,
47
+ color: Color.LOCKED
48
+ };
49
+ const FOUND_HEAD = {
50
+ color: Color.SUCCESS,
51
+ marginBottom: 4
52
+ };
53
+ const SWATCHES = {
54
+ display: 'flex',
55
+ gap: 4,
56
+ margin: '6px 0',
57
+ flexWrap: 'wrap'
58
+ };
59
+ const SWATCH = {
60
+ width: 22,
61
+ height: 22,
62
+ borderRadius: 5,
63
+ border: '1px solid rgba(16,24,40,.15)'
64
+ };
65
+ const CHIP = {
66
+ display: 'inline-flex',
67
+ alignItems: 'center',
68
+ gap: 6,
69
+ maxWidth: '100%',
70
+ fontSize: 12,
71
+ color: Color.MAIN,
72
+ background: Color.FROZEN,
73
+ border: `1px solid ${Color.FORM}`,
74
+ borderRadius: 6,
75
+ padding: '3px 8px'
76
+ };
77
+ const CHIP_NAME = {
78
+ overflow: 'hidden',
79
+ textOverflow: 'ellipsis',
80
+ whiteSpace: 'nowrap'
81
+ };
82
+ const CHIP_X = {
83
+ border: 'none',
84
+ background: 'none',
85
+ cursor: 'pointer',
86
+ color: Color.LOCKED,
87
+ fontSize: 14,
88
+ lineHeight: 1,
89
+ padding: 0
90
+ };
91
+ const OR = {
92
+ fontSize: 11,
93
+ letterSpacing: '.08em',
94
+ textTransform: 'uppercase',
95
+ color: Color.LOCKED
96
+ };
97
+ const NOTE = {
98
+ fontSize: 12,
99
+ color: Color.WARNING
100
+ };
101
+ const ERROR = {
102
+ fontSize: 12,
103
+ color: Color.DANGER
104
+ };
105
+ function hostOf(rawUrl) {
106
+ return rawUrl.trim().replace(/^https?:\/\//i, '').replace(/\/.*$/, '');
107
+ }
108
+ function summarize(host, brand) {
109
+ const fonts = [brand.theme.fontFamily, brand.theme.headingFontFamily].filter(Boolean).map(stack => stack.split(',')[0].replace(/["']/g, '').trim());
110
+ return {
111
+ host,
112
+ colors: Object.values(brand.theme.colors ?? {}).filter(Boolean),
113
+ fonts: Array.from(new Set(fonts)),
114
+ logo: brand.logoUrl !== '',
115
+ voice: brand.brandVoice.trim() !== ''
116
+ };
117
+ }
118
+ /** Derives a brand from a site URL, or from attached materials plus the written voice; the caller applies it. */
119
+ export function DeriveThemeSection({
120
+ application,
121
+ extractTheme,
122
+ logoSrc,
123
+ disabled = false,
124
+ onTheme,
125
+ voice,
126
+ onVoice,
127
+ onLogo
128
+ }) {
129
+ const lang = useLang();
130
+ const {
131
+ extract,
132
+ extracting,
133
+ error
134
+ } = useExtractTheme(application, extractTheme);
135
+ const fileInputRef = useRef(null);
136
+ const [siteUrl, setSiteUrl] = useState('');
137
+ const [scan, setScan] = useState(null);
138
+ const [localVoice, setLocalVoice] = useState('');
139
+ const [image, setImage] = useState(null);
140
+ const [sources, setSources] = useState([]);
141
+ const nextSourceId = useRef(1);
142
+ const [note, setNote] = useState(null);
143
+ const logoAtRequest = useRef(logoSrc);
144
+ const liveLogoSrc = useRef(logoSrc);
145
+ liveLogoSrc.current = logoSrc;
146
+ const voiceValue = voice ?? localVoice;
147
+ const setVoice = onVoice ?? setLocalVoice;
148
+ const busy = disabled || extracting;
149
+ const readErrorNote = name => lang({
150
+ message: 'BRAND_BOOK.DERIVE_THEME.SKIP_READ_ERROR',
151
+ name
152
+ });
153
+ const addFiles = async files => {
154
+ const notes = [];
155
+ let pickedImage = image;
156
+ for (const file of files) {
157
+ if (ACCEPTED_IMAGE_TYPES.includes(file.type)) {
158
+ if (pickedImage) {
159
+ notes.push(lang({
160
+ message: 'BRAND_BOOK.DERIVE_THEME.SKIP_ONLY_ONE_IMAGE',
161
+ name: file.name
162
+ }));
163
+ continue;
164
+ }
165
+ const ref = await fileToReferenceImage(file);
166
+ if (ref) {
167
+ pickedImage = {
168
+ image: ref,
169
+ name: file.name
170
+ };
171
+ setImage(pickedImage);
172
+ } else notes.push(readErrorNote(file.name));
173
+ continue;
174
+ }
175
+ const result = await fileToSource(file);
176
+ if (result.ok) {
177
+ const id = nextSourceId.current;
178
+ nextSourceId.current += 1;
179
+ setSources(prev => [...prev, {
180
+ id,
181
+ source: result.source
182
+ }]);
183
+ } else if (result.reason === 'too-large') {
184
+ notes.push(lang({
185
+ message: 'BRAND_BOOK.DERIVE_THEME.SKIP_TOO_LARGE',
186
+ name: file.name
187
+ }));
188
+ } else if (result.reason === 'empty') {
189
+ notes.push(lang({
190
+ message: 'BRAND_BOOK.DERIVE_THEME.SKIP_EMPTY',
191
+ name: file.name
192
+ }));
193
+ } else {
194
+ notes.push(readErrorNote(file.name));
195
+ }
196
+ }
197
+ setNote(notes.length > 0 ? notes.join(' ') : null);
198
+ };
199
+ const referenceImage = async () => {
200
+ if (image) return {
201
+ ok: true,
202
+ image: image.image
203
+ };
204
+ if (logoSrc.trim() === '') return {
205
+ ok: true
206
+ };
207
+ try {
208
+ const resp = await fetch(logoSrc);
209
+ const blob = await resp.blob();
210
+ const ref = await fileToReferenceImage(new File([blob], 'brand-logo', {
211
+ type: blob.type
212
+ }));
213
+ return ref ? {
214
+ ok: true,
215
+ image: ref
216
+ } : {
217
+ ok: false
218
+ };
219
+ } catch {
220
+ return {
221
+ ok: false
222
+ };
223
+ }
224
+ };
225
+ const apply = (brand, host) => {
226
+ onTheme(brand.theme);
227
+ if (brand.brandVoice.trim() !== '') setVoice(brand.brandVoice.trim());
228
+ if (brand.logoUrl !== '' && liveLogoSrc.current === logoAtRequest.current) onLogo?.(brand.logoUrl);
229
+ setScan(host === '' ? null : summarize(host, brand));
230
+ };
231
+ const scanSite = async () => {
232
+ setNote(null);
233
+ logoAtRequest.current = logoSrc;
234
+ const brand = await extract({
235
+ siteUrl: siteUrl.trim()
236
+ });
237
+ if (brand) apply(brand, hostOf(siteUrl));
238
+ };
239
+ const deriveFromMaterials = async () => {
240
+ setNote(null);
241
+ logoAtRequest.current = logoSrc;
242
+ const logo = await referenceImage();
243
+ if (!logo.ok && sources.length === 0 && voiceValue.trim() === '') {
244
+ setNote(lang({
245
+ message: 'BRAND_BOOK.DERIVE_THEME.LOGO_LOAD_FAILED_ONLY'
246
+ }));
247
+ return;
248
+ }
249
+ if (!logo.ok) setNote(lang({
250
+ message: 'BRAND_BOOK.DERIVE_THEME.LOGO_LOAD_FAILED_FALLBACK'
251
+ }));
252
+ const brand = await extract({
253
+ image: logo.ok ? logo.image : undefined,
254
+ sources: sources.map(s => s.source),
255
+ description: voiceValue.trim()
256
+ });
257
+ if (brand) apply(brand, '');
258
+ };
259
+ const canScan = !busy && siteUrl.trim() !== '';
260
+ const canDerive = !busy && (!!image || sources.length > 0 || voiceValue.trim() !== '' || logoSrc.trim() !== '');
261
+ return _jsxs("div", {
262
+ style: {
263
+ display: 'flex',
264
+ flexDirection: 'column',
265
+ gap: 8,
266
+ marginBottom: 12
267
+ },
268
+ children: [_jsxs("div", {
269
+ style: SITE_BLOCK,
270
+ children: [_jsx("div", {
271
+ style: LABEL,
272
+ children: lang({
273
+ message: 'BRAND_BOOK.DERIVE_THEME.BUILD_FROM_WEBSITE'
274
+ })
275
+ }), _jsxs("div", {
276
+ style: {
277
+ display: 'flex',
278
+ gap: 8
279
+ },
280
+ children: [_jsx("input", {
281
+ style: INPUT,
282
+ value: siteUrl,
283
+ placeholder: lang({
284
+ message: 'BRAND_BOOK.DERIVE_THEME.SITE_URL_PLACEHOLDER'
285
+ }),
286
+ disabled: busy,
287
+ onChange: e => setSiteUrl(e.target.value),
288
+ onKeyDown: e => {
289
+ if (e.key === 'Enter' && canScan) void scanSite();
290
+ }
291
+ }), _jsx("div", {
292
+ style: {
293
+ flexShrink: 0
294
+ },
295
+ children: _jsx(Button, {
296
+ size: "compact",
297
+ color: "primary",
298
+ isDisabled: !canScan,
299
+ onClick: () => {
300
+ void scanSite();
301
+ },
302
+ children: extracting ? lang({
303
+ message: 'BRAND_BOOK.DERIVE_THEME.SCANNING'
304
+ }) : lang({
305
+ message: 'BRAND_BOOK.DERIVE_THEME.SCAN_SITE'
306
+ })
307
+ })
308
+ })]
309
+ }), _jsx("div", {
310
+ style: {
311
+ ...HINT,
312
+ marginTop: 8,
313
+ marginBottom: 0
314
+ },
315
+ children: lang({
316
+ message: 'BRAND_BOOK.DERIVE_THEME.SCAN_EXPLAINER'
317
+ })
318
+ }), scan && _jsxs("div", {
319
+ style: FOUND,
320
+ children: [_jsxs("div", {
321
+ style: FOUND_HEAD,
322
+ children: [lang({
323
+ message: 'BRAND_BOOK.DERIVE_THEME.READ_CHECK'
324
+ }), ' ', scan.host]
325
+ }), _jsx("div", {
326
+ style: SWATCHES,
327
+ children: scan.colors.map(color => _jsx("span", {
328
+ style: {
329
+ ...SWATCH,
330
+ background: color
331
+ },
332
+ title: color
333
+ }, color))
334
+ }), _jsxs("div", {
335
+ children: [lang({
336
+ message: 'BRAND_BOOK.DERIVE_THEME.COLOURS_COUNT',
337
+ count: scan.colors.length
338
+ }), scan.fonts.length > 0 && ` · ${scan.fonts.join(' · ')}`, scan.logo && ` · ${lang({
339
+ message: 'BRAND_BOOK.DERIVE_THEME.LOGO_TAG'
340
+ })}`, scan.voice && ` · ${lang({
341
+ message: 'BRAND_BOOK.DERIVE_THEME.VOICE_TAG'
342
+ })}`, ` — ${lang({
343
+ message: 'BRAND_BOOK.DERIVE_THEME.EDITABLE_BELOW'
344
+ })}`]
345
+ })]
346
+ })]
347
+ }), _jsx("div", {
348
+ style: OR,
349
+ children: lang({
350
+ message: 'BRAND_BOOK.DERIVE_THEME.OR'
351
+ })
352
+ }), _jsx("div", {
353
+ style: LABEL,
354
+ children: lang({
355
+ message: 'BRAND_BOOK.DERIVE_THEME.BRAND_VOICE_LABEL'
356
+ })
357
+ }), _jsx("div", {
358
+ style: HINT,
359
+ children: lang({
360
+ message: 'BRAND_BOOK.DERIVE_THEME.BRAND_VOICE_HINT'
361
+ })
362
+ }), _jsx("textarea", {
363
+ style: TEXTAREA,
364
+ value: voiceValue,
365
+ placeholder: lang({
366
+ message: 'BRAND_BOOK.DERIVE_THEME.BRAND_VOICE_PLACEHOLDER'
367
+ }),
368
+ disabled: busy,
369
+ onChange: e => setVoice(e.target.value)
370
+ }), (image || sources.length > 0) && _jsxs("div", {
371
+ style: {
372
+ display: 'flex',
373
+ flexWrap: 'wrap',
374
+ gap: 6
375
+ },
376
+ children: [image && _jsxs("span", {
377
+ style: CHIP,
378
+ children: [_jsxs("span", {
379
+ style: CHIP_NAME,
380
+ children: ["\uD83D\uDDBC", image.name]
381
+ }), _jsx("button", {
382
+ type: "button",
383
+ style: CHIP_X,
384
+ "aria-label": lang({
385
+ message: 'BRAND_BOOK.DERIVE_THEME.REMOVE_IMAGE'
386
+ }),
387
+ onClick: () => setImage(null),
388
+ children: "\u00D7"
389
+ })]
390
+ }), sources.map(({
391
+ id,
392
+ source
393
+ }) => _jsxs("span", {
394
+ style: CHIP,
395
+ children: [_jsx("span", {
396
+ style: CHIP_NAME,
397
+ children: source.name || lang({
398
+ message: 'BRAND_BOOK.DERIVE_THEME.FILE_FALLBACK_NAME'
399
+ })
400
+ }), _jsx("button", {
401
+ type: "button",
402
+ style: CHIP_X,
403
+ "aria-label": lang({
404
+ message: 'BRAND_BOOK.DERIVE_THEME.REMOVE_SOURCE',
405
+ name: source.name
406
+ }),
407
+ onClick: () => setSources(prev => prev.filter(s => s.id !== id)),
408
+ children: "\u00D7"
409
+ })]
410
+ }, id))]
411
+ }), _jsx("input", {
412
+ ref: fileInputRef,
413
+ type: "file",
414
+ multiple: true,
415
+ accept: [...ACCEPTED_IMAGE_TYPES, ACCEPTED_SOURCE_ACCEPT].join(','),
416
+ style: {
417
+ display: 'none'
418
+ },
419
+ onChange: e => {
420
+ const files = Array.from(e.target.files ?? []);
421
+ e.target.value = '';
422
+ void addFiles(files);
423
+ }
424
+ }), _jsxs("div", {
425
+ style: {
426
+ display: 'flex',
427
+ gap: 8,
428
+ flexWrap: 'wrap'
429
+ },
430
+ children: [_jsx(Button, {
431
+ size: "compact",
432
+ color: "secondary",
433
+ isDisabled: busy,
434
+ onClick: () => fileInputRef.current?.click(),
435
+ children: lang({
436
+ message: 'BRAND_BOOK.DERIVE_THEME.ATTACH_FILES'
437
+ })
438
+ }), _jsx(Button, {
439
+ size: "compact",
440
+ color: "primary",
441
+ isDisabled: !canDerive,
442
+ onClick: () => {
443
+ void deriveFromMaterials();
444
+ },
445
+ children: extracting ? lang({
446
+ message: 'BRAND_BOOK.DERIVE_THEME.READING'
447
+ }) : lang({
448
+ message: 'BRAND_BOOK.DERIVE_THEME.DERIVE_BRAND'
449
+ })
450
+ })]
451
+ }), note && _jsx("div", {
452
+ style: NOTE,
453
+ children: note
454
+ }), error && _jsx("div", {
455
+ style: ERROR,
456
+ children: error
457
+ })]
458
+ });
459
+ }
@@ -0,0 +1 @@
1
+ export { DeriveThemeSection } from './DeriveThemeSection';
@@ -0,0 +1 @@
1
+ export { DeriveThemeSection } from './DeriveThemeSection';
@@ -0,0 +1,2 @@
1
+ import { type DeriveThemeMessages } from './types';
2
+ export declare const useLang: () => (props: import("@pushwoosh/dumb-components/polyglot").LangProps<DeriveThemeMessages>) => string;
@@ -0,0 +1,33 @@
1
+ import { createLang } from '@pushwoosh/dumb-components/polyglot';
2
+ import { messages as ar } from './messages_ar';
3
+ import { messages as bn } from './messages_bn';
4
+ import { messages as de } from './messages_de';
5
+ import { messages as en } from './messages_en';
6
+ import { messages as es } from './messages_es';
7
+ import { messages as fr } from './messages_fr';
8
+ import { messages as he } from './messages_he';
9
+ import { messages as hi } from './messages_hi';
10
+ import { messages as ja } from './messages_ja';
11
+ import { messages as ko } from './messages_ko';
12
+ import { messages as pt } from './messages_pt';
13
+ import { messages as ru } from './messages_ru';
14
+ import { messages as th } from './messages_th';
15
+ import { messages as zh } from './messages_zh';
16
+ export const {
17
+ useLang
18
+ } = createLang({
19
+ ar,
20
+ bn,
21
+ de,
22
+ en,
23
+ es,
24
+ fr,
25
+ he,
26
+ hi,
27
+ ja,
28
+ ko,
29
+ pt,
30
+ ru,
31
+ th,
32
+ zh
33
+ });
@@ -0,0 +1,3 @@
1
+ import type { LangMessages } from '@pushwoosh/dumb-components/polyglot';
2
+ import { type DeriveThemeMessages } from './types';
3
+ export declare const messages: LangMessages<DeriveThemeMessages>;
@@ -0,0 +1,29 @@
1
+ export const messages = {
2
+ 'BRAND_BOOK.DERIVE_THEME.SKIP_ONLY_ONE_IMAGE': 'تم تخطي “{{name}}” — يتم استخدام صورة واحدة فقط.',
3
+ 'BRAND_BOOK.DERIVE_THEME.SKIP_READ_ERROR': 'تعذرت قراءة “{{name}}”.',
4
+ 'BRAND_BOOK.DERIVE_THEME.SKIP_TOO_LARGE': '“{{name}}” كبير جدًا.',
5
+ 'BRAND_BOOK.DERIVE_THEME.SKIP_EMPTY': '“{{name}}” فارغ.',
6
+ 'BRAND_BOOK.DERIVE_THEME.LOGO_LOAD_FAILED_ONLY': 'تعذر تحميل صورة الشعار — أرفقها كملف بدلاً من ذلك.',
7
+ 'BRAND_BOOK.DERIVE_THEME.LOGO_LOAD_FAILED_FALLBACK': 'تعذر تحميل صورة الشعار؛ سيتم الاشتقاق من المواد الأخرى.',
8
+ 'BRAND_BOOK.DERIVE_THEME.BUILD_FROM_WEBSITE': 'أنشئ من موقعك الإلكتروني',
9
+ 'BRAND_BOOK.DERIVE_THEME.SITE_URL_PLACEHOLDER': 'acme.com',
10
+ 'BRAND_BOOK.DERIVE_THEME.SCANNING': 'جارٍ المسح…',
11
+ 'BRAND_BOOK.DERIVE_THEME.SCAN_SITE': 'مسح الموقع',
12
+ 'BRAND_BOOK.DERIVE_THEME.SCAN_EXPLAINER': 'نقرأ الصفحة وملفات الأنماط الخاصة بها — الألوان والخطوط والشعار ونبرة النص. لا يتم تخزين أي شيء حتى تحفظ العلامة التجارية.',
13
+ 'BRAND_BOOK.DERIVE_THEME.READ_CHECK': '✓ تمت القراءة',
14
+ 'BRAND_BOOK.DERIVE_THEME.COLOURS_COUNT': '{{count}} ألوان',
15
+ 'BRAND_BOOK.DERIVE_THEME.LOGO_TAG': 'شعار',
16
+ 'BRAND_BOOK.DERIVE_THEME.VOICE_TAG': 'نبرة',
17
+ 'BRAND_BOOK.DERIVE_THEME.EDITABLE_BELOW': 'كل شيء قابل للتعديل أدناه',
18
+ 'BRAND_BOOK.DERIVE_THEME.OR': 'أو',
19
+ 'BRAND_BOOK.DERIVE_THEME.BRAND_VOICE_LABEL': 'نبرة العلامة التجارية',
20
+ 'BRAND_BOOK.DERIVE_THEME.BRAND_VOICE_HINT': 'كيف تتحدث العلامة التجارية. يملأ المسح هذا الحقل من الموقع؛ كما يوجه لوحة الألوان عند الاستخلاص من المواد المرفقة.',
21
+ 'BRAND_BOOK.DERIVE_THEME.BRAND_VOICE_PLACEHOLDER': 'مثال: حوارية وساخرة، جمل قصيرة، تخاطب القارئ مباشرة',
22
+ 'BRAND_BOOK.DERIVE_THEME.REMOVE_IMAGE': 'إزالة الصورة',
23
+ 'BRAND_BOOK.DERIVE_THEME.FILE_FALLBACK_NAME': 'ملف',
24
+ 'BRAND_BOOK.DERIVE_THEME.REMOVE_SOURCE': 'إزالة {{name}}',
25
+ 'BRAND_BOOK.DERIVE_THEME.ATTACH_FILES': 'إرفاق ملفات',
26
+ 'BRAND_BOOK.DERIVE_THEME.READING': 'جارٍ القراءة…',
27
+ 'BRAND_BOOK.DERIVE_THEME.DERIVE_BRAND': 'استخلاص العلامة التجارية',
28
+ 'BRAND_BOOK.DERIVE_THEME.EXTRACT_FAILED': 'تعذرت قراءة العلامة التجارية: {{error}}'
29
+ };
@@ -0,0 +1,3 @@
1
+ import type { LangMessages } from '@pushwoosh/dumb-components/polyglot';
2
+ import { type DeriveThemeMessages } from './types';
3
+ export declare const messages: LangMessages<DeriveThemeMessages>;
@@ -0,0 +1,29 @@
1
+ export const messages = {
2
+ 'BRAND_BOOK.DERIVE_THEME.SKIP_ONLY_ONE_IMAGE': '“{{name}}” এড়িয়ে যাওয়া হয়েছে — শুধুমাত্র একটি ছবি ব্যবহৃত হয়েছে।',
3
+ 'BRAND_BOOK.DERIVE_THEME.SKIP_READ_ERROR': '“{{name}}” পড়া যায়নি।',
4
+ 'BRAND_BOOK.DERIVE_THEME.SKIP_TOO_LARGE': '“{{name}}” খুব বড়।',
5
+ 'BRAND_BOOK.DERIVE_THEME.SKIP_EMPTY': '“{{name}}” খালি।',
6
+ 'BRAND_BOOK.DERIVE_THEME.LOGO_LOAD_FAILED_ONLY': 'লোগো ছবিটি লোড করা যায়নি — পরিবর্তে এটি একটি ফাইল হিসাবে সংযুক্ত করুন।',
7
+ 'BRAND_BOOK.DERIVE_THEME.LOGO_LOAD_FAILED_FALLBACK': 'লোগো ছবিটি লোড করা যায়নি; অন্যান্য উপাদান থেকে তৈরি করা হচ্ছে।',
8
+ 'BRAND_BOOK.DERIVE_THEME.BUILD_FROM_WEBSITE': 'আপনার ওয়েবসাইট থেকে তৈরি করুন',
9
+ 'BRAND_BOOK.DERIVE_THEME.SITE_URL_PLACEHOLDER': 'acme.com',
10
+ 'BRAND_BOOK.DERIVE_THEME.SCANNING': 'স্ক্যান করা হচ্ছে…',
11
+ 'BRAND_BOOK.DERIVE_THEME.SCAN_SITE': 'সাইট স্ক্যান করুন',
12
+ 'BRAND_BOOK.DERIVE_THEME.SCAN_EXPLAINER': 'আমরা পৃষ্ঠা এবং এর স্টাইলশীটগুলি পড়ি — রঙ, ফন্ট, লোগো এবং এর কপির টোন। আপনি ব্র্যান্ডটি সেভ না করা পর্যন্ত কিছুই সংরক্ষণ করা হয় না।',
13
+ 'BRAND_BOOK.DERIVE_THEME.READ_CHECK': '✓ পড়া হয়েছে',
14
+ 'BRAND_BOOK.DERIVE_THEME.COLOURS_COUNT': '{{count}}টি রঙ',
15
+ 'BRAND_BOOK.DERIVE_THEME.LOGO_TAG': 'লোগো',
16
+ 'BRAND_BOOK.DERIVE_THEME.VOICE_TAG': 'ভয়েস',
17
+ 'BRAND_BOOK.DERIVE_THEME.EDITABLE_BELOW': 'নিচে সবকিছু সম্পাদনাযোগ্য',
18
+ 'BRAND_BOOK.DERIVE_THEME.OR': 'অথবা',
19
+ 'BRAND_BOOK.DERIVE_THEME.BRAND_VOICE_LABEL': 'ব্র্যান্ড ভয়েস',
20
+ 'BRAND_BOOK.DERIVE_THEME.BRAND_VOICE_HINT': 'ব্র্যান্ডটি কীভাবে কথা বলে। একটি স্ক্যান সাইট থেকে এটি পূরণ করে; এটি সংযুক্ত উপকরণ থেকে ডিরাইভ করার সময় প্যালেটকেও চালনা করে।',
21
+ 'BRAND_BOOK.DERIVE_THEME.BRAND_VOICE_PLACEHOLDER': 'যেমন কথোপকথনমূলক এবং আত্ম-বিদ্রূপাত্মক, ছোট বাক্য, সরাসরি পাঠকের সাথে কথা বলে',
22
+ 'BRAND_BOOK.DERIVE_THEME.REMOVE_IMAGE': 'ছবি সরান',
23
+ 'BRAND_BOOK.DERIVE_THEME.FILE_FALLBACK_NAME': 'ফাইল',
24
+ 'BRAND_BOOK.DERIVE_THEME.REMOVE_SOURCE': '{{name}} সরান',
25
+ 'BRAND_BOOK.DERIVE_THEME.ATTACH_FILES': 'ফাইল সংযুক্ত করুন',
26
+ 'BRAND_BOOK.DERIVE_THEME.READING': 'পড়া হচ্ছে…',
27
+ 'BRAND_BOOK.DERIVE_THEME.DERIVE_BRAND': 'ব্র্যান্ড ডিরাইভ করুন',
28
+ 'BRAND_BOOK.DERIVE_THEME.EXTRACT_FAILED': 'ব্র্যান্ডটি পড়া যায়নি: {{error}}'
29
+ };
@@ -0,0 +1,3 @@
1
+ import type { LangMessages } from '@pushwoosh/dumb-components/polyglot';
2
+ import { type DeriveThemeMessages } from './types';
3
+ export declare const messages: LangMessages<DeriveThemeMessages>;
@@ -0,0 +1,29 @@
1
+ export const messages = {
2
+ 'BRAND_BOOK.DERIVE_THEME.SKIP_ONLY_ONE_IMAGE': '„{{name}}“ übersprungen – es wird nur ein Bild verwendet.',
3
+ 'BRAND_BOOK.DERIVE_THEME.SKIP_READ_ERROR': '„{{name}}“ konnte nicht gelesen werden.',
4
+ 'BRAND_BOOK.DERIVE_THEME.SKIP_TOO_LARGE': '„{{name}}“ ist zu groß.',
5
+ 'BRAND_BOOK.DERIVE_THEME.SKIP_EMPTY': '„{{name}}“ ist leer.',
6
+ 'BRAND_BOOK.DERIVE_THEME.LOGO_LOAD_FAILED_ONLY': 'Das Logo-Bild konnte nicht geladen werden – hängen Sie es stattdessen als Datei an.',
7
+ 'BRAND_BOOK.DERIVE_THEME.LOGO_LOAD_FAILED_FALLBACK': 'Logo-Bild konnte nicht geladen werden; wird von anderen Materialien abgeleitet.',
8
+ 'BRAND_BOOK.DERIVE_THEME.BUILD_FROM_WEBSITE': 'Von Ihrer Website erstellen',
9
+ 'BRAND_BOOK.DERIVE_THEME.SITE_URL_PLACEHOLDER': 'acme.com',
10
+ 'BRAND_BOOK.DERIVE_THEME.SCANNING': 'Wird gescannt…',
11
+ 'BRAND_BOOK.DERIVE_THEME.SCAN_SITE': 'Website scannen',
12
+ 'BRAND_BOOK.DERIVE_THEME.SCAN_EXPLAINER': 'Wir lesen die Seite und ihre Stylesheets – Farben, Schriftarten, Logo und den Tonfall der Texte. Nichts wird gespeichert, bis Sie die Marke speichern.',
13
+ 'BRAND_BOOK.DERIVE_THEME.READ_CHECK': '✓ Gelesen',
14
+ 'BRAND_BOOK.DERIVE_THEME.COLOURS_COUNT': '{{count}} Farben',
15
+ 'BRAND_BOOK.DERIVE_THEME.LOGO_TAG': 'Logo',
16
+ 'BRAND_BOOK.DERIVE_THEME.VOICE_TAG': 'Tonfall',
17
+ 'BRAND_BOOK.DERIVE_THEME.EDITABLE_BELOW': 'alles unten bearbeitbar',
18
+ 'BRAND_BOOK.DERIVE_THEME.OR': 'oder',
19
+ 'BRAND_BOOK.DERIVE_THEME.BRAND_VOICE_LABEL': 'Markenstimme',
20
+ 'BRAND_BOOK.DERIVE_THEME.BRAND_VOICE_HINT': 'Wie die Marke spricht. Ein Scan füllt dies von der Website aus; es steuert auch die Palette, wenn Sie sie aus angehängten Materialien ableiten.',
21
+ 'BRAND_BOOK.DERIVE_THEME.BRAND_VOICE_PLACEHOLDER': 'z. B. gesprächig und selbstironisch, kurze Sätze, spricht den Leser direkt an',
22
+ 'BRAND_BOOK.DERIVE_THEME.REMOVE_IMAGE': 'Bild entfernen',
23
+ 'BRAND_BOOK.DERIVE_THEME.FILE_FALLBACK_NAME': 'Datei',
24
+ 'BRAND_BOOK.DERIVE_THEME.REMOVE_SOURCE': '{{name}} entfernen',
25
+ 'BRAND_BOOK.DERIVE_THEME.ATTACH_FILES': 'Dateien anhängen',
26
+ 'BRAND_BOOK.DERIVE_THEME.READING': 'Lese…',
27
+ 'BRAND_BOOK.DERIVE_THEME.DERIVE_BRAND': 'Marke ableiten',
28
+ 'BRAND_BOOK.DERIVE_THEME.EXTRACT_FAILED': 'Marke konnte nicht gelesen werden: {{error}}'
29
+ };
@@ -0,0 +1,3 @@
1
+ import type { LangMessages } from '@pushwoosh/dumb-components/polyglot';
2
+ import { type DeriveThemeMessages } from './types';
3
+ export declare const messages: LangMessages<DeriveThemeMessages>;
@@ -0,0 +1,29 @@
1
+ export const messages = {
2
+ 'BRAND_BOOK.DERIVE_THEME.SKIP_ONLY_ONE_IMAGE': '“{{name}}” skipped — only one image is used.',
3
+ 'BRAND_BOOK.DERIVE_THEME.SKIP_READ_ERROR': '“{{name}}” could not be read.',
4
+ 'BRAND_BOOK.DERIVE_THEME.SKIP_TOO_LARGE': '“{{name}}” is too large.',
5
+ 'BRAND_BOOK.DERIVE_THEME.SKIP_EMPTY': '“{{name}}” is empty.',
6
+ 'BRAND_BOOK.DERIVE_THEME.LOGO_LOAD_FAILED_ONLY': 'Could not load the logo image — attach it as a file instead.',
7
+ 'BRAND_BOOK.DERIVE_THEME.LOGO_LOAD_FAILED_FALLBACK': 'Could not load the logo image; deriving from the other materials.',
8
+ 'BRAND_BOOK.DERIVE_THEME.BUILD_FROM_WEBSITE': 'Build from your website',
9
+ 'BRAND_BOOK.DERIVE_THEME.SITE_URL_PLACEHOLDER': 'acme.com',
10
+ 'BRAND_BOOK.DERIVE_THEME.SCANNING': 'Scanning…',
11
+ 'BRAND_BOOK.DERIVE_THEME.SCAN_SITE': 'Scan site',
12
+ 'BRAND_BOOK.DERIVE_THEME.SCAN_EXPLAINER': 'We read the page and its stylesheets — colours, fonts, logo and the tone of its copy. Nothing is stored until you save the brand.',
13
+ 'BRAND_BOOK.DERIVE_THEME.READ_CHECK': '✓ Read',
14
+ 'BRAND_BOOK.DERIVE_THEME.COLOURS_COUNT': '{{count}} colours',
15
+ 'BRAND_BOOK.DERIVE_THEME.LOGO_TAG': 'logo',
16
+ 'BRAND_BOOK.DERIVE_THEME.VOICE_TAG': 'voice',
17
+ 'BRAND_BOOK.DERIVE_THEME.EDITABLE_BELOW': 'all editable below',
18
+ 'BRAND_BOOK.DERIVE_THEME.OR': 'or',
19
+ 'BRAND_BOOK.DERIVE_THEME.BRAND_VOICE_LABEL': 'Brand voice',
20
+ 'BRAND_BOOK.DERIVE_THEME.BRAND_VOICE_HINT': 'How the brand talks. A scan fills this from the site; it also steers the palette when you derive from attached materials.',
21
+ 'BRAND_BOOK.DERIVE_THEME.BRAND_VOICE_PLACEHOLDER': 'e.g. conversational and self-ironic, short sentences, speaks to the reader directly',
22
+ 'BRAND_BOOK.DERIVE_THEME.REMOVE_IMAGE': 'Remove image',
23
+ 'BRAND_BOOK.DERIVE_THEME.FILE_FALLBACK_NAME': 'file',
24
+ 'BRAND_BOOK.DERIVE_THEME.REMOVE_SOURCE': 'Remove {{name}}',
25
+ 'BRAND_BOOK.DERIVE_THEME.ATTACH_FILES': 'Attach files',
26
+ 'BRAND_BOOK.DERIVE_THEME.READING': 'Reading…',
27
+ 'BRAND_BOOK.DERIVE_THEME.DERIVE_BRAND': 'Derive brand',
28
+ 'BRAND_BOOK.DERIVE_THEME.EXTRACT_FAILED': 'Could not read the brand: {{error}}'
29
+ };
@@ -0,0 +1,3 @@
1
+ import type { LangMessages } from '@pushwoosh/dumb-components/polyglot';
2
+ import { type DeriveThemeMessages } from './types';
3
+ export declare const messages: LangMessages<DeriveThemeMessages>;