@emailshepherd/cli 0.1.26 → 0.1.36
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/cli.js +271 -467
- package/dist/templates/devWrapper.html +281 -0
- package/dist/types.d.ts +5 -289
- package/package.json +14 -10
- package/templates/AGENTS.md +0 -163
- package/templates/README.md +0 -115
- package/templates/claude/CLAUDE.md +0 -1
- package/templates/claude/settings.local.json +0 -8
- package/templates/gitignore +0 -6
- package/templates/package.json +0 -13
- package/templates/src/vite-env.d.ts +0 -6
- package/templates/tsconfig.json +0 -12
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>EmailShepherd Dev</title>
|
|
7
|
+
<style>
|
|
8
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
9
|
+
html, body { height: 100%; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; }
|
|
10
|
+
.container { display: flex; height: 100%; }
|
|
11
|
+
.panel {
|
|
12
|
+
width: 320px;
|
|
13
|
+
background: #1a1a1a;
|
|
14
|
+
color: #e0e0e0;
|
|
15
|
+
padding: 16px;
|
|
16
|
+
overflow-y: auto;
|
|
17
|
+
border-right: 1px solid #333;
|
|
18
|
+
flex-shrink: 0;
|
|
19
|
+
}
|
|
20
|
+
.panel-header {
|
|
21
|
+
margin-bottom: 16px;
|
|
22
|
+
padding-bottom: 16px;
|
|
23
|
+
border-bottom: 1px solid #333;
|
|
24
|
+
}
|
|
25
|
+
.panel-header h2 { font-size: 14px; color: #fff; margin-bottom: 6px; }
|
|
26
|
+
.panel-header p { font-size: 12px; color: #888; line-height: 1.4; }
|
|
27
|
+
.reset-btn {
|
|
28
|
+
margin-top: 12px;
|
|
29
|
+
padding: 6px 12px;
|
|
30
|
+
background: #333;
|
|
31
|
+
border: 1px solid #444;
|
|
32
|
+
border-radius: 4px;
|
|
33
|
+
color: #ccc;
|
|
34
|
+
font-size: 12px;
|
|
35
|
+
cursor: pointer;
|
|
36
|
+
}
|
|
37
|
+
.reset-btn:hover { background: #444; color: #fff; }
|
|
38
|
+
.reset-btn:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
39
|
+
.component-section { margin-bottom: 8px; }
|
|
40
|
+
.component-header {
|
|
41
|
+
display: flex;
|
|
42
|
+
align-items: center;
|
|
43
|
+
justify-content: space-between;
|
|
44
|
+
padding: 10px 0;
|
|
45
|
+
cursor: pointer;
|
|
46
|
+
border-bottom: 1px solid #333;
|
|
47
|
+
user-select: none;
|
|
48
|
+
}
|
|
49
|
+
.component-header h3 {
|
|
50
|
+
font-size: 12px;
|
|
51
|
+
text-transform: uppercase;
|
|
52
|
+
letter-spacing: 0.5px;
|
|
53
|
+
color: #888;
|
|
54
|
+
margin: 0;
|
|
55
|
+
}
|
|
56
|
+
.component-header:hover h3 { color: #aaa; }
|
|
57
|
+
.collapse-icon {
|
|
58
|
+
font-size: 10px;
|
|
59
|
+
color: #666;
|
|
60
|
+
transition: transform 0.2s;
|
|
61
|
+
}
|
|
62
|
+
.component-section.collapsed .collapse-icon { transform: rotate(-90deg); }
|
|
63
|
+
.component-section.collapsed .component-fields { display: none; }
|
|
64
|
+
.component-fields { padding: 12px 0; }
|
|
65
|
+
.field { margin-bottom: 12px; }
|
|
66
|
+
.field label {
|
|
67
|
+
display: block;
|
|
68
|
+
font-size: 12px;
|
|
69
|
+
color: #aaa;
|
|
70
|
+
margin-bottom: 4px;
|
|
71
|
+
}
|
|
72
|
+
.field input, .field select {
|
|
73
|
+
width: 100%;
|
|
74
|
+
padding: 8px;
|
|
75
|
+
border: 1px solid #444;
|
|
76
|
+
border-radius: 4px;
|
|
77
|
+
background: #2a2a2a;
|
|
78
|
+
color: #fff;
|
|
79
|
+
font-size: 13px;
|
|
80
|
+
}
|
|
81
|
+
.field input:focus, .field select:focus {
|
|
82
|
+
outline: none;
|
|
83
|
+
border-color: #666;
|
|
84
|
+
}
|
|
85
|
+
.field input[type="checkbox"] {
|
|
86
|
+
width: auto;
|
|
87
|
+
margin-right: 8px;
|
|
88
|
+
}
|
|
89
|
+
.checkbox-label {
|
|
90
|
+
display: flex;
|
|
91
|
+
align-items: center;
|
|
92
|
+
cursor: pointer;
|
|
93
|
+
}
|
|
94
|
+
.preview { flex: 1; background: #fff; position: relative; }
|
|
95
|
+
.preview iframe { width: 100%; height: 100%; border: none; }
|
|
96
|
+
.loading-overlay {
|
|
97
|
+
display: none;
|
|
98
|
+
position: absolute;
|
|
99
|
+
top: 0;
|
|
100
|
+
left: 0;
|
|
101
|
+
right: 0;
|
|
102
|
+
bottom: 0;
|
|
103
|
+
background: rgba(255,255,255,0.8);
|
|
104
|
+
justify-content: center;
|
|
105
|
+
align-items: center;
|
|
106
|
+
z-index: 10;
|
|
107
|
+
}
|
|
108
|
+
.loading-overlay.visible { display: flex; }
|
|
109
|
+
.spinner {
|
|
110
|
+
width: 32px;
|
|
111
|
+
height: 32px;
|
|
112
|
+
border: 3px solid #ddd;
|
|
113
|
+
border-top-color: #333;
|
|
114
|
+
border-radius: 50%;
|
|
115
|
+
animation: spin 0.8s linear infinite;
|
|
116
|
+
}
|
|
117
|
+
@keyframes spin { to { transform: rotate(360deg); } }
|
|
118
|
+
</style>
|
|
119
|
+
</head>
|
|
120
|
+
<body>
|
|
121
|
+
<div class="container">
|
|
122
|
+
<div class="panel" id="panel">
|
|
123
|
+
<div class="panel-header">
|
|
124
|
+
<h2>Preview Values</h2>
|
|
125
|
+
<p>Adjust field values to preview how your components will look with different content.</p>
|
|
126
|
+
<button class="reset-btn" id="reset-btn">Reset All</button>
|
|
127
|
+
</div>
|
|
128
|
+
<div id="fields-container"></div>
|
|
129
|
+
</div>
|
|
130
|
+
<div class="preview">
|
|
131
|
+
<div class="loading-overlay" id="loading-overlay"><div class="spinner"></div></div>
|
|
132
|
+
<iframe id="preview-frame" src="./rendered.html"></iframe>
|
|
133
|
+
</div>
|
|
134
|
+
</div>
|
|
135
|
+
<script>
|
|
136
|
+
let fieldsManifest = null;
|
|
137
|
+
let overrides = {};
|
|
138
|
+
let debounceTimer = null;
|
|
139
|
+
let collapsedSections = {};
|
|
140
|
+
|
|
141
|
+
async function loadFields() {
|
|
142
|
+
const res = await fetch('./fields.json');
|
|
143
|
+
fieldsManifest = await res.json();
|
|
144
|
+
renderForm();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function renderForm() {
|
|
148
|
+
const container = document.getElementById('fields-container');
|
|
149
|
+
container.innerHTML = '';
|
|
150
|
+
|
|
151
|
+
// Container component
|
|
152
|
+
container.appendChild(createComponentSection(fieldsManifest.container_component));
|
|
153
|
+
|
|
154
|
+
// Regular components
|
|
155
|
+
for (const component of fieldsManifest.components) {
|
|
156
|
+
container.appendChild(createComponentSection(component));
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function createComponentSection(component) {
|
|
161
|
+
const section = document.createElement('div');
|
|
162
|
+
section.className = 'component-section';
|
|
163
|
+
// Collapsed by default unless explicitly expanded
|
|
164
|
+
if (collapsedSections[component.name] !== false) {
|
|
165
|
+
section.classList.add('collapsed');
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const header = document.createElement('div');
|
|
169
|
+
header.className = 'component-header';
|
|
170
|
+
header.innerHTML = '<h3>' + escapeHtml(component.label) + '</h3><span class="collapse-icon">▼</span>';
|
|
171
|
+
header.addEventListener('click', () => {
|
|
172
|
+
section.classList.toggle('collapsed');
|
|
173
|
+
collapsedSections[component.name] = !section.classList.contains('collapsed');
|
|
174
|
+
});
|
|
175
|
+
section.appendChild(header);
|
|
176
|
+
|
|
177
|
+
const fields = document.createElement('div');
|
|
178
|
+
fields.className = 'component-fields';
|
|
179
|
+
for (const field of component.fields) {
|
|
180
|
+
fields.appendChild(createFieldInput(component.name, field));
|
|
181
|
+
}
|
|
182
|
+
section.appendChild(fields);
|
|
183
|
+
|
|
184
|
+
return section;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function createFieldInput(componentName, field) {
|
|
188
|
+
const div = document.createElement('div');
|
|
189
|
+
div.className = 'field';
|
|
190
|
+
|
|
191
|
+
const defaultValue = field.default_value;
|
|
192
|
+
const currentValue = overrides[componentName]?.[field.liquid_variable] ?? defaultValue;
|
|
193
|
+
|
|
194
|
+
if (field.type === 'boolean') {
|
|
195
|
+
const id = componentName + '_' + field.liquid_variable;
|
|
196
|
+
div.innerHTML = '<label class="checkbox-label"><input type="checkbox" id="' + id + '" ' + (currentValue ? 'checked' : '') + '> ' + escapeHtml(field.label) + '</label>';
|
|
197
|
+
const input = div.querySelector('input');
|
|
198
|
+
input.addEventListener('change', () => handleChange(componentName, field.liquid_variable, input.checked));
|
|
199
|
+
} else if (field.type === 'enum') {
|
|
200
|
+
div.innerHTML = '<label>' + escapeHtml(field.label) + '</label>';
|
|
201
|
+
const select = document.createElement('select');
|
|
202
|
+
for (const opt of field.options) {
|
|
203
|
+
const option = document.createElement('option');
|
|
204
|
+
option.value = opt.value;
|
|
205
|
+
option.textContent = opt.label;
|
|
206
|
+
if (opt.value === currentValue) option.selected = true;
|
|
207
|
+
select.appendChild(option);
|
|
208
|
+
}
|
|
209
|
+
select.addEventListener('change', () => handleChange(componentName, field.liquid_variable, select.value));
|
|
210
|
+
div.appendChild(select);
|
|
211
|
+
} else if (field.type === 'number') {
|
|
212
|
+
div.innerHTML = '<label>' + escapeHtml(field.label) + '</label><input type="number" value="' + escapeHtml(String(currentValue)) + '">';
|
|
213
|
+
const input = div.querySelector('input');
|
|
214
|
+
input.addEventListener('input', () => handleChange(componentName, field.liquid_variable, parseFloat(input.value) || 0));
|
|
215
|
+
} else {
|
|
216
|
+
div.innerHTML = '<label>' + escapeHtml(field.label) + '</label><input type="text" value="' + escapeHtml(String(currentValue)) + '">';
|
|
217
|
+
const input = div.querySelector('input');
|
|
218
|
+
input.addEventListener('input', () => handleChange(componentName, field.liquid_variable, input.value));
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return div;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function handleChange(componentName, fieldName, value) {
|
|
225
|
+
if (!overrides[componentName]) overrides[componentName] = {};
|
|
226
|
+
overrides[componentName][fieldName] = value;
|
|
227
|
+
|
|
228
|
+
clearTimeout(debounceTimer);
|
|
229
|
+
debounceTimer = setTimeout(updatePreview, 300);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function resetAll() {
|
|
233
|
+
overrides = {};
|
|
234
|
+
renderForm();
|
|
235
|
+
const frame = document.getElementById('preview-frame');
|
|
236
|
+
frame.removeAttribute('srcdoc');
|
|
237
|
+
frame.src = './rendered.html';
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function setLoading(loading) {
|
|
241
|
+
const overlay = document.getElementById('loading-overlay');
|
|
242
|
+
if (loading) {
|
|
243
|
+
overlay.classList.add('visible');
|
|
244
|
+
} else {
|
|
245
|
+
overlay.classList.remove('visible');
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
async function updatePreview() {
|
|
250
|
+
setLoading(true);
|
|
251
|
+
|
|
252
|
+
try {
|
|
253
|
+
const res = await fetch('/api/render', {
|
|
254
|
+
method: 'POST',
|
|
255
|
+
headers: { 'Content-Type': 'application/json' },
|
|
256
|
+
body: JSON.stringify(overrides),
|
|
257
|
+
});
|
|
258
|
+
const data = await res.json();
|
|
259
|
+
|
|
260
|
+
if (data.html) {
|
|
261
|
+
const frame = document.getElementById('preview-frame');
|
|
262
|
+
frame.srcdoc = data.html;
|
|
263
|
+
} else if (data.error) {
|
|
264
|
+
console.error('Render error:', data.error);
|
|
265
|
+
}
|
|
266
|
+
} catch (err) {
|
|
267
|
+
console.error('Failed to update preview:', err);
|
|
268
|
+
} finally {
|
|
269
|
+
setLoading(false);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function escapeHtml(str) {
|
|
274
|
+
return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
document.getElementById('reset-btn').addEventListener('click', resetAll);
|
|
278
|
+
loadFields();
|
|
279
|
+
</script>
|
|
280
|
+
</body>
|
|
281
|
+
</html>
|
package/dist/types.d.ts
CHANGED
|
@@ -1,294 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*/
|
|
4
|
-
type DesignTokens = {
|
|
5
|
-
[key: string]: unknown;
|
|
6
|
-
} | null;
|
|
7
|
-
interface RichTextCustomStyle {
|
|
8
|
-
style: string;
|
|
9
|
-
name: string;
|
|
10
|
-
label: string;
|
|
11
|
-
}
|
|
12
|
-
type FieldDefinition = TextFieldDefinition | NumberFieldDefinition | EnumFieldDefinition | BooleanFieldDefinition | UrlFieldDefinition | ImageFieldDefinition | ColorFieldDefinition | RichTextFieldDefinition | CodeFieldDefinition;
|
|
13
|
-
interface Component {
|
|
14
|
-
id: number;
|
|
15
|
-
name: string;
|
|
16
|
-
label: string;
|
|
17
|
-
/** @nullable */
|
|
18
|
-
description: string | null;
|
|
19
|
-
email_design_system_id: number;
|
|
20
|
-
updated_at: string;
|
|
21
|
-
created_at: string;
|
|
22
|
-
/** @nullable */
|
|
23
|
-
container?: boolean | null;
|
|
24
|
-
template: string;
|
|
25
|
-
field_definitions: FieldDefinition[];
|
|
26
|
-
screenshot_url: string;
|
|
27
|
-
/** @nullable */
|
|
28
|
-
position: number | null;
|
|
29
|
-
/** @nullable */
|
|
30
|
-
last_updated_by: UserReference;
|
|
31
|
-
/** @nullable */
|
|
32
|
-
feed_id: number | null;
|
|
33
|
-
deprecated: boolean;
|
|
34
|
-
}
|
|
35
|
-
type TextFieldDefinitionType = typeof TextFieldDefinitionType[keyof typeof TextFieldDefinitionType];
|
|
36
|
-
declare const TextFieldDefinitionType: {
|
|
37
|
-
readonly text: "text";
|
|
38
|
-
};
|
|
39
|
-
type TextFieldDefinitionValidations = {
|
|
40
|
-
min_length?: number;
|
|
41
|
-
max_length?: number;
|
|
42
|
-
must_not_be_blank?: boolean;
|
|
43
|
-
must_not_be_default?: boolean;
|
|
44
|
-
};
|
|
45
|
-
interface TextFieldDefinition {
|
|
46
|
-
type: TextFieldDefinitionType;
|
|
47
|
-
label: string;
|
|
48
|
-
/** @nullable */
|
|
49
|
-
group?: string | null;
|
|
50
|
-
liquid_variable: string;
|
|
51
|
-
visible_if?: string;
|
|
52
|
-
default_value: string;
|
|
53
|
-
validations?: TextFieldDefinitionValidations;
|
|
54
|
-
hint?: string;
|
|
55
|
-
hidden_in_editor?: boolean;
|
|
56
|
-
hidden_from_ai?: boolean;
|
|
57
|
-
/** @nullable */
|
|
58
|
-
feed_field_name?: string | null;
|
|
59
|
-
}
|
|
60
|
-
type NumberFieldDefinitionType = typeof NumberFieldDefinitionType[keyof typeof NumberFieldDefinitionType];
|
|
61
|
-
declare const NumberFieldDefinitionType: {
|
|
62
|
-
readonly number: "number";
|
|
63
|
-
};
|
|
64
|
-
type NumberFieldDefinitionValidations = {
|
|
65
|
-
min?: number;
|
|
66
|
-
max?: number;
|
|
67
|
-
};
|
|
68
|
-
interface NumberFieldDefinition {
|
|
69
|
-
type: NumberFieldDefinitionType;
|
|
70
|
-
label: string;
|
|
71
|
-
/** @nullable */
|
|
72
|
-
group?: string | null;
|
|
73
|
-
liquid_variable: string;
|
|
74
|
-
visible_if?: string;
|
|
75
|
-
default_value: number;
|
|
76
|
-
validations?: NumberFieldDefinitionValidations;
|
|
77
|
-
hint?: string;
|
|
78
|
-
hidden_in_editor?: boolean;
|
|
79
|
-
hidden_from_ai?: boolean;
|
|
80
|
-
/** @nullable */
|
|
81
|
-
feed_field_name?: string | null;
|
|
82
|
-
}
|
|
83
|
-
type EnumFieldDefinitionType = typeof EnumFieldDefinitionType[keyof typeof EnumFieldDefinitionType];
|
|
84
|
-
declare const EnumFieldDefinitionType: {
|
|
85
|
-
readonly enum: "enum";
|
|
86
|
-
};
|
|
87
|
-
type EnumFieldDefinitionValidations = {
|
|
88
|
-
[key: string]: unknown;
|
|
89
|
-
};
|
|
90
|
-
type EnumFieldDefinitionOptionsItem = {
|
|
91
|
-
label: string;
|
|
92
|
-
value: string;
|
|
93
|
-
/** @nullable */
|
|
94
|
-
icon_url?: string | null;
|
|
95
|
-
};
|
|
96
|
-
interface EnumFieldDefinition {
|
|
97
|
-
type: EnumFieldDefinitionType;
|
|
98
|
-
label: string;
|
|
99
|
-
/** @nullable */
|
|
100
|
-
group?: string | null;
|
|
101
|
-
liquid_variable: string;
|
|
102
|
-
visible_if?: string;
|
|
103
|
-
default_value: string;
|
|
104
|
-
validations?: EnumFieldDefinitionValidations;
|
|
105
|
-
options: EnumFieldDefinitionOptionsItem[];
|
|
106
|
-
hint?: string;
|
|
107
|
-
hidden_in_editor?: boolean;
|
|
108
|
-
hidden_from_ai?: boolean;
|
|
109
|
-
/** @nullable */
|
|
110
|
-
feed_field_name?: string | null;
|
|
111
|
-
}
|
|
112
|
-
type BooleanFieldDefinitionType = typeof BooleanFieldDefinitionType[keyof typeof BooleanFieldDefinitionType];
|
|
113
|
-
declare const BooleanFieldDefinitionType: {
|
|
114
|
-
readonly boolean: "boolean";
|
|
115
|
-
};
|
|
116
|
-
type BooleanFieldDefinitionValidations = {
|
|
117
|
-
[key: string]: unknown;
|
|
118
|
-
};
|
|
119
|
-
interface BooleanFieldDefinition {
|
|
120
|
-
type: BooleanFieldDefinitionType;
|
|
121
|
-
label: string;
|
|
122
|
-
/** @nullable */
|
|
123
|
-
group?: string | null;
|
|
124
|
-
liquid_variable: string;
|
|
125
|
-
visible_if?: string;
|
|
126
|
-
default_value: boolean;
|
|
127
|
-
validations?: BooleanFieldDefinitionValidations;
|
|
128
|
-
hint?: string;
|
|
129
|
-
hidden_in_editor?: boolean;
|
|
130
|
-
hidden_from_ai?: boolean;
|
|
131
|
-
/** @nullable */
|
|
132
|
-
feed_field_name?: string | null;
|
|
133
|
-
}
|
|
134
|
-
type UrlFieldDefinitionType = typeof UrlFieldDefinitionType[keyof typeof UrlFieldDefinitionType];
|
|
135
|
-
declare const UrlFieldDefinitionType: {
|
|
136
|
-
readonly url: "url";
|
|
137
|
-
};
|
|
138
|
-
type UrlFieldDefinitionValidations = {
|
|
139
|
-
must_not_be_blank?: boolean;
|
|
140
|
-
must_not_be_default?: boolean;
|
|
141
|
-
};
|
|
142
|
-
interface UrlFieldDefinition {
|
|
143
|
-
type: UrlFieldDefinitionType;
|
|
144
|
-
label: string;
|
|
145
|
-
/** @nullable */
|
|
146
|
-
group?: string | null;
|
|
147
|
-
liquid_variable: string;
|
|
148
|
-
visible_if?: string;
|
|
149
|
-
default_value: string;
|
|
150
|
-
validations?: UrlFieldDefinitionValidations;
|
|
151
|
-
hint?: string;
|
|
152
|
-
hidden_in_editor?: boolean;
|
|
153
|
-
hidden_from_ai?: boolean;
|
|
154
|
-
/** @nullable */
|
|
155
|
-
feed_field_name?: string | null;
|
|
156
|
-
/** @nullable */
|
|
157
|
-
skip_link_tracking?: boolean | null;
|
|
158
|
-
}
|
|
159
|
-
type ImageFieldDefinitionType = typeof ImageFieldDefinitionType[keyof typeof ImageFieldDefinitionType];
|
|
160
|
-
declare const ImageFieldDefinitionType: {
|
|
161
|
-
readonly image: "image";
|
|
162
|
-
};
|
|
163
|
-
type ImageFieldDefinitionValidations = {
|
|
164
|
-
must_not_be_blank?: boolean;
|
|
165
|
-
must_not_be_default?: boolean;
|
|
166
|
-
};
|
|
167
|
-
interface ImageFieldDefinition {
|
|
168
|
-
type: ImageFieldDefinitionType;
|
|
169
|
-
label: string;
|
|
170
|
-
/** @nullable */
|
|
171
|
-
group?: string | null;
|
|
172
|
-
liquid_variable: string;
|
|
173
|
-
visible_if?: string;
|
|
174
|
-
default_value: string;
|
|
175
|
-
validations?: ImageFieldDefinitionValidations;
|
|
176
|
-
hint?: string;
|
|
177
|
-
hidden_in_editor?: boolean;
|
|
178
|
-
hidden_from_ai?: boolean;
|
|
179
|
-
/** @nullable */
|
|
180
|
-
feed_field_name?: string | null;
|
|
181
|
-
}
|
|
182
|
-
type ColorFieldDefinitionType = typeof ColorFieldDefinitionType[keyof typeof ColorFieldDefinitionType];
|
|
183
|
-
declare const ColorFieldDefinitionType: {
|
|
184
|
-
readonly color: "color";
|
|
185
|
-
};
|
|
186
|
-
type ColorFieldDefinitionValidations = {
|
|
187
|
-
[key: string]: unknown;
|
|
188
|
-
};
|
|
189
|
-
interface ColorFieldDefinition {
|
|
190
|
-
type: ColorFieldDefinitionType;
|
|
191
|
-
label: string;
|
|
192
|
-
/** @nullable */
|
|
193
|
-
group?: string | null;
|
|
194
|
-
liquid_variable: string;
|
|
195
|
-
visible_if?: string;
|
|
196
|
-
default_value: string;
|
|
197
|
-
validations?: ColorFieldDefinitionValidations;
|
|
198
|
-
hint?: string;
|
|
199
|
-
hidden_in_editor?: boolean;
|
|
200
|
-
hidden_from_ai?: boolean;
|
|
201
|
-
/** @nullable */
|
|
202
|
-
feed_field_name?: string | null;
|
|
203
|
-
}
|
|
204
|
-
type RichTextFieldDefinitionType = typeof RichTextFieldDefinitionType[keyof typeof RichTextFieldDefinitionType];
|
|
205
|
-
declare const RichTextFieldDefinitionType: {
|
|
206
|
-
readonly rich_text: "rich_text";
|
|
207
|
-
};
|
|
208
|
-
type RichTextFieldDefinitionValidations = {
|
|
209
|
-
max_content_length?: number;
|
|
210
|
-
min_content_length?: number;
|
|
211
|
-
must_not_be_blank?: boolean;
|
|
212
|
-
must_not_be_default?: boolean;
|
|
213
|
-
};
|
|
214
|
-
type RichTextFieldDefinitionMarksBold = {
|
|
215
|
-
enabled: boolean;
|
|
216
|
-
};
|
|
217
|
-
type RichTextFieldDefinitionMarksItalic = {
|
|
218
|
-
enabled: boolean;
|
|
219
|
-
};
|
|
220
|
-
type RichTextFieldDefinitionMarksLink = {
|
|
221
|
-
enabled: boolean;
|
|
222
|
-
};
|
|
223
|
-
type RichTextFieldDefinitionMarksBulletList = {
|
|
224
|
-
enabled: boolean;
|
|
225
|
-
};
|
|
226
|
-
type RichTextFieldDefinitionMarksNumberedList = {
|
|
227
|
-
enabled: boolean;
|
|
228
|
-
};
|
|
229
|
-
/**
|
|
230
|
-
* @nullable
|
|
231
|
-
*/
|
|
232
|
-
type RichTextFieldDefinitionMarks = {
|
|
233
|
-
bold: RichTextFieldDefinitionMarksBold;
|
|
234
|
-
italic: RichTextFieldDefinitionMarksItalic;
|
|
235
|
-
link: RichTextFieldDefinitionMarksLink;
|
|
236
|
-
bullet_list: RichTextFieldDefinitionMarksBulletList;
|
|
237
|
-
numbered_list: RichTextFieldDefinitionMarksNumberedList;
|
|
238
|
-
} | null;
|
|
239
|
-
interface RichTextFieldDefinition {
|
|
240
|
-
type: RichTextFieldDefinitionType;
|
|
241
|
-
label: string;
|
|
242
|
-
/** @nullable */
|
|
243
|
-
group?: string | null;
|
|
244
|
-
liquid_variable: string;
|
|
245
|
-
visible_if?: string;
|
|
246
|
-
default_value: string;
|
|
247
|
-
validations?: RichTextFieldDefinitionValidations;
|
|
248
|
-
hint?: string;
|
|
249
|
-
hidden_in_editor?: boolean;
|
|
250
|
-
hidden_from_ai?: boolean;
|
|
251
|
-
/** @nullable */
|
|
252
|
-
feed_field_name?: string | null;
|
|
253
|
-
/** @nullable */
|
|
254
|
-
marks: RichTextFieldDefinitionMarks;
|
|
255
|
-
/** @nullable */
|
|
256
|
-
custom_styles_names?: string[] | null;
|
|
257
|
-
}
|
|
258
|
-
type CodeFieldDefinitionType = typeof CodeFieldDefinitionType[keyof typeof CodeFieldDefinitionType];
|
|
259
|
-
declare const CodeFieldDefinitionType: {
|
|
260
|
-
readonly code: "code";
|
|
261
|
-
};
|
|
262
|
-
type CodeFieldDefinitionValidations = {
|
|
263
|
-
must_not_be_blank?: boolean;
|
|
264
|
-
must_not_be_default?: boolean;
|
|
265
|
-
};
|
|
266
|
-
interface CodeFieldDefinition {
|
|
267
|
-
type: CodeFieldDefinitionType;
|
|
268
|
-
label: string;
|
|
269
|
-
/** @nullable */
|
|
270
|
-
group?: string | null;
|
|
271
|
-
liquid_variable: string;
|
|
272
|
-
visible_if?: string;
|
|
273
|
-
default_value: string;
|
|
274
|
-
validations?: CodeFieldDefinitionValidations;
|
|
275
|
-
hint?: string;
|
|
276
|
-
hidden_in_editor?: boolean;
|
|
277
|
-
hidden_from_ai?: boolean;
|
|
278
|
-
/** @nullable */
|
|
279
|
-
feed_field_name?: string | null;
|
|
280
|
-
}
|
|
281
|
-
interface UserReference {
|
|
282
|
-
id: number;
|
|
283
|
-
first_name: string;
|
|
284
|
-
last_name: string;
|
|
285
|
-
/** @nullable */
|
|
286
|
-
profile_image_url: string | null;
|
|
287
|
-
}
|
|
1
|
+
import { Component, DesignTokens, RichTextCustomStyle } from '@emailshepherd/api-client';
|
|
2
|
+
export { DesignTokens, FieldDefinition, RichTextCustomStyle } from '@emailshepherd/api-client';
|
|
288
3
|
|
|
289
|
-
type ComponentDefinition = Omit<Component, "email_design_system_id" | "created_at" | "updated_at" | "screenshot_url" | "last_updated_by" | "container" | "position">;
|
|
4
|
+
type ComponentDefinition = Omit<Component, "id" | "email_design_system_id" | "created_at" | "updated_at" | "screenshot_url" | "last_updated_by" | "container" | "position">;
|
|
290
5
|
type EDSMetadata = {
|
|
291
6
|
name: string;
|
|
7
|
+
description: string;
|
|
292
8
|
design_tokens: DesignTokens;
|
|
293
9
|
custom_styles?: RichTextCustomStyle[];
|
|
294
10
|
};
|
|
@@ -321,4 +37,4 @@ declare function defineDesignTokens(tokens: DesignTokens): DesignTokens;
|
|
|
321
37
|
*/
|
|
322
38
|
declare function defineCustomStyles(styles: RichTextCustomStyle[]): RichTextCustomStyle[];
|
|
323
39
|
|
|
324
|
-
export { type ComponentDefinition, type
|
|
40
|
+
export { type ComponentDefinition, type EDSConfig, type EDSMetadata, defineComponent, defineCustomStyles, defineDesignTokens, defineEDS };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@emailshepherd/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.36",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"registry": "https://registry.npmjs.org",
|
|
@@ -16,27 +16,31 @@
|
|
|
16
16
|
}
|
|
17
17
|
},
|
|
18
18
|
"files": [
|
|
19
|
-
"dist"
|
|
20
|
-
"templates"
|
|
19
|
+
"dist"
|
|
21
20
|
],
|
|
22
21
|
"scripts": {
|
|
23
|
-
"build": "tsup src/
|
|
24
|
-
"
|
|
25
|
-
"
|
|
22
|
+
"build": "tsup && cp -r src/templates dist/",
|
|
23
|
+
"test": "vitest run",
|
|
24
|
+
"test:watch": "vitest",
|
|
25
|
+
"prepublishOnly": "pnpm run build"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@
|
|
28
|
+
"@emailshepherd/api-client": "workspace:*",
|
|
29
29
|
"axios": "^1.13.2",
|
|
30
30
|
"chokidar": "^4.0.3",
|
|
31
31
|
"commander": "^14.0.2",
|
|
32
32
|
"dotenv": "^17.2.3",
|
|
33
|
-
"
|
|
33
|
+
"update-notifier": "^7.3.1",
|
|
34
|
+
"vite": "^7.2.6",
|
|
35
|
+
"vite-plugin-checker": "^0.12.0"
|
|
34
36
|
},
|
|
35
37
|
"devDependencies": {
|
|
36
38
|
"@types/node": "^24.10.1",
|
|
37
|
-
"
|
|
39
|
+
"@types/update-notifier": "^6.0.8",
|
|
40
|
+
"msw": "^2.12.7",
|
|
38
41
|
"tsup": "^8.5.1",
|
|
39
42
|
"tsx": "^4.21.0",
|
|
40
|
-
"typescript": "^5.9.3"
|
|
43
|
+
"typescript": "^5.9.3",
|
|
44
|
+
"vitest": "^4.0.16"
|
|
41
45
|
}
|
|
42
46
|
}
|