@nice2dev/ui-printing 1.1.6 → 1.1.9
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.
- package/dist/index.cjs +2 -2
- package/dist/index.d.ts +5 -5
- package/dist/index.mjs +1894 -1728
- package/dist/ui-printing.css +1 -1
- package/package.json +3 -2
- package/src/index.ts +5 -24
- package/src/print-button/NicePrintButton.tsx +44 -18
- package/src/print-button/PrintButton.module.css +147 -43
- package/src/print-preview/NicePrintPreview.tsx +19 -17
- package/src/print-preview/PrintPreview.module.css +60 -18
- package/src/print-queue/NicePrintQueue.tsx +76 -42
- package/src/print-queue/PrintQueue.module.css +207 -57
- package/src/template-browser/NiceTemplateBrowser.tsx +44 -19
- package/src/template-browser/TemplateBrowser.module.css +70 -25
- package/src/template-editor/NiceTemplateEditor.tsx +307 -182
- package/src/template-editor/TemplateEditor.module.css +184 -128
- package/src/types/printingTypes.ts +1 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/print-button/NicePrintButton.d.ts.map +0 -1
- package/dist/print-button/index.d.ts.map +0 -1
- package/dist/print-preview/NicePrintPreview.d.ts.map +0 -1
- package/dist/print-preview/index.d.ts.map +0 -1
- package/dist/print-queue/NicePrintQueue.d.ts.map +0 -1
- package/dist/print-queue/index.d.ts.map +0 -1
- package/dist/style.css +0 -1
- package/dist/template-browser/NiceTemplateBrowser.d.ts.map +0 -1
- package/dist/template-browser/index.d.ts.map +0 -1
- package/dist/template-editor/NiceTemplateEditor.d.ts.map +0 -1
- package/dist/template-editor/index.d.ts.map +0 -1
- package/dist/types/printingTypes.d.ts.map +0 -1
- package/src/template-editor/NiceTemplateEditor.tsx.first +0 -1011
- package/src/template-editor/NiceTemplateEditor.tsx.tmp +0 -392
|
@@ -1,11 +1,24 @@
|
|
|
1
1
|
/* eslint-disable jsx-a11y/click-events-have-key-events -- modal overlay backdrops (Esc-on-parent provides keyboard close), selection rows in .map() accompanied by visible cursor:pointer styling and sibling buttons; full keyboard migration via useAccessibleClick + extracted subcomponents tracked in TODO_1.0.10 A2.3 */
|
|
2
|
+
import { NiceIcon, useNiceTranslation } from '@nice2dev/ui';
|
|
2
3
|
import React, { useState } from 'react';
|
|
3
4
|
|
|
4
|
-
import type {
|
|
5
|
+
import type {
|
|
6
|
+
PrintTemplate,
|
|
7
|
+
TemplateId as _TemplateId,
|
|
8
|
+
NiceTemplateBrowserProps,
|
|
9
|
+
} from '../types/printingTypes';
|
|
5
10
|
|
|
6
11
|
import styles from './TemplateBrowser.module.css';
|
|
7
12
|
|
|
8
|
-
|
|
13
|
+
/** Built-in category chips; `key` is what a template's `category` field holds. */
|
|
14
|
+
const CATEGORIES: { key: string; fallback: string }[] = [
|
|
15
|
+
{ key: 'printing.category.invoices', fallback: 'Invoices' },
|
|
16
|
+
{ key: 'printing.category.reports', fallback: 'Reports' },
|
|
17
|
+
{ key: 'printing.category.labels', fallback: 'Labels' },
|
|
18
|
+
{ key: 'printing.category.letters', fallback: 'Letters' },
|
|
19
|
+
{ key: 'printing.category.contracts', fallback: 'Contracts' },
|
|
20
|
+
{ key: 'printing.category.other', fallback: 'Other' },
|
|
21
|
+
];
|
|
9
22
|
|
|
10
23
|
function importTemplateFromJson(file: File): Promise<PrintTemplate> {
|
|
11
24
|
return new Promise((resolve, reject) => {
|
|
@@ -43,6 +56,7 @@ export const NiceTemplateBrowser: React.FC<NiceTemplateBrowserProps> = ({
|
|
|
43
56
|
style,
|
|
44
57
|
theme = 'light',
|
|
45
58
|
}) => {
|
|
59
|
+
const { t } = useNiceTranslation();
|
|
46
60
|
const [search, setSearch] = useState('');
|
|
47
61
|
const [categoryFilter, setCategoryFilter] = useState<string | null>(null);
|
|
48
62
|
const [hoveredId, setHoveredId] = useState<string | null>(null);
|
|
@@ -82,19 +96,23 @@ export const NiceTemplateBrowser: React.FC<NiceTemplateBrowserProps> = ({
|
|
|
82
96
|
<input
|
|
83
97
|
type="search"
|
|
84
98
|
className={styles.searchInput}
|
|
85
|
-
placeholder=
|
|
99
|
+
placeholder={t('printing.searchTemplates', 'Search templates…')}
|
|
86
100
|
value={search}
|
|
87
101
|
onChange={(e) => setSearch(e.target.value)}
|
|
88
102
|
/>
|
|
89
|
-
<button
|
|
90
|
-
|
|
103
|
+
<button
|
|
104
|
+
className={styles.actionBtn}
|
|
105
|
+
onClick={onNew}
|
|
106
|
+
title={t('printing.newTemplate', 'New template')}
|
|
107
|
+
>
|
|
108
|
+
<NiceIcon name="plus" size={14} /> {t('printing.new', 'New')}
|
|
91
109
|
</button>
|
|
92
110
|
<button
|
|
93
111
|
className={styles.actionBtn}
|
|
94
112
|
onClick={() => fileInputRef.current?.click()}
|
|
95
|
-
title=
|
|
113
|
+
title={t('printing.importJson', 'Import JSON')}
|
|
96
114
|
>
|
|
97
|
-
|
|
115
|
+
<NiceIcon name="upload" size={14} /> {t('printing.import', 'Import')}
|
|
98
116
|
</button>
|
|
99
117
|
<input ref={fileInputRef} type="file" accept=".json" hidden onChange={handleFileImport} />
|
|
100
118
|
</div>
|
|
@@ -105,15 +123,15 @@ export const NiceTemplateBrowser: React.FC<NiceTemplateBrowserProps> = ({
|
|
|
105
123
|
className={`${styles.catChip} ${!categoryFilter ? styles.catChipActive : ''}`}
|
|
106
124
|
onClick={() => setCategoryFilter(null)}
|
|
107
125
|
>
|
|
108
|
-
|
|
126
|
+
{t('printing.filter.all', 'All')}
|
|
109
127
|
</button>
|
|
110
128
|
{CATEGORIES.map((cat) => (
|
|
111
129
|
<button
|
|
112
|
-
key={cat}
|
|
113
|
-
className={`${styles.catChip} ${categoryFilter === cat ? styles.catChipActive : ''}`}
|
|
114
|
-
onClick={() => setCategoryFilter((c) => (c === cat ? null : cat))}
|
|
130
|
+
key={cat.key}
|
|
131
|
+
className={`${styles.catChip} ${categoryFilter === cat.fallback ? styles.catChipActive : ''}`}
|
|
132
|
+
onClick={() => setCategoryFilter((c) => (c === cat.fallback ? null : cat.fallback))}
|
|
115
133
|
>
|
|
116
|
-
{cat}
|
|
134
|
+
{t(cat.key, cat.fallback)}
|
|
117
135
|
</button>
|
|
118
136
|
))}
|
|
119
137
|
</div>
|
|
@@ -164,9 +182,9 @@ export const NiceTemplateBrowser: React.FC<NiceTemplateBrowserProps> = ({
|
|
|
164
182
|
onExport?.(tpl);
|
|
165
183
|
exportTemplate(tpl);
|
|
166
184
|
}}
|
|
167
|
-
title=
|
|
185
|
+
title={t('printing.export', 'Export')}
|
|
168
186
|
>
|
|
169
|
-
|
|
187
|
+
<NiceIcon name="download" size={14} />
|
|
170
188
|
</button>
|
|
171
189
|
{onDelete && (
|
|
172
190
|
<button
|
|
@@ -175,9 +193,9 @@ export const NiceTemplateBrowser: React.FC<NiceTemplateBrowserProps> = ({
|
|
|
175
193
|
e.stopPropagation();
|
|
176
194
|
onDelete(tpl.id);
|
|
177
195
|
}}
|
|
178
|
-
title=
|
|
196
|
+
title={t('printing.action.remove', 'Remove')}
|
|
179
197
|
>
|
|
180
|
-
|
|
198
|
+
<NiceIcon name="trash" size={14} />
|
|
181
199
|
</button>
|
|
182
200
|
)}
|
|
183
201
|
</div>
|
|
@@ -190,7 +208,10 @@ export const NiceTemplateBrowser: React.FC<NiceTemplateBrowserProps> = ({
|
|
|
190
208
|
{tpl.description && <div className={styles.cardDesc}>{tpl.description}</div>}
|
|
191
209
|
<div className={styles.cardMeta}>
|
|
192
210
|
<span className={styles.cardSize}>
|
|
193
|
-
{tpl.paperSize}
|
|
211
|
+
{tpl.paperSize}{' '}
|
|
212
|
+
{tpl.orientation === 'landscape'
|
|
213
|
+
? t('printing.orientation.landscape', 'landscape')
|
|
214
|
+
: t('printing.orientation.portrait', 'portrait')}
|
|
194
215
|
</span>
|
|
195
216
|
{tpl.category && <span className={styles.cardCat}>{tpl.category}</span>}
|
|
196
217
|
</div>
|
|
@@ -209,9 +230,13 @@ export const NiceTemplateBrowser: React.FC<NiceTemplateBrowserProps> = ({
|
|
|
209
230
|
|
|
210
231
|
{filtered.length === 0 && (
|
|
211
232
|
<div className={styles.emptyState}>
|
|
212
|
-
<span className={styles.emptyIcon}
|
|
233
|
+
<span className={styles.emptyIcon}>
|
|
234
|
+
<NiceIcon name="file" size={32} />
|
|
235
|
+
</span>
|
|
213
236
|
<span>
|
|
214
|
-
{search
|
|
237
|
+
{search
|
|
238
|
+
? `${t('printing.noMatches', 'No matches for')} "${search}"`
|
|
239
|
+
: t('printing.noTemplates', 'No templates yet.')}
|
|
215
240
|
</span>
|
|
216
241
|
</div>
|
|
217
242
|
)}
|
|
@@ -10,7 +10,11 @@
|
|
|
10
10
|
overflow: hidden;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
.dark {
|
|
13
|
+
.dark {
|
|
14
|
+
background: var(--nice-bg-primary, #0f172a);
|
|
15
|
+
color: var(--nice-text-secondary, #e2e8f0);
|
|
16
|
+
border-color: var(--nice-border-color, #1e293b);
|
|
17
|
+
}
|
|
14
18
|
|
|
15
19
|
/* ── Top bar ── */
|
|
16
20
|
.topBar {
|
|
@@ -18,12 +22,15 @@
|
|
|
18
22
|
align-items: center;
|
|
19
23
|
gap: var(--nice-space-2, 8px);
|
|
20
24
|
padding: var(--nice-space-2-5, 10px) var(--nice-space-3, 12px);
|
|
21
|
-
background: var(--nice-bg, #
|
|
25
|
+
background: var(--nice-bg, #fff);
|
|
22
26
|
border-bottom: 1px solid var(--nice-border, #e2e8f0);
|
|
23
27
|
flex-shrink: 0;
|
|
24
28
|
}
|
|
25
29
|
|
|
26
|
-
.dark .topBar {
|
|
30
|
+
.dark .topBar {
|
|
31
|
+
background: var(--nice-bg-secondary, #1e293b);
|
|
32
|
+
border-bottom-color: var(--nice-border-color, #334155);
|
|
33
|
+
}
|
|
27
34
|
|
|
28
35
|
.searchInput {
|
|
29
36
|
flex: 1;
|
|
@@ -36,14 +43,21 @@
|
|
|
36
43
|
outline: none;
|
|
37
44
|
}
|
|
38
45
|
|
|
39
|
-
.searchInput:focus {
|
|
40
|
-
|
|
46
|
+
.searchInput:focus {
|
|
47
|
+
border-color: var(--nice-primary-light, #93c5fd);
|
|
48
|
+
background: var(--nice-bg, #fff);
|
|
49
|
+
}
|
|
50
|
+
.dark .searchInput {
|
|
51
|
+
background: var(--nice-bg-tertiary, #334155);
|
|
52
|
+
border-color: var(--nice-border-color, #475569);
|
|
53
|
+
color: var(--nice-text-secondary, #e2e8f0);
|
|
54
|
+
}
|
|
41
55
|
|
|
42
56
|
.actionBtn {
|
|
43
57
|
padding: var(--nice-space-1-5, 6px) var(--nice-space-3, 12px);
|
|
44
58
|
border: 1px solid var(--nice-border, #e2e8f0);
|
|
45
59
|
border-radius: var(--nice-radius-md, 6px);
|
|
46
|
-
background: var(--nice-bg, #
|
|
60
|
+
background: var(--nice-bg, #fff);
|
|
47
61
|
cursor: pointer;
|
|
48
62
|
font-size: 12px;
|
|
49
63
|
font-weight: 500;
|
|
@@ -52,8 +66,14 @@
|
|
|
52
66
|
transition: all 0.1s;
|
|
53
67
|
}
|
|
54
68
|
|
|
55
|
-
.actionBtn:hover {
|
|
56
|
-
|
|
69
|
+
.actionBtn:hover {
|
|
70
|
+
background: var(--nice-bg-secondary, #f1f5f9);
|
|
71
|
+
}
|
|
72
|
+
.dark .actionBtn {
|
|
73
|
+
background: var(--nice-bg-tertiary, #334155);
|
|
74
|
+
border-color: var(--nice-border-color, #475569);
|
|
75
|
+
color: var(--nice-text-secondary, #e2e8f0);
|
|
76
|
+
}
|
|
57
77
|
|
|
58
78
|
/* ── Categories ── */
|
|
59
79
|
.categoryRow {
|
|
@@ -63,28 +83,33 @@
|
|
|
63
83
|
border-bottom: 1px solid var(--nice-bg-secondary, #f1f5f9);
|
|
64
84
|
flex-wrap: wrap;
|
|
65
85
|
flex-shrink: 0;
|
|
66
|
-
background: var(--nice-bg, #
|
|
86
|
+
background: var(--nice-bg, #fff);
|
|
67
87
|
}
|
|
68
88
|
|
|
69
|
-
.dark .categoryRow {
|
|
89
|
+
.dark .categoryRow {
|
|
90
|
+
background: var(--nice-bg-secondary, #1e293b);
|
|
91
|
+
border-bottom-color: var(--nice-border-color, #334155);
|
|
92
|
+
}
|
|
70
93
|
|
|
71
94
|
.catChip {
|
|
72
95
|
padding: var(--nice-space-0-75, 3px) var(--nice-space-2-5, 10px);
|
|
73
96
|
border: 1px solid var(--nice-border, #e2e8f0);
|
|
74
97
|
border-radius: var(--nice-radius-xl, 14px);
|
|
75
|
-
background: var(--nice-bg, #
|
|
98
|
+
background: var(--nice-bg, #fff);
|
|
76
99
|
cursor: pointer;
|
|
77
100
|
font-size: 12px;
|
|
78
101
|
color: var(--nice-text-secondary, #64748b);
|
|
79
102
|
transition: all 0.1s;
|
|
80
103
|
}
|
|
81
104
|
|
|
82
|
-
.catChip:hover {
|
|
105
|
+
.catChip:hover {
|
|
106
|
+
background: var(--nice-bg-secondary, #f1f5f9);
|
|
107
|
+
}
|
|
83
108
|
|
|
84
109
|
.catChipActive {
|
|
85
110
|
background: var(--nice-primary-hover, #2563eb);
|
|
86
111
|
border-color: var(--nice-primary-hover, #2563eb);
|
|
87
|
-
color: var(--nice-
|
|
112
|
+
color: var(--nice-text-on-primary, #fff);
|
|
88
113
|
}
|
|
89
114
|
|
|
90
115
|
/* ── Template grid ── */
|
|
@@ -102,7 +127,7 @@
|
|
|
102
127
|
.card {
|
|
103
128
|
flex: 0 0 auto;
|
|
104
129
|
width: 180px;
|
|
105
|
-
background: var(--nice-bg, #
|
|
130
|
+
background: var(--nice-bg, #fff);
|
|
106
131
|
border: 2px solid var(--nice-border, #e2e8f0);
|
|
107
132
|
border-radius: var(--nice-radius-lg, 8px);
|
|
108
133
|
overflow: hidden;
|
|
@@ -120,7 +145,10 @@
|
|
|
120
145
|
box-shadow: 0 0 0 3px var(--nice-primary-tint-15, rgba(37, 99, 235, 0.15));
|
|
121
146
|
}
|
|
122
147
|
|
|
123
|
-
.dark .card {
|
|
148
|
+
.dark .card {
|
|
149
|
+
background: var(--nice-bg-secondary, #1e293b);
|
|
150
|
+
border-color: var(--nice-border-color, #334155);
|
|
151
|
+
}
|
|
124
152
|
|
|
125
153
|
/* Thumbnail */
|
|
126
154
|
.thumbnail {
|
|
@@ -145,7 +173,7 @@
|
|
|
145
173
|
|
|
146
174
|
.paperMini {
|
|
147
175
|
width: 70px;
|
|
148
|
-
background: var(--nice-bg, #
|
|
176
|
+
background: var(--nice-bg, #fff);
|
|
149
177
|
border: 1px solid var(--nice-border, #e2e8f0);
|
|
150
178
|
border-radius: var(--nice-radius-sm, 2px);
|
|
151
179
|
padding: var(--nice-space-2, 8px) var(--nice-space-1-5, 6px);
|
|
@@ -175,7 +203,7 @@
|
|
|
175
203
|
.overlayBtn {
|
|
176
204
|
width: 32px;
|
|
177
205
|
height: 32px;
|
|
178
|
-
background: var(--nice-bg, #
|
|
206
|
+
background: var(--nice-bg, #fff);
|
|
179
207
|
border: none;
|
|
180
208
|
border-radius: var(--nice-radius-full, 50%);
|
|
181
209
|
cursor: pointer;
|
|
@@ -186,11 +214,16 @@
|
|
|
186
214
|
transition: all 0.1s;
|
|
187
215
|
}
|
|
188
216
|
|
|
189
|
-
.overlayBtn:hover {
|
|
217
|
+
.overlayBtn:hover {
|
|
218
|
+
background: var(--nice-primary-bg, #e0f2fe);
|
|
219
|
+
}
|
|
190
220
|
|
|
191
221
|
.overlayBtnDanger {
|
|
192
|
-
width: 28px;
|
|
193
|
-
|
|
222
|
+
width: 28px;
|
|
223
|
+
height: 28px;
|
|
224
|
+
display: flex;
|
|
225
|
+
align-items: center;
|
|
226
|
+
justify-content: center;
|
|
194
227
|
background: var(--nice-overlay-light-90, rgba(255, 255, 255, 0.9));
|
|
195
228
|
border: 1px solid var(--nice-border, #e2e8f0);
|
|
196
229
|
border-radius: var(--nice-radius-md, 6px);
|
|
@@ -200,10 +233,14 @@
|
|
|
200
233
|
transition: all 0.1s;
|
|
201
234
|
}
|
|
202
235
|
|
|
203
|
-
.overlayBtnDanger:hover {
|
|
236
|
+
.overlayBtnDanger:hover {
|
|
237
|
+
background: var(--nice-danger-bg, #fee2e2) !important;
|
|
238
|
+
}
|
|
204
239
|
|
|
205
240
|
/* Card body */
|
|
206
|
-
.cardBody {
|
|
241
|
+
.cardBody {
|
|
242
|
+
padding: var(--nice-space-2, 8px) var(--nice-space-2-5, 10px);
|
|
243
|
+
}
|
|
207
244
|
|
|
208
245
|
.cardName {
|
|
209
246
|
font-weight: 600;
|
|
@@ -215,7 +252,9 @@
|
|
|
215
252
|
margin-bottom: var(--nice-space-0-5, 2px);
|
|
216
253
|
}
|
|
217
254
|
|
|
218
|
-
.dark .cardName {
|
|
255
|
+
.dark .cardName {
|
|
256
|
+
color: var(--nice-text-primary, #f1f5f9);
|
|
257
|
+
}
|
|
219
258
|
|
|
220
259
|
.cardDesc {
|
|
221
260
|
font-size: 11px;
|
|
@@ -251,7 +290,11 @@
|
|
|
251
290
|
border-radius: var(--nice-radius-sm, 4px);
|
|
252
291
|
}
|
|
253
292
|
|
|
254
|
-
.cardTags {
|
|
293
|
+
.cardTags {
|
|
294
|
+
display: flex;
|
|
295
|
+
gap: var(--nice-space-0-75, 3px);
|
|
296
|
+
flex-wrap: wrap;
|
|
297
|
+
}
|
|
255
298
|
|
|
256
299
|
.cardTag {
|
|
257
300
|
font-size: 9px;
|
|
@@ -274,4 +317,6 @@
|
|
|
274
317
|
font-size: 14px;
|
|
275
318
|
}
|
|
276
319
|
|
|
277
|
-
.emptyIcon {
|
|
320
|
+
.emptyIcon {
|
|
321
|
+
font-size: 40px;
|
|
322
|
+
}
|