@zenithbuild/core 0.1.0 → 0.3.1

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 (90) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +24 -40
  3. package/bin/zen-build.ts +2 -0
  4. package/bin/zen-dev.ts +2 -0
  5. package/bin/zen-preview.ts +2 -0
  6. package/bin/zenith.ts +2 -0
  7. package/cli/commands/add.ts +37 -0
  8. package/cli/commands/build.ts +37 -0
  9. package/cli/commands/create.ts +702 -0
  10. package/cli/commands/dev.ts +197 -0
  11. package/cli/commands/index.ts +112 -0
  12. package/cli/commands/preview.ts +62 -0
  13. package/cli/commands/remove.ts +33 -0
  14. package/cli/index.ts +10 -0
  15. package/cli/main.ts +101 -0
  16. package/cli/utils/branding.ts +153 -0
  17. package/cli/utils/logger.ts +40 -0
  18. package/cli/utils/plugin-manager.ts +114 -0
  19. package/cli/utils/project.ts +71 -0
  20. package/compiler/build-analyzer.ts +122 -0
  21. package/compiler/discovery/layouts.ts +61 -0
  22. package/compiler/index.ts +40 -24
  23. package/compiler/ir/types.ts +1 -0
  24. package/compiler/parse/parseScript.ts +29 -5
  25. package/compiler/parse/parseTemplate.ts +96 -58
  26. package/compiler/parse/scriptAnalysis.ts +77 -0
  27. package/compiler/runtime/dataExposure.ts +49 -31
  28. package/compiler/runtime/generateDOM.ts +18 -17
  29. package/compiler/runtime/generateHydrationBundle.ts +24 -5
  30. package/compiler/runtime/transformIR.ts +140 -49
  31. package/compiler/runtime/wrapExpressionWithLoop.ts +11 -11
  32. package/compiler/spa-build.ts +70 -153
  33. package/compiler/ssg-build.ts +412 -0
  34. package/compiler/transform/layoutProcessor.ts +132 -0
  35. package/compiler/transform/transformNode.ts +19 -19
  36. package/dist/cli.js +11648 -0
  37. package/dist/zen-build.js +11659 -0
  38. package/dist/zen-dev.js +11659 -0
  39. package/dist/zen-preview.js +11659 -0
  40. package/dist/zenith.js +11659 -0
  41. package/package.json +22 -2
  42. package/runtime/bundle-generator.ts +416 -0
  43. package/runtime/client-runtime.ts +532 -0
  44. package/.eslintignore +0 -15
  45. package/.gitattributes +0 -2
  46. package/.github/ISSUE_TEMPLATE/compiler-errors-for-invalid-state-declarations.md +0 -25
  47. package/.github/ISSUE_TEMPLATE/new_ticket.yaml +0 -34
  48. package/.github/pull_request_template.md +0 -15
  49. package/.github/workflows/discord-changelog.yml +0 -141
  50. package/.github/workflows/discord-notify.yml +0 -242
  51. package/.github/workflows/discord-version.yml +0 -195
  52. package/.prettierignore +0 -13
  53. package/.prettierrc +0 -21
  54. package/.zen.d.ts +0 -15
  55. package/app/components/Button.zen +0 -46
  56. package/app/components/Link.zen +0 -11
  57. package/app/favicon.ico +0 -0
  58. package/app/layouts/Main.zen +0 -59
  59. package/app/pages/about.zen +0 -23
  60. package/app/pages/blog/[id].zen +0 -53
  61. package/app/pages/blog/index.zen +0 -32
  62. package/app/pages/dynamic-dx.zen +0 -712
  63. package/app/pages/dynamic-primitives.zen +0 -453
  64. package/app/pages/index.zen +0 -154
  65. package/app/pages/navigation-demo.zen +0 -229
  66. package/app/pages/posts/[...slug].zen +0 -61
  67. package/app/pages/primitives-demo.zen +0 -273
  68. package/assets/logos/0E3B5DDD-605C-4839-BB2E-DFCA8ADC9604.PNG +0 -0
  69. package/assets/logos/760971E5-79A1-44F9-90B9-925DF30F4278.PNG +0 -0
  70. package/assets/logos/8A06ED80-9ED2-4689-BCBD-13B2E95EE8E4.JPG +0 -0
  71. package/assets/logos/C691FF58-ED13-4E8D-B6A3-02E835849340.PNG +0 -0
  72. package/assets/logos/C691FF58-ED13-4E8D-B6A3-02E835849340.svg +0 -601
  73. package/assets/logos/README.md +0 -54
  74. package/assets/logos/zen.icns +0 -0
  75. package/bun.lock +0 -39
  76. package/compiler/legacy/binding.ts +0 -254
  77. package/compiler/legacy/bindings.ts +0 -338
  78. package/compiler/legacy/component-process.ts +0 -1208
  79. package/compiler/legacy/component.ts +0 -301
  80. package/compiler/legacy/event.ts +0 -50
  81. package/compiler/legacy/expression.ts +0 -1149
  82. package/compiler/legacy/mutation.ts +0 -280
  83. package/compiler/legacy/parse.ts +0 -299
  84. package/compiler/legacy/split.ts +0 -608
  85. package/compiler/legacy/types.ts +0 -32
  86. package/docs/COMMENTS.md +0 -111
  87. package/docs/COMMITS.md +0 -36
  88. package/docs/CONTRIBUTING.md +0 -116
  89. package/docs/STYLEGUIDE.md +0 -62
  90. package/scripts/webhook-proxy.ts +0 -213
@@ -0,0 +1,532 @@
1
+ /**
2
+ * Zenith Client Runtime
3
+ *
4
+ * Shared runtime module served as /runtime.js in dev mode.
5
+ * Includes:
6
+ * - Reactivity primitives (signal, state, effect, memo)
7
+ * - Lifecycle hooks (zenOnMount, zenOnUnmount)
8
+ * - Event wiring
9
+ * - Hydration functions
10
+ *
11
+ * This is a standalone module that can be imported/served separately
12
+ * from page-specific code.
13
+ */
14
+
15
+ // ============================================
16
+ // Dependency Tracking System
17
+ // ============================================
18
+
19
+ let currentEffect: any = null;
20
+ const effectStack: any[] = [];
21
+ let batchDepth = 0;
22
+ const pendingEffects = new Set<any>();
23
+
24
+ function pushContext(effect: any) {
25
+ effectStack.push(currentEffect);
26
+ currentEffect = effect;
27
+ }
28
+
29
+ function popContext() {
30
+ currentEffect = effectStack.pop() || null;
31
+ }
32
+
33
+ function trackDependency(subscribers: Set<any>) {
34
+ if (currentEffect) {
35
+ subscribers.add(currentEffect);
36
+ currentEffect.dependencies.add(subscribers);
37
+ }
38
+ }
39
+
40
+ function notifySubscribers(subscribers: Set<any>) {
41
+ const effects = [...subscribers];
42
+ for (const effect of effects) {
43
+ if (batchDepth > 0) {
44
+ pendingEffects.add(effect);
45
+ } else {
46
+ effect.run();
47
+ }
48
+ }
49
+ }
50
+
51
+ function cleanupEffect(effect: any) {
52
+ for (const deps of effect.dependencies) {
53
+ deps.delete(effect);
54
+ }
55
+ effect.dependencies.clear();
56
+ }
57
+
58
+ // ============================================
59
+ // zenSignal - Atomic reactive value
60
+ // ============================================
61
+
62
+ export function zenSignal<T>(initialValue: T): (newValue?: T) => T {
63
+ let value = initialValue;
64
+ const subscribers = new Set<any>();
65
+
66
+ function signal(newValue?: T): T {
67
+ if (arguments.length === 0) {
68
+ trackDependency(subscribers);
69
+ return value;
70
+ }
71
+ if (newValue !== value) {
72
+ value = newValue as T;
73
+ notifySubscribers(subscribers);
74
+ }
75
+ return value;
76
+ }
77
+
78
+ return signal;
79
+ }
80
+
81
+ // ============================================
82
+ // zenState - Deep reactive object with Proxy
83
+ // ============================================
84
+
85
+ export function zenState<T extends object>(initialObj: T): T {
86
+ const subscribers = new Map<string, Set<any>>();
87
+
88
+ function getSubscribers(path: string): Set<any> {
89
+ if (!subscribers.has(path)) {
90
+ subscribers.set(path, new Set());
91
+ }
92
+ return subscribers.get(path)!;
93
+ }
94
+
95
+ function createProxy(obj: any, parentPath: string = ''): any {
96
+ if (obj === null || typeof obj !== 'object') {
97
+ return obj;
98
+ }
99
+
100
+ return new Proxy(obj, {
101
+ get(target, prop) {
102
+ if (typeof prop === 'symbol') return target[prop];
103
+
104
+ const path = parentPath ? `${parentPath}.${String(prop)}` : String(prop);
105
+ trackDependency(getSubscribers(path));
106
+
107
+ const value = target[prop];
108
+ if (value !== null && typeof value === 'object') {
109
+ return createProxy(value, path);
110
+ }
111
+ return value;
112
+ },
113
+
114
+ set(target, prop, newValue) {
115
+ if (typeof prop === 'symbol') {
116
+ target[prop] = newValue;
117
+ return true;
118
+ }
119
+
120
+ const path = parentPath ? `${parentPath}.${String(prop)}` : String(prop);
121
+ const oldValue = target[prop];
122
+
123
+ if (oldValue !== newValue) {
124
+ target[prop] = newValue;
125
+
126
+ // Notify this path
127
+ const subs = subscribers.get(path);
128
+ if (subs) notifySubscribers(subs);
129
+
130
+ // Notify parent paths
131
+ const parts = path.split('.');
132
+ for (let i = parts.length - 1; i >= 0; i--) {
133
+ const parentPath = parts.slice(0, i).join('.');
134
+ if (parentPath) {
135
+ const parentSubs = subscribers.get(parentPath);
136
+ if (parentSubs) notifySubscribers(parentSubs);
137
+ }
138
+ }
139
+ }
140
+ return true;
141
+ }
142
+ });
143
+ }
144
+
145
+ return createProxy(initialObj);
146
+ }
147
+
148
+ // ============================================
149
+ // zenEffect - Reactive effect
150
+ // ============================================
151
+
152
+ export function zenEffect(fn: () => void | (() => void)): () => void {
153
+ let cleanup: (() => void) | void;
154
+
155
+ const effect = {
156
+ dependencies: new Set<Set<any>>(),
157
+ run() {
158
+ cleanupEffect(effect);
159
+ pushContext(effect);
160
+ try {
161
+ if (cleanup) cleanup();
162
+ cleanup = fn();
163
+ } finally {
164
+ popContext();
165
+ }
166
+ }
167
+ };
168
+
169
+ effect.run();
170
+
171
+ return () => {
172
+ cleanupEffect(effect);
173
+ if (cleanup) cleanup();
174
+ };
175
+ }
176
+
177
+ // ============================================
178
+ // zenMemo - Computed/derived value
179
+ // ============================================
180
+
181
+ export function zenMemo<T>(fn: () => T): () => T {
182
+ let value: T;
183
+ let dirty = true;
184
+ const subscribers = new Set<any>();
185
+
186
+ const effect = {
187
+ dependencies: new Set<Set<any>>(),
188
+ run() {
189
+ cleanupEffect(effect);
190
+ pushContext(effect);
191
+ try {
192
+ value = fn();
193
+ dirty = false;
194
+ notifySubscribers(subscribers);
195
+ } finally {
196
+ popContext();
197
+ }
198
+ }
199
+ };
200
+
201
+ return () => {
202
+ trackDependency(subscribers);
203
+ if (dirty) {
204
+ effect.run();
205
+ }
206
+ return value;
207
+ };
208
+ }
209
+
210
+ // ============================================
211
+ // zenRef - Non-reactive mutable container
212
+ // ============================================
213
+
214
+ export function zenRef<T>(initialValue?: T): { current: T | null } {
215
+ return { current: initialValue !== undefined ? initialValue : null };
216
+ }
217
+
218
+ // ============================================
219
+ // zenBatch - Batch updates
220
+ // ============================================
221
+
222
+ export function zenBatch(fn: () => void): void {
223
+ batchDepth++;
224
+ try {
225
+ fn();
226
+ } finally {
227
+ batchDepth--;
228
+ if (batchDepth === 0) {
229
+ const effects = [...pendingEffects];
230
+ pendingEffects.clear();
231
+ for (const effect of effects) {
232
+ effect.run();
233
+ }
234
+ }
235
+ }
236
+ }
237
+
238
+ // ============================================
239
+ // zenUntrack - Read without tracking
240
+ // ============================================
241
+
242
+ export function zenUntrack<T>(fn: () => T): T {
243
+ const prevEffect = currentEffect;
244
+ currentEffect = null;
245
+ try {
246
+ return fn();
247
+ } finally {
248
+ currentEffect = prevEffect;
249
+ }
250
+ }
251
+
252
+ // ============================================
253
+ // Lifecycle Hooks
254
+ // ============================================
255
+
256
+ const mountCallbacks: Array<() => void | (() => void)> = [];
257
+ const unmountCallbacks: Array<() => void> = [];
258
+ let isMounted = false;
259
+
260
+ export function zenOnMount(fn: () => void | (() => void)): void {
261
+ if (isMounted) {
262
+ const cleanup = fn();
263
+ if (typeof cleanup === 'function') {
264
+ unmountCallbacks.push(cleanup);
265
+ }
266
+ } else {
267
+ mountCallbacks.push(fn);
268
+ }
269
+ }
270
+
271
+ export function zenOnUnmount(fn: () => void): void {
272
+ unmountCallbacks.push(fn);
273
+ }
274
+
275
+ export function triggerMount(): void {
276
+ isMounted = true;
277
+ for (const cb of mountCallbacks) {
278
+ const cleanup = cb();
279
+ if (typeof cleanup === 'function') {
280
+ unmountCallbacks.push(cleanup);
281
+ }
282
+ }
283
+ mountCallbacks.length = 0;
284
+ }
285
+
286
+ export function triggerUnmount(): void {
287
+ isMounted = false;
288
+ for (const cb of unmountCallbacks) {
289
+ try { cb(); } catch (e) { console.error('[Zenith] Unmount error:', e); }
290
+ }
291
+ unmountCallbacks.length = 0;
292
+ }
293
+
294
+ // ============================================
295
+ // Expression Registry
296
+ // ============================================
297
+
298
+ const expressionRegistry = new Map<string, (state: any) => any>();
299
+
300
+ export function registerExpression(id: string, fn: (state: any) => any): void {
301
+ expressionRegistry.set(id, fn);
302
+ }
303
+
304
+ export function getExpression(id: string): ((state: any) => any) | undefined {
305
+ return expressionRegistry.get(id);
306
+ }
307
+
308
+ // ============================================
309
+ // Hydration Functions
310
+ // ============================================
311
+
312
+ const bindings: Array<{ node: Element; type: string; expressionId: string; attributeName?: string }> = [];
313
+
314
+ export function hydrate(state: any, container?: Element | Document): void {
315
+ const root = container || document;
316
+
317
+ // Clear existing bindings
318
+ bindings.length = 0;
319
+
320
+ // Find all text expression placeholders
321
+ const textPlaceholders = root.querySelectorAll('[data-zen-text]');
322
+ textPlaceholders.forEach((node) => {
323
+ const expressionId = node.getAttribute('data-zen-text');
324
+ if (!expressionId) return;
325
+
326
+ bindings.push({ node: node as Element, type: 'text', expressionId });
327
+ updateTextBinding(node as Element, expressionId, state);
328
+ });
329
+
330
+ // Find attribute bindings
331
+ const attrSelectors = ['class', 'style', 'src', 'href', 'disabled', 'checked'];
332
+ for (const attr of attrSelectors) {
333
+ const attrPlaceholders = root.querySelectorAll(`[data-zen-attr-${attr}]`);
334
+ attrPlaceholders.forEach((node) => {
335
+ const expressionId = node.getAttribute(`data-zen-attr-${attr}`);
336
+ if (!expressionId) return;
337
+
338
+ bindings.push({ node: node as Element, type: 'attribute', expressionId, attributeName: attr });
339
+ updateAttributeBinding(node as Element, attr, expressionId, state);
340
+ });
341
+ }
342
+
343
+ // Bind event handlers
344
+ bindEvents(root);
345
+
346
+ // Trigger mount
347
+ triggerMount();
348
+ }
349
+
350
+ function updateTextBinding(node: Element, expressionId: string, state: any): void {
351
+ const expression = expressionRegistry.get(expressionId);
352
+ if (!expression) {
353
+ console.warn(`[Zenith] Expression ${expressionId} not found`);
354
+ return;
355
+ }
356
+
357
+ try {
358
+ const result = expression(state);
359
+ if (result === null || result === undefined || result === false) {
360
+ node.textContent = '';
361
+ } else {
362
+ node.textContent = String(result);
363
+ }
364
+ } catch (error) {
365
+ console.error(`[Zenith] Error evaluating expression ${expressionId}:`, error);
366
+ }
367
+ }
368
+
369
+ function updateAttributeBinding(element: Element, attrName: string, expressionId: string, state: any): void {
370
+ const expression = expressionRegistry.get(expressionId);
371
+ if (!expression) return;
372
+
373
+ try {
374
+ const result = expression(state);
375
+
376
+ if (attrName === 'class' || attrName === 'className') {
377
+ (element as HTMLElement).className = String(result ?? '');
378
+ } else if (attrName === 'style' && typeof result === 'object') {
379
+ const styleStr = Object.entries(result).map(([k, v]) => `${k}: ${v}`).join('; ');
380
+ element.setAttribute('style', styleStr);
381
+ } else if (['disabled', 'checked', 'readonly'].includes(attrName)) {
382
+ if (result) {
383
+ element.setAttribute(attrName, '');
384
+ } else {
385
+ element.removeAttribute(attrName);
386
+ }
387
+ } else {
388
+ if (result === null || result === undefined || result === false) {
389
+ element.removeAttribute(attrName);
390
+ } else {
391
+ element.setAttribute(attrName, String(result));
392
+ }
393
+ }
394
+ } catch (error) {
395
+ console.error(`[Zenith] Error updating attribute ${attrName}:`, error);
396
+ }
397
+ }
398
+
399
+ export function update(state: any): void {
400
+ for (const binding of bindings) {
401
+ if (binding.type === 'text') {
402
+ updateTextBinding(binding.node, binding.expressionId, state);
403
+ } else if (binding.type === 'attribute' && binding.attributeName) {
404
+ updateAttributeBinding(binding.node, binding.attributeName, binding.expressionId, state);
405
+ }
406
+ }
407
+ }
408
+
409
+ export function bindEvents(container: Element | Document): void {
410
+ const eventTypes = ['click', 'change', 'input', 'submit', 'focus', 'blur', 'keyup', 'keydown'];
411
+
412
+ for (const eventType of eventTypes) {
413
+ const elements = container.querySelectorAll(`[data-zen-${eventType}]`);
414
+
415
+ elements.forEach((element) => {
416
+ const handlerName = element.getAttribute(`data-zen-${eventType}`);
417
+ if (!handlerName) return;
418
+
419
+ // Remove existing handler if any
420
+ const handlerKey = `__zen_${eventType}_handler`;
421
+ const existingHandler = (element as any)[handlerKey];
422
+ if (existingHandler) {
423
+ element.removeEventListener(eventType, existingHandler);
424
+ }
425
+
426
+ // Create new handler
427
+ const handler = (event: Event) => {
428
+ try {
429
+ // Try window first, then expression registry
430
+ let handlerFunc = (window as any)[handlerName];
431
+ if (typeof handlerFunc !== 'function') {
432
+ handlerFunc = (window as any).__ZENITH_EXPRESSIONS__?.get(handlerName);
433
+ }
434
+
435
+ if (typeof handlerFunc === 'function') {
436
+ handlerFunc(event, element);
437
+ } else {
438
+ console.warn(`[Zenith] Event handler "${handlerName}" not found`);
439
+ }
440
+ } catch (error) {
441
+ console.error(`[Zenith] Error executing handler "${handlerName}":`, error);
442
+ }
443
+ };
444
+
445
+ (element as any)[handlerKey] = handler;
446
+ element.addEventListener(eventType, handler);
447
+ });
448
+ }
449
+ }
450
+
451
+ export function cleanup(container?: Element | Document): void {
452
+ const root = container || document;
453
+ const eventTypes = ['click', 'change', 'input', 'submit', 'focus', 'blur', 'keyup', 'keydown'];
454
+
455
+ for (const eventType of eventTypes) {
456
+ const elements = root.querySelectorAll(`[data-zen-${eventType}]`);
457
+ elements.forEach((element) => {
458
+ const handlerKey = `__zen_${eventType}_handler`;
459
+ const handler = (element as any)[handlerKey];
460
+ if (handler) {
461
+ element.removeEventListener(eventType, handler);
462
+ delete (element as any)[handlerKey];
463
+ }
464
+ });
465
+ }
466
+
467
+ bindings.length = 0;
468
+ triggerUnmount();
469
+ }
470
+
471
+ // ============================================
472
+ // Browser Globals Setup
473
+ // ============================================
474
+
475
+ export function setupGlobals(): void {
476
+ if (typeof window === 'undefined') return;
477
+
478
+ const w = window as any;
479
+
480
+ // Zenith namespace
481
+ w.__zenith = {
482
+ signal: zenSignal,
483
+ state: zenState,
484
+ effect: zenEffect,
485
+ memo: zenMemo,
486
+ ref: zenRef,
487
+ batch: zenBatch,
488
+ untrack: zenUntrack,
489
+ onMount: zenOnMount,
490
+ onUnmount: zenOnUnmount,
491
+ triggerMount,
492
+ triggerUnmount
493
+ };
494
+
495
+ // Expression registry
496
+ w.__ZENITH_EXPRESSIONS__ = expressionRegistry;
497
+
498
+ // Hydration functions
499
+ w.__zenith_hydrate = hydrate;
500
+ w.__zenith_update = update;
501
+ w.__zenith_bindEvents = bindEvents;
502
+ w.__zenith_cleanup = cleanup;
503
+ w.zenithHydrate = hydrate;
504
+ w.zenithUpdate = update;
505
+ w.zenithBindEvents = bindEvents;
506
+ w.zenithCleanup = cleanup;
507
+
508
+ // Direct primitives
509
+ w.zenSignal = zenSignal;
510
+ w.zenState = zenState;
511
+ w.zenEffect = zenEffect;
512
+ w.zenMemo = zenMemo;
513
+ w.zenRef = zenRef;
514
+ w.zenBatch = zenBatch;
515
+ w.zenUntrack = zenUntrack;
516
+ w.zenOnMount = zenOnMount;
517
+ w.zenOnUnmount = zenOnUnmount;
518
+
519
+ // Short aliases
520
+ w.signal = zenSignal;
521
+ w.state = zenState;
522
+ w.effect = zenEffect;
523
+ w.memo = zenMemo;
524
+ w.ref = zenRef;
525
+ w.batch = zenBatch;
526
+ w.untrack = zenUntrack;
527
+ w.onMount = zenOnMount;
528
+ w.onUnmount = zenOnUnmount;
529
+ }
530
+
531
+ // Auto-setup globals on import
532
+ setupGlobals();
package/.eslintignore DELETED
@@ -1,15 +0,0 @@
1
- # ESLint ignore file
2
- # .zen files are ignored temporarily until proper language support is added in Phase 3+
3
-
4
- # Ignore .zen files (custom Zenith syntax)
5
- **/*.zen
6
-
7
- # Standard ignores
8
- node_modules/
9
- dist/
10
- out/
11
- *.log
12
-
13
-
14
-
15
-
package/.gitattributes DELETED
@@ -1,2 +0,0 @@
1
- # Auto detect text files and perform LF normalization
2
- * text=auto
@@ -1,25 +0,0 @@
1
- # Compiler errors for invalid state declarations and usage
2
-
3
- ## Description
4
- Add compiler enforcement for the following invalid scenarios:
5
- - Use of undeclared state variables: `{{ unknown }}`.
6
- - Use of expressions in placeholders: `{{ count + 1 }}`.
7
- - Invalid state initialization: `state count = count + 1;`.
8
- - State mutations outside allowed event handlers.
9
-
10
- ## Acceptance Criteria
11
-
12
- 1. Compiler throws errors for undeclared state usage in placeholders.
13
- 2. Compiler disallows expressions within placeholders.
14
- 3. Errors are thrown for invalid state initialization logic.
15
- 4. State mutations are only allowed inside event handlers.
16
- 5. Test cases ensure all invalid scenarios are caught at compile time.
17
-
18
- ### Example:
19
- ```html
20
- <script>
21
- state count = 5;
22
- state other = count + 1; // Error
23
- </script>
24
- <p>{{ count + 1 }}</p> <!-- Error -->
25
- <p>{{ unknown }}</p> <!-- Error -->
@@ -1,34 +0,0 @@
1
- name: "\U0001F4A1 New Issue"
2
- description: Suggest a new task
3
-
4
- title: 'nn-your-issue'
5
-
6
- body:
7
- - type: markdown
8
- attributes:
9
- value: |
10
- _Thank you for taking the time to propose a new idea_
11
-
12
- - type: textarea
13
- id: problem
14
- attributes:
15
- label: '<h2>Describe the Problem</h2>'
16
- description: Please provide a short user story **DESCRIPTION** of the **PROBLEM**
17
- placeholder: As a user I...
18
- validations:
19
- required: true
20
-
21
- - type: textarea
22
- id: solution
23
- attributes:
24
- label: '<h2>Acceptance Criteria</h2>'
25
- description: Please provide the REQUIREMENTS that must be fulfilled to consider this issue resolved.
26
- placeholder: X must show Y when Z...
27
- validations:
28
- required: true
29
-
30
- - type: textarea
31
- id: references
32
- attributes:
33
- label: '<h2>References</h2>'
34
- description: Please provide any **SCREENSHOTS**, **CODE SNIPPETS** or **LINKS** to the codebase or documentation which will help implement a solution.
@@ -1,15 +0,0 @@
1
- # 🚀 Summary
2
-
3
- This merge implements/resolves... (include relevant ticket)
4
-
5
- ## 📝 How can we Reproduce/Test?
6
-
7
- Please provide instructions so we can reproduce:
8
-
9
- - [ ] Step 1
10
- - [ ] Step 2
11
- - [ ] ...
12
-
13
- ## 📸 Any screenshots or links to points in your code or references elsewhere as needed
14
-
15
- Please delete if not relevant.