@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.
- package/CHANGELOG.md +7 -1
- package/README.md +18 -14
- package/dist/index.js +34 -14
- package/dist/index.js.map +1 -1
- package/dist/preset.js +30 -20
- package/dist/preset.js.map +1 -1
- package/dist/preview/render.d.ts +1 -1
- package/dist/preview/render.js +34 -14
- package/dist/preview/render.js.map +1 -1
- package/dist/preview.js +34 -14
- package/dist/preview.js.map +1 -1
- package/package.json +30 -15
- package/preset.js +2 -1
- package/.github/workflows/ci.yml +0 -61
- package/.github/workflows/publish.yml +0 -82
- package/.github/workflows/storybook-preview.yml +0 -62
- package/__tests__/create-aurelia-app.test.ts +0 -94
- package/__tests__/preset.test.ts +0 -78
- package/__tests__/preview.test.ts +0 -17
- package/__tests__/render.test.ts +0 -176
- package/__tests__/webpack.test.ts +0 -21
- package/apps/hello-world/.storybook/main.ts +0 -49
- package/apps/hello-world/.storybook/preview.ts +0 -1
- package/apps/hello-world/.stylelintrc.json +0 -5
- package/apps/hello-world/README.md +0 -28
- package/apps/hello-world/eslint.config.mjs +0 -25
- package/apps/hello-world/favicon.ico +0 -0
- package/apps/hello-world/index.html +0 -17
- package/apps/hello-world/package-lock.json +0 -9424
- package/apps/hello-world/package.json +0 -55
- package/apps/hello-world/src/components/feedback-form.html +0 -111
- package/apps/hello-world/src/components/feedback-form.ts +0 -45
- package/apps/hello-world/src/components/notification-center.html +0 -119
- package/apps/hello-world/src/components/notification-center.ts +0 -27
- package/apps/hello-world/src/components/stat-card.html +0 -107
- package/apps/hello-world/src/components/stat-card.ts +0 -41
- package/apps/hello-world/src/components/weather-widget.html +0 -89
- package/apps/hello-world/src/components/weather-widget.ts +0 -31
- package/apps/hello-world/src/hello-world.html +0 -48
- package/apps/hello-world/src/hello-world.ts +0 -17
- package/apps/hello-world/src/main.ts +0 -6
- package/apps/hello-world/src/my-app.html +0 -1
- package/apps/hello-world/src/my-app.ts +0 -3
- package/apps/hello-world/src/resource.d.ts +0 -15
- package/apps/hello-world/src/services/weather-service.ts +0 -15
- package/apps/hello-world/src/stories/feedback-form.stories.ts +0 -58
- package/apps/hello-world/src/stories/hello-world.stories.ts +0 -64
- package/apps/hello-world/src/stories/notification-center.stories.ts +0 -88
- package/apps/hello-world/src/stories/stat-card.stories.ts +0 -75
- package/apps/hello-world/src/stories/weather-widget.stories.ts +0 -62
- package/apps/hello-world/test/my-app.spec.ts +0 -15
- package/apps/hello-world/test/setup.ts +0 -29
- package/apps/hello-world/tsconfig.json +0 -19
- package/apps/hello-world/tsconfig.vitest.json +0 -11
- package/apps/hello-world/vite.config.ts +0 -17
- package/apps/hello-world/vitest.config.ts +0 -15
- package/apps/hello-world-rsbuild/.storybook/main.ts +0 -16
- package/apps/hello-world-rsbuild/.storybook/preview.ts +0 -1
- package/apps/hello-world-rsbuild/.stylelintrc.json +0 -5
- package/apps/hello-world-rsbuild/README.md +0 -28
- package/apps/hello-world-rsbuild/eslint.config.mjs +0 -25
- package/apps/hello-world-rsbuild/favicon.ico +0 -0
- package/apps/hello-world-rsbuild/index.html +0 -17
- package/apps/hello-world-rsbuild/package-lock.json +0 -11131
- package/apps/hello-world-rsbuild/package.json +0 -56
- package/apps/hello-world-rsbuild/src/components/feedback-form.html +0 -111
- package/apps/hello-world-rsbuild/src/components/feedback-form.ts +0 -45
- package/apps/hello-world-rsbuild/src/components/notification-center.html +0 -119
- package/apps/hello-world-rsbuild/src/components/notification-center.ts +0 -27
- package/apps/hello-world-rsbuild/src/components/stat-card.html +0 -107
- package/apps/hello-world-rsbuild/src/components/stat-card.ts +0 -41
- package/apps/hello-world-rsbuild/src/components/weather-widget.html +0 -89
- package/apps/hello-world-rsbuild/src/components/weather-widget.ts +0 -31
- package/apps/hello-world-rsbuild/src/hello-world.html +0 -48
- package/apps/hello-world-rsbuild/src/hello-world.ts +0 -17
- package/apps/hello-world-rsbuild/src/main.ts +0 -6
- package/apps/hello-world-rsbuild/src/my-app.html +0 -1
- package/apps/hello-world-rsbuild/src/my-app.ts +0 -3
- package/apps/hello-world-rsbuild/src/resource.d.ts +0 -15
- package/apps/hello-world-rsbuild/src/services/weather-service.ts +0 -15
- package/apps/hello-world-rsbuild/src/stories/feedback-form.stories.ts +0 -58
- package/apps/hello-world-rsbuild/src/stories/hello-world.stories.ts +0 -64
- package/apps/hello-world-rsbuild/src/stories/notification-center.stories.ts +0 -88
- package/apps/hello-world-rsbuild/src/stories/stat-card.stories.ts +0 -75
- package/apps/hello-world-rsbuild/src/stories/weather-widget.stories.ts +0 -62
- package/apps/hello-world-rsbuild/test/my-app.spec.ts +0 -15
- package/apps/hello-world-rsbuild/test/setup.ts +0 -29
- package/apps/hello-world-rsbuild/tsconfig.json +0 -19
- package/apps/hello-world-rsbuild/tsconfig.vitest.json +0 -11
- package/apps/hello-world-rsbuild/vite.config.ts +0 -17
- package/apps/hello-world-rsbuild/vitest.config.ts +0 -15
- package/apps/hello-world-webpack/.env.development +0 -0
- package/apps/hello-world-webpack/.storybook/main.ts +0 -14
- package/apps/hello-world-webpack/.storybook/preview.ts +0 -3
- package/apps/hello-world-webpack/.stylelintrc.json +0 -5
- package/apps/hello-world-webpack/README.md +0 -29
- package/apps/hello-world-webpack/eslint.config.mjs +0 -25
- package/apps/hello-world-webpack/favicon.ico +0 -0
- package/apps/hello-world-webpack/index.html +0 -15
- package/apps/hello-world-webpack/package-lock.json +0 -9828
- package/apps/hello-world-webpack/package.json +0 -52
- package/apps/hello-world-webpack/src/components/feedback-form.html +0 -111
- package/apps/hello-world-webpack/src/components/feedback-form.ts +0 -45
- package/apps/hello-world-webpack/src/components/notification-center.html +0 -119
- package/apps/hello-world-webpack/src/components/notification-center.ts +0 -27
- package/apps/hello-world-webpack/src/components/stat-card.html +0 -107
- package/apps/hello-world-webpack/src/components/stat-card.ts +0 -41
- package/apps/hello-world-webpack/src/components/weather-widget.html +0 -89
- package/apps/hello-world-webpack/src/components/weather-widget.ts +0 -31
- package/apps/hello-world-webpack/src/hello-world.html +0 -48
- package/apps/hello-world-webpack/src/hello-world.ts +0 -17
- package/apps/hello-world-webpack/src/main.ts +0 -6
- package/apps/hello-world-webpack/src/my-app.css +0 -3
- package/apps/hello-world-webpack/src/my-app.html +0 -1
- package/apps/hello-world-webpack/src/my-app.stories.ts +0 -17
- package/apps/hello-world-webpack/src/my-app.ts +0 -3
- package/apps/hello-world-webpack/src/resource.d.ts +0 -13
- package/apps/hello-world-webpack/src/services/weather-service.ts +0 -15
- package/apps/hello-world-webpack/src/stories/feedback-form.stories.ts +0 -58
- package/apps/hello-world-webpack/src/stories/hello-world.stories.ts +0 -64
- package/apps/hello-world-webpack/src/stories/notification-center.stories.ts +0 -88
- package/apps/hello-world-webpack/src/stories/stat-card.stories.ts +0 -75
- package/apps/hello-world-webpack/src/stories/weather-widget.stories.ts +0 -62
- package/apps/hello-world-webpack/tsconfig.json +0 -18
- package/apps/hello-world-webpack/webpack.config.js +0 -111
- package/jest.config.cjs +0 -9
- package/rollup.config.mjs +0 -52
- package/scripts/sync-versions.cjs +0 -55
- package/src/index.ts +0 -42
- package/src/preset.ts +0 -79
- package/src/preview/helpers.ts +0 -7
- package/src/preview/render.ts +0 -243
- package/src/preview/storybook-types-runtime.ts +0 -2
- package/src/preview/storybook-types.ts +0 -34
- package/src/preview/types-runtime.ts +0 -2
- package/src/preview/types.ts +0 -62
- package/src/preview.ts +0 -11
- package/src/webpack.ts +0 -40
- package/tsconfig.build.json +0 -5
- package/tsconfig.json +0 -15
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "apptasks-video",
|
|
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
|
-
"@storybook/builder-vite": "^10.2.0",
|
|
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
|
-
"stylelint": "^16.12.0",
|
|
34
|
-
"stylelint-config-standard": "^36.0.1",
|
|
35
|
-
"stylus": "^0.64.0",
|
|
36
|
-
"tailwindcss": "^4.0.0",
|
|
37
|
-
"tslib": "^2.8.1",
|
|
38
|
-
"typescript": "^5.7.2",
|
|
39
|
-
"typescript-eslint": "^8.18.1",
|
|
40
|
-
"vite": "^7.0.0",
|
|
41
|
-
"vitest": "^4.0.0"
|
|
42
|
-
},
|
|
43
|
-
"scripts": {
|
|
44
|
-
"lint:js": "eslint src test",
|
|
45
|
-
"lint:css": "stylelint \"src/**/*.css\"",
|
|
46
|
-
"lint": "npm run lint:js && npm run lint:css",
|
|
47
|
-
"pretest": "npm run lint",
|
|
48
|
-
"start": "vite",
|
|
49
|
-
"build": "vite build",
|
|
50
|
-
"test": "vitest",
|
|
51
|
-
"storybook": "storybook dev -p 6006",
|
|
52
|
-
"build-storybook": "storybook build"
|
|
53
|
-
},
|
|
54
|
-
"type": "module"
|
|
55
|
-
}
|
|
@@ -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}°</p>
|
|
86
|
-
<p>${report.condition}</p>
|
|
87
|
-
<small>High ${report.high}° - Low ${report.low}°</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
|
-
}
|