@aurelia/storybook 2.2.1 → 2.3.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 (140) hide show
  1. package/CHANGELOG.md +7 -1
  2. package/README.md +18 -14
  3. package/dist/index.js +34 -14
  4. package/dist/index.js.map +1 -1
  5. package/dist/preset.js +30 -20
  6. package/dist/preset.js.map +1 -1
  7. package/dist/preview/render.d.ts +1 -1
  8. package/dist/preview/render.js +34 -14
  9. package/dist/preview/render.js.map +1 -1
  10. package/dist/preview.js +34 -14
  11. package/dist/preview.js.map +1 -1
  12. package/package.json +30 -15
  13. package/preset.js +2 -1
  14. package/.github/workflows/ci.yml +0 -61
  15. package/.github/workflows/publish.yml +0 -82
  16. package/.github/workflows/storybook-preview.yml +0 -62
  17. package/__tests__/create-aurelia-app.test.ts +0 -94
  18. package/__tests__/preset.test.ts +0 -78
  19. package/__tests__/preview.test.ts +0 -17
  20. package/__tests__/render.test.ts +0 -176
  21. package/__tests__/webpack.test.ts +0 -21
  22. package/apps/hello-world/.storybook/main.ts +0 -49
  23. package/apps/hello-world/.storybook/preview.ts +0 -1
  24. package/apps/hello-world/.stylelintrc.json +0 -5
  25. package/apps/hello-world/README.md +0 -28
  26. package/apps/hello-world/eslint.config.mjs +0 -25
  27. package/apps/hello-world/favicon.ico +0 -0
  28. package/apps/hello-world/index.html +0 -17
  29. package/apps/hello-world/package-lock.json +0 -9424
  30. package/apps/hello-world/package.json +0 -55
  31. package/apps/hello-world/src/components/feedback-form.html +0 -111
  32. package/apps/hello-world/src/components/feedback-form.ts +0 -45
  33. package/apps/hello-world/src/components/notification-center.html +0 -119
  34. package/apps/hello-world/src/components/notification-center.ts +0 -27
  35. package/apps/hello-world/src/components/stat-card.html +0 -107
  36. package/apps/hello-world/src/components/stat-card.ts +0 -41
  37. package/apps/hello-world/src/components/weather-widget.html +0 -89
  38. package/apps/hello-world/src/components/weather-widget.ts +0 -31
  39. package/apps/hello-world/src/hello-world.html +0 -48
  40. package/apps/hello-world/src/hello-world.ts +0 -17
  41. package/apps/hello-world/src/main.ts +0 -6
  42. package/apps/hello-world/src/my-app.html +0 -1
  43. package/apps/hello-world/src/my-app.ts +0 -3
  44. package/apps/hello-world/src/resource.d.ts +0 -15
  45. package/apps/hello-world/src/services/weather-service.ts +0 -15
  46. package/apps/hello-world/src/stories/feedback-form.stories.ts +0 -58
  47. package/apps/hello-world/src/stories/hello-world.stories.ts +0 -64
  48. package/apps/hello-world/src/stories/notification-center.stories.ts +0 -88
  49. package/apps/hello-world/src/stories/stat-card.stories.ts +0 -75
  50. package/apps/hello-world/src/stories/weather-widget.stories.ts +0 -62
  51. package/apps/hello-world/test/my-app.spec.ts +0 -15
  52. package/apps/hello-world/test/setup.ts +0 -29
  53. package/apps/hello-world/tsconfig.json +0 -19
  54. package/apps/hello-world/tsconfig.vitest.json +0 -11
  55. package/apps/hello-world/vite.config.ts +0 -17
  56. package/apps/hello-world/vitest.config.ts +0 -15
  57. package/apps/hello-world-rsbuild/.storybook/main.ts +0 -16
  58. package/apps/hello-world-rsbuild/.storybook/preview.ts +0 -1
  59. package/apps/hello-world-rsbuild/.stylelintrc.json +0 -5
  60. package/apps/hello-world-rsbuild/README.md +0 -28
  61. package/apps/hello-world-rsbuild/eslint.config.mjs +0 -25
  62. package/apps/hello-world-rsbuild/favicon.ico +0 -0
  63. package/apps/hello-world-rsbuild/index.html +0 -17
  64. package/apps/hello-world-rsbuild/package-lock.json +0 -11131
  65. package/apps/hello-world-rsbuild/package.json +0 -56
  66. package/apps/hello-world-rsbuild/src/components/feedback-form.html +0 -111
  67. package/apps/hello-world-rsbuild/src/components/feedback-form.ts +0 -45
  68. package/apps/hello-world-rsbuild/src/components/notification-center.html +0 -119
  69. package/apps/hello-world-rsbuild/src/components/notification-center.ts +0 -27
  70. package/apps/hello-world-rsbuild/src/components/stat-card.html +0 -107
  71. package/apps/hello-world-rsbuild/src/components/stat-card.ts +0 -41
  72. package/apps/hello-world-rsbuild/src/components/weather-widget.html +0 -89
  73. package/apps/hello-world-rsbuild/src/components/weather-widget.ts +0 -31
  74. package/apps/hello-world-rsbuild/src/hello-world.html +0 -48
  75. package/apps/hello-world-rsbuild/src/hello-world.ts +0 -17
  76. package/apps/hello-world-rsbuild/src/main.ts +0 -6
  77. package/apps/hello-world-rsbuild/src/my-app.html +0 -1
  78. package/apps/hello-world-rsbuild/src/my-app.ts +0 -3
  79. package/apps/hello-world-rsbuild/src/resource.d.ts +0 -15
  80. package/apps/hello-world-rsbuild/src/services/weather-service.ts +0 -15
  81. package/apps/hello-world-rsbuild/src/stories/feedback-form.stories.ts +0 -58
  82. package/apps/hello-world-rsbuild/src/stories/hello-world.stories.ts +0 -64
  83. package/apps/hello-world-rsbuild/src/stories/notification-center.stories.ts +0 -88
  84. package/apps/hello-world-rsbuild/src/stories/stat-card.stories.ts +0 -75
  85. package/apps/hello-world-rsbuild/src/stories/weather-widget.stories.ts +0 -62
  86. package/apps/hello-world-rsbuild/test/my-app.spec.ts +0 -15
  87. package/apps/hello-world-rsbuild/test/setup.ts +0 -29
  88. package/apps/hello-world-rsbuild/tsconfig.json +0 -19
  89. package/apps/hello-world-rsbuild/tsconfig.vitest.json +0 -11
  90. package/apps/hello-world-rsbuild/vite.config.ts +0 -17
  91. package/apps/hello-world-rsbuild/vitest.config.ts +0 -15
  92. package/apps/hello-world-webpack/.env.development +0 -0
  93. package/apps/hello-world-webpack/.storybook/main.ts +0 -14
  94. package/apps/hello-world-webpack/.storybook/preview.ts +0 -3
  95. package/apps/hello-world-webpack/.stylelintrc.json +0 -5
  96. package/apps/hello-world-webpack/README.md +0 -29
  97. package/apps/hello-world-webpack/eslint.config.mjs +0 -25
  98. package/apps/hello-world-webpack/favicon.ico +0 -0
  99. package/apps/hello-world-webpack/index.html +0 -15
  100. package/apps/hello-world-webpack/package-lock.json +0 -9828
  101. package/apps/hello-world-webpack/package.json +0 -52
  102. package/apps/hello-world-webpack/src/components/feedback-form.html +0 -111
  103. package/apps/hello-world-webpack/src/components/feedback-form.ts +0 -45
  104. package/apps/hello-world-webpack/src/components/notification-center.html +0 -119
  105. package/apps/hello-world-webpack/src/components/notification-center.ts +0 -27
  106. package/apps/hello-world-webpack/src/components/stat-card.html +0 -107
  107. package/apps/hello-world-webpack/src/components/stat-card.ts +0 -41
  108. package/apps/hello-world-webpack/src/components/weather-widget.html +0 -89
  109. package/apps/hello-world-webpack/src/components/weather-widget.ts +0 -31
  110. package/apps/hello-world-webpack/src/hello-world.html +0 -48
  111. package/apps/hello-world-webpack/src/hello-world.ts +0 -17
  112. package/apps/hello-world-webpack/src/main.ts +0 -6
  113. package/apps/hello-world-webpack/src/my-app.css +0 -3
  114. package/apps/hello-world-webpack/src/my-app.html +0 -1
  115. package/apps/hello-world-webpack/src/my-app.stories.ts +0 -17
  116. package/apps/hello-world-webpack/src/my-app.ts +0 -3
  117. package/apps/hello-world-webpack/src/resource.d.ts +0 -13
  118. package/apps/hello-world-webpack/src/services/weather-service.ts +0 -15
  119. package/apps/hello-world-webpack/src/stories/feedback-form.stories.ts +0 -58
  120. package/apps/hello-world-webpack/src/stories/hello-world.stories.ts +0 -64
  121. package/apps/hello-world-webpack/src/stories/notification-center.stories.ts +0 -88
  122. package/apps/hello-world-webpack/src/stories/stat-card.stories.ts +0 -75
  123. package/apps/hello-world-webpack/src/stories/weather-widget.stories.ts +0 -62
  124. package/apps/hello-world-webpack/tsconfig.json +0 -18
  125. package/apps/hello-world-webpack/webpack.config.js +0 -111
  126. package/jest.config.cjs +0 -9
  127. package/rollup.config.mjs +0 -52
  128. package/scripts/sync-versions.cjs +0 -55
  129. package/src/index.ts +0 -42
  130. package/src/preset.ts +0 -79
  131. package/src/preview/helpers.ts +0 -7
  132. package/src/preview/render.ts +0 -243
  133. package/src/preview/storybook-types-runtime.ts +0 -2
  134. package/src/preview/storybook-types.ts +0 -34
  135. package/src/preview/types-runtime.ts +0 -2
  136. package/src/preview/types.ts +0 -62
  137. package/src/preview.ts +0 -11
  138. package/src/webpack.ts +0 -40
  139. package/tsconfig.build.json +0 -5
  140. package/tsconfig.json +0 -15
@@ -1,56 +0,0 @@
1
- {
2
- "name": "apptasks-video-rsbuild",
3
- "description": "An Aurelia 2 client application.",
4
- "version": "2.2.1",
5
- "repository": {
6
- "type": "git",
7
- "url": "???"
8
- },
9
- "license": "UNLICENSED",
10
- "dependencies": {
11
- "@aurelia/router": "^2.0.0-rc.0",
12
- "@aurelia/validation": "^2.0.0-rc.0",
13
- "@aurelia/validation-html": "^2.0.0-rc.0",
14
- "aurelia": "^2.0.0-rc.0"
15
- },
16
- "devDependencies": {
17
- "@aurelia/storybook": "^2.2.1",
18
- "@aurelia/testing": "^2.0.0-rc.0",
19
- "@aurelia/vite-plugin": "^2.0.0-rc.0",
20
- "@rsbuild/core": "^1.7.2",
21
- "@tailwindcss/vite": "^4.0.0",
22
- "@types/node": "^22.10.2",
23
- "@types/react": "^19.1.8",
24
- "@types/react-dom": "^19.1.6",
25
- "eslint": "^9.17.0",
26
- "globals": "^15.14.0",
27
- "jsdom": "^25.0.1",
28
- "node-html-parser": "^7.0.1",
29
- "react": "^19.1.0",
30
- "react-dom": "^19.1.0",
31
- "sass": "^1.83.4",
32
- "storybook": "^10.2.0",
33
- "storybook-builder-rsbuild": "^3.2.2",
34
- "stylelint": "^16.12.0",
35
- "stylelint-config-standard": "^36.0.1",
36
- "stylus": "^0.64.0",
37
- "tailwindcss": "^4.0.0",
38
- "tslib": "^2.8.1",
39
- "typescript": "^5.7.2",
40
- "typescript-eslint": "^8.18.1",
41
- "vite": "^7.0.0",
42
- "vitest": "^4.0.0"
43
- },
44
- "scripts": {
45
- "lint:js": "eslint src test",
46
- "lint:css": "stylelint \"src/**/*.css\"",
47
- "lint": "npm run lint:js && npm run lint:css",
48
- "pretest": "npm run lint",
49
- "start": "vite",
50
- "build": "vite build",
51
- "test": "vitest",
52
- "storybook": "storybook dev -p 6006",
53
- "build-storybook": "storybook build"
54
- },
55
- "type": "module"
56
- }
@@ -1,111 +0,0 @@
1
- <style>
2
- .feedback-form {
3
- display: flex;
4
- flex-direction: column;
5
- gap: 18px;
6
- padding: 28px;
7
- border-radius: 18px;
8
- background: #fff;
9
- border: 1px solid rgba(15, 23, 42, 0.08);
10
- box-shadow: 0 15px 40px rgba(15, 23, 42, 0.08);
11
- max-width: 420px;
12
- font-family: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
13
- }
14
-
15
- .feedback-form label {
16
- display: flex;
17
- flex-direction: column;
18
- gap: 8px;
19
- font-size: 14px;
20
- color: #0f172a;
21
- font-weight: 600;
22
- }
23
-
24
- .feedback-form input,
25
- .feedback-form select,
26
- .feedback-form textarea {
27
- border-radius: 12px;
28
- border: 1px solid rgba(15, 23, 42, 0.15);
29
- padding: 12px 14px;
30
- font-size: 15px;
31
- font-weight: 500;
32
- color: #0f172a;
33
- background: #f8fafc;
34
- transition: border 0.2s ease, box-shadow 0.2s ease;
35
- }
36
-
37
- .feedback-form input:focus,
38
- .feedback-form select:focus,
39
- .feedback-form textarea:focus {
40
- outline: none;
41
- border-color: #2563eb;
42
- box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.2);
43
- background: #fff;
44
- }
45
-
46
- .feedback-form__actions {
47
- display: flex;
48
- gap: 12px;
49
- }
50
-
51
- .feedback-form__actions button {
52
- flex: 1;
53
- border: none;
54
- border-radius: 12px;
55
- padding: 12px 16px;
56
- font-size: 15px;
57
- font-weight: 600;
58
- cursor: pointer;
59
- transition: transform 0.2s ease, box-shadow 0.2s ease;
60
- }
61
-
62
- .feedback-form__actions button:first-child {
63
- background: linear-gradient(135deg, #2563eb, #4f46e5);
64
- color: #fff;
65
- box-shadow: 0 15px 30px rgba(79, 70, 229, 0.3);
66
- }
67
-
68
- .feedback-form__actions button:first-child:disabled {
69
- opacity: 0.65;
70
- box-shadow: none;
71
- cursor: not-allowed;
72
- }
73
-
74
- .feedback-form__actions button:last-child {
75
- background: #e2e8f0;
76
- color: #0f172a;
77
- }
78
-
79
- .feedback-form__success {
80
- margin: 0;
81
- font-size: 14px;
82
- font-weight: 600;
83
- color: #059669;
84
- text-align: center;
85
- }
86
- </style>
87
- <form class="feedback-form" submit.trigger="submit($event)" aria-live="polite">
88
- <label>
89
- Name
90
- <input type="text" value.two-way="form.name" placeholder="Ada Lovelace" required />
91
- </label>
92
- <label>
93
- Email
94
- <input type="email" value.two-way="form.email" placeholder="ada@example.com" required />
95
- </label>
96
- <label>
97
- Topic
98
- <select value.two-way="form.topic">
99
- <option repeat.for="topic of topics" value.bind="topic">${topic}</option>
100
- </select>
101
- </label>
102
- <label>
103
- Message
104
- <textarea rows="4" value.two-way="form.message"></textarea>
105
- </label>
106
- <div class="feedback-form__actions">
107
- <button type="submit" disabled.bind="submitting">${submitting ? 'Sending...' : 'Send feedback'}</button>
108
- <button type="button" click.trigger="reset()" disabled.bind="submitting">Reset</button>
109
- </div>
110
- <p if.bind="submitted" class="feedback-form__success">Thank you for the feedback!</p>
111
- </form>
@@ -1,45 +0,0 @@
1
- import { bindable } from 'aurelia';
2
-
3
- export interface FeedbackPayload {
4
- name: string;
5
- email: string;
6
- topic: string;
7
- message: string;
8
- }
9
-
10
- export class FeedbackForm {
11
- @bindable() topics: string[] = ['Bug report', 'Feature idea', 'General praise'];
12
- @bindable() submitting = false;
13
- @bindable() onSubmit?: (payload: FeedbackPayload) => Promise<void> | void;
14
-
15
- form: FeedbackPayload = {
16
- name: '',
17
- email: '',
18
- topic: 'Bug report',
19
- message: '',
20
- };
21
-
22
- submitted = false;
23
-
24
- async submit(event?: Event) {
25
- event?.preventDefault();
26
- if (this.submitting) {
27
- return;
28
- }
29
-
30
- this.submitting = true;
31
- await this.onSubmit?.({ ...this.form });
32
- this.submitting = false;
33
- this.submitted = true;
34
- }
35
-
36
- reset() {
37
- this.form = {
38
- name: '',
39
- email: '',
40
- topic: this.topics[0] ?? '',
41
- message: '',
42
- };
43
- this.submitted = false;
44
- }
45
- }
@@ -1,119 +0,0 @@
1
- <style>
2
- .notification-center {
3
- width: 420px;
4
- border-radius: 20px;
5
- background: #0f172a;
6
- color: #f8fafc;
7
- padding: 20px 24px;
8
- box-shadow: 0 25px 50px rgba(15, 23, 42, 0.45);
9
- font-family: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
10
- }
11
-
12
- .notification-center__header {
13
- display: flex;
14
- justify-content: space-between;
15
- margin-bottom: 18px;
16
- }
17
-
18
- .notification-center__header h2 {
19
- margin: 0;
20
- font-size: 20px;
21
- }
22
-
23
- .notification-center__count {
24
- font-size: 13px;
25
- opacity: 0.7;
26
- align-self: center;
27
- }
28
-
29
- .notification-center__list {
30
- list-style: none;
31
- margin: 0;
32
- padding: 0;
33
- display: flex;
34
- flex-direction: column;
35
- gap: 12px;
36
- }
37
-
38
- .notification-center__item {
39
- display: flex;
40
- justify-content: space-between;
41
- padding: 14px 16px;
42
- border-radius: 14px;
43
- background: rgba(148, 163, 184, 0.12);
44
- border: 1px solid rgba(148, 163, 184, 0.2);
45
- gap: 12px;
46
- }
47
-
48
- .notification-center__item strong {
49
- display: block;
50
- font-size: 15px;
51
- margin-bottom: 4px;
52
- }
53
-
54
- .notification-center__item p {
55
- margin: 0 0 6px;
56
- font-size: 14px;
57
- opacity: 0.9;
58
- }
59
-
60
- .notification-center__item small {
61
- font-size: 12px;
62
- opacity: 0.6;
63
- }
64
-
65
- .notification-center__item button {
66
- background: transparent;
67
- border: 1px solid rgba(255, 255, 255, 0.4);
68
- color: inherit;
69
- border-radius: 999px;
70
- padding: 4px 12px;
71
- height: fit-content;
72
- cursor: pointer;
73
- transition: background 0.2s ease;
74
- }
75
-
76
- .notification-center__item button:hover,
77
- .notification-center__item button:focus-visible {
78
- background: rgba(255, 255, 255, 0.1);
79
- }
80
-
81
- .notification-center__item.success {
82
- border-color: rgba(45, 212, 191, 0.4);
83
- }
84
-
85
- .notification-center__item.warning {
86
- border-color: rgba(249, 115, 22, 0.4);
87
- }
88
-
89
- .notification-center__item.error {
90
- border-color: rgba(239, 68, 68, 0.4);
91
- }
92
-
93
- .notification-center__empty {
94
- text-align: center;
95
- padding: 16px;
96
- background: rgba(148, 163, 184, 0.1);
97
- border-radius: 12px;
98
- font-size: 14px;
99
- }
100
- </style>
101
- <section class="notification-center">
102
- <header class="notification-center__header">
103
- <h2>Notifications</h2>
104
- <span class="notification-center__count">${notifications.length} total</span>
105
- </header>
106
- <ul class="notification-center__list">
107
- <li repeat.for="note of visibleNotifications" class="notification-center__item ${note.level}">
108
- <div>
109
- <strong>${note.title}</strong>
110
- <p>${note.message}</p>
111
- <small if.bind="showTimestamp">${note.timestamp}</small>
112
- </div>
113
- <button type="button" click.trigger="dismiss(note)">Dismiss</button>
114
- </li>
115
- <li if.bind="visibleNotifications.length === 0" class="notification-center__empty">
116
- You're all caught up!
117
- </li>
118
- </ul>
119
- </section>
@@ -1,27 +0,0 @@
1
- import { bindable } from 'aurelia';
2
-
3
- export type NotificationLevel = 'info' | 'success' | 'warning' | 'error';
4
-
5
- export interface NotificationItem {
6
- id: number;
7
- title: string;
8
- message: string;
9
- level: NotificationLevel;
10
- timestamp?: string;
11
- }
12
-
13
- export class NotificationCenter {
14
- @bindable() notifications: NotificationItem[] = [];
15
- @bindable() maxVisible = 4;
16
- @bindable() showTimestamp = true;
17
- @bindable() onDismiss?: (notification: NotificationItem) => void;
18
-
19
- get visibleNotifications() {
20
- return (this.notifications ?? []).slice(0, this.maxVisible);
21
- }
22
-
23
- dismiss(notification: NotificationItem) {
24
- this.notifications = (this.notifications ?? []).filter((note) => note.id !== notification.id);
25
- this.onDismiss?.(notification);
26
- }
27
- }
@@ -1,107 +0,0 @@
1
- <style>
2
- .stat-card {
3
- border-radius: 16px;
4
- padding: 20px 24px;
5
- background: linear-gradient(135deg, #1f3d8f, #3c74ff);
6
- color: #fff;
7
- box-shadow: 0 20px 45px rgba(13, 32, 94, 0.35);
8
- max-width: 360px;
9
- font-family: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
10
- }
11
-
12
- .stat-card__header {
13
- display: flex;
14
- justify-content: space-between;
15
- gap: 12px;
16
- align-items: flex-start;
17
- }
18
-
19
- .stat-card__label {
20
- text-transform: uppercase;
21
- letter-spacing: 0.08em;
22
- font-size: 12px;
23
- opacity: 0.8;
24
- margin: 0 0 6px;
25
- }
26
-
27
- .stat-card__value {
28
- font-size: 44px;
29
- margin: 0;
30
- font-weight: 600;
31
- line-height: 1;
32
- }
33
-
34
- .stat-card__unit {
35
- font-size: 20px;
36
- margin-left: 6px;
37
- opacity: 0.85;
38
- }
39
-
40
- .stat-card__refresh {
41
- border: 1px solid rgba(255, 255, 255, 0.4);
42
- background: rgba(255, 255, 255, 0.12);
43
- color: #fff;
44
- padding: 6px 12px;
45
- border-radius: 999px;
46
- font-size: 12px;
47
- letter-spacing: 0.05em;
48
- text-transform: uppercase;
49
- cursor: pointer;
50
- transition: background 0.2s ease, border 0.2s ease;
51
- }
52
-
53
- .stat-card__refresh:focus-visible,
54
- .stat-card__refresh:hover {
55
- background: rgba(255, 255, 255, 0.2);
56
- border-color: rgba(255, 255, 255, 0.7);
57
- }
58
-
59
- .stat-card__description {
60
- margin: 18px 0 12px;
61
- font-size: 15px;
62
- opacity: 0.9;
63
- }
64
-
65
- .stat-card__footer {
66
- display: inline-flex;
67
- align-items: center;
68
- gap: 8px;
69
- border-radius: 999px;
70
- padding: 6px 14px;
71
- font-size: 14px;
72
- font-weight: 500;
73
- }
74
-
75
- .stat-card__footer.positive {
76
- background: rgba(20, 235, 178, 0.2);
77
- color: #14ebb2;
78
- }
79
-
80
- .stat-card__footer.negative {
81
- background: rgba(255, 107, 107, 0.2);
82
- color: #ff6b6b;
83
- }
84
-
85
- .stat-card__footer.neutral {
86
- background: rgba(255, 255, 255, 0.2);
87
- color: #fff;
88
- }
89
- </style>
90
- <section class="stat-card" aria-live="polite">
91
- <header class="stat-card__header">
92
- <div>
93
- <p class="stat-card__label">${title}</p>
94
- <h2 class="stat-card__value">
95
- ${value}<span if.bind="unit" class="stat-card__unit">${unit}</span>
96
- </h2>
97
- </div>
98
- <button type="button" class="stat-card__refresh" click.trigger="refresh()" title="Refresh metric" aria-label="Refresh metric">
99
- Refresh
100
- </button>
101
- </header>
102
- <p class="stat-card__description">${description}</p>
103
- <footer class="stat-card__footer ${changeState}">
104
- <strong>${changeLabel}</strong>
105
- <span>${changeCopy}</span>
106
- </footer>
107
- </section>
@@ -1,41 +0,0 @@
1
- import { bindable } from 'aurelia';
2
-
3
- type TrendState = 'positive' | 'negative' | 'neutral';
4
-
5
- export class StatCard {
6
- @bindable() title = 'Active users';
7
- @bindable() value: number | string = 0;
8
- @bindable() unit = '';
9
- @bindable() change = 0; // percent delta
10
- @bindable() description = '';
11
- @bindable() changeCopy = 'vs last week';
12
- @bindable() onRefresh?: () => void;
13
-
14
- refresh() {
15
- this.onRefresh?.();
16
- }
17
-
18
- get changeLabel() {
19
- const numeric = typeof this.change === 'number' ? this.change : Number(this.change);
20
- if (!Number.isFinite(numeric)) {
21
- return '0%';
22
- }
23
- const rounded = numeric.toFixed(1).replace(/\.0$/, '');
24
- const sign = numeric > 0 ? '+' : '';
25
- return `${sign}${rounded}%`;
26
- }
27
-
28
- get changeState(): TrendState {
29
- const numeric = typeof this.change === 'number' ? this.change : Number(this.change);
30
- if (!Number.isFinite(numeric)) {
31
- return 'neutral';
32
- }
33
- if (numeric > 0) {
34
- return 'positive';
35
- }
36
- if (numeric < 0) {
37
- return 'negative';
38
- }
39
- return 'neutral';
40
- }
41
- }
@@ -1,89 +0,0 @@
1
- <style>
2
- .weather-widget {
3
- width: 320px;
4
- border-radius: 24px;
5
- padding: 22px;
6
- background: linear-gradient(160deg, #fef3c7, #fcd34d);
7
- color: #1f2937;
8
- box-shadow: 0 20px 45px rgba(244, 114, 10, 0.25);
9
- font-family: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
10
- }
11
-
12
- .weather-widget header {
13
- display: flex;
14
- justify-content: space-between;
15
- align-items: center;
16
- margin-bottom: 14px;
17
- }
18
-
19
- .weather-widget header h2 {
20
- margin: 0;
21
- font-size: 20px;
22
- font-weight: 600;
23
- }
24
-
25
- .weather-widget button {
26
- border: none;
27
- background: rgba(255, 255, 255, 0.4);
28
- color: #92400e;
29
- border-radius: 12px;
30
- padding: 6px 12px;
31
- font-weight: 600;
32
- cursor: pointer;
33
- transition: background 0.2s ease;
34
- }
35
-
36
- .weather-widget button:disabled {
37
- opacity: 0.6;
38
- cursor: not-allowed;
39
- }
40
-
41
- .weather-widget button:not(:disabled):hover,
42
- .weather-widget button:not(:disabled):focus-visible {
43
- background: rgba(255, 255, 255, 0.6);
44
- }
45
-
46
- .weather-widget__state {
47
- padding: 16px;
48
- border-radius: 16px;
49
- background: rgba(255, 255, 255, 0.6);
50
- font-weight: 600;
51
- text-align: center;
52
- }
53
-
54
- .weather-widget__state--error {
55
- background: rgba(248, 113, 113, 0.3);
56
- color: #991b1b;
57
- }
58
-
59
- .weather-widget__body {
60
- display: flex;
61
- flex-direction: column;
62
- gap: 6px;
63
- font-weight: 600;
64
- }
65
-
66
- .weather-widget__temp {
67
- font-size: 64px;
68
- margin: 0;
69
- font-weight: 700;
70
- }
71
-
72
- .weather-widget__body small {
73
- font-size: 14px;
74
- opacity: 0.8;
75
- }
76
- </style>
77
- <section class="weather-widget" aria-live="polite">
78
- <header>
79
- <h2>${location}</h2>
80
- <button type="button" click.trigger="refresh()" disabled.bind="state === 'loading'">Refresh</button>
81
- </header>
82
- <div if.bind="state === 'loading'" class="weather-widget__state">Loading latest data...</div>
83
- <div if.bind="state === 'error'" class="weather-widget__state weather-widget__state--error">${error}</div>
84
- <div if.bind="state === 'ready'" class="weather-widget__body">
85
- <p class="weather-widget__temp">${report.temperature}&deg;</p>
86
- <p>${report.condition}</p>
87
- <small>High ${report.high}&deg; - Low ${report.low}&deg;</small>
88
- </div>
89
- </section>
@@ -1,31 +0,0 @@
1
- import { bindable } from 'aurelia';
2
- import { IWeatherService, WeatherSummary, WeatherService } from '../services/weather-service';
3
-
4
- export class WeatherWidget {
5
- static inject = [IWeatherService];
6
-
7
- constructor(private readonly service: WeatherService) {}
8
-
9
- @bindable() location = 'Seattle, WA';
10
-
11
- report: WeatherSummary | null = null;
12
- state: 'idle' | 'loading' | 'ready' | 'error' = 'idle';
13
- error = '';
14
-
15
- binding() {
16
- void this.refresh();
17
- }
18
-
19
- async refresh() {
20
- try {
21
- this.state = 'loading';
22
- this.error = '';
23
- const location = this.location ?? 'Seattle, WA';
24
- this.report = await this.service.getWeather(location);
25
- this.state = 'ready';
26
- } catch (err) {
27
- this.state = 'error';
28
- this.error = err instanceof Error ? err.message : 'Unable to load weather data.';
29
- }
30
- }
31
- }
@@ -1,48 +0,0 @@
1
- <style>
2
- .hello-card {
3
- max-width: 360px;
4
- padding: 32px;
5
- border-radius: 24px;
6
- background: linear-gradient(135deg, #ec4899, #a855f7);
7
- color: #fff;
8
- font-family: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
9
- box-shadow: 0 25px 45px rgba(168, 85, 247, 0.35);
10
- }
11
-
12
- .hello-card h1 {
13
- margin: 0 0 12px;
14
- font-size: 28px;
15
- font-weight: 600;
16
- }
17
-
18
- .hello-card p {
19
- margin: 0 0 18px;
20
- font-size: 16px;
21
- opacity: 0.95;
22
- }
23
-
24
- .hello-card button {
25
- border: none;
26
- border-radius: 16px;
27
- padding: 12px 18px;
28
- font-size: 15px;
29
- font-weight: 600;
30
- background: #fff;
31
- color: #a855f7;
32
- cursor: pointer;
33
- box-shadow: 0 15px 30px rgba(255, 255, 255, 0.25);
34
- transition: transform 0.2s ease, box-shadow 0.2s ease;
35
- }
36
-
37
- .hello-card button:hover,
38
- .hello-card button:focus-visible {
39
- transform: translateY(-2px);
40
- box-shadow: 0 18px 32px rgba(255, 255, 255, 0.35);
41
- }
42
- </style>
43
- <div class="hello-card">
44
- <h1>${message}</h1>
45
- <p>Counter: ${counter}</p>
46
- <button click.trigger="increment()">Increment</button>
47
- <au-slot></au-slot>
48
- </div>
@@ -1,17 +0,0 @@
1
- import { bindable } from 'aurelia';
2
-
3
- export class HelloWorld {
4
- @bindable() message = 'Hello from Aurelia!';
5
- // New reactive counter property to track number of clicks
6
- counter = 0;
7
- // New bindable event callback for the increment action
8
- @bindable() onIncrement;
9
-
10
- // Method to increment the counter and fire the onIncrement callback if provided.
11
- increment() {
12
- this.counter++;
13
- if (this.onIncrement) {
14
- this.onIncrement(this.counter);
15
- }
16
- }
17
- }