widgies 0.1.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/README.md +105 -0
- package/dist/affirmation.d.ts +1 -0
- package/dist/affirmation.js +129 -0
- package/dist/affirmation.min.js +129 -0
- package/dist/ambient.d.ts +1 -0
- package/dist/ambient.js +191 -0
- package/dist/ambient.min.js +191 -0
- package/dist/calculator.d.ts +1 -0
- package/dist/calculator.js +97 -0
- package/dist/calculator.min.js +97 -0
- package/dist/chunk-3F3FJ7VN.js +82 -0
- package/dist/chunk-BP7C5X5K.min.js +82 -0
- package/dist/core/BaseWidget.d.ts +15 -0
- package/dist/core/theme.d.ts +2 -0
- package/dist/index.d.ts +8 -0
- package/dist/qr-code.d.ts +1 -0
- package/dist/qr-code.js +125 -0
- package/dist/qr-code.min.js +125 -0
- package/dist/qrcode-5PUKNF3Z.js +3 -0
- package/dist/qrcode-DXXPLUCT.min.js +3 -0
- package/dist/random-number.d.ts +1 -0
- package/dist/random-number.js +109 -0
- package/dist/random-number.min.js +109 -0
- package/dist/timer.d.ts +1 -0
- package/dist/timer.js +153 -0
- package/dist/timer.min.js +153 -0
- package/dist/widgets/affirmation.d.ts +21 -0
- package/dist/widgets/ambient.d.ts +34 -0
- package/dist/widgets/calculator.d.ts +18 -0
- package/dist/widgets/qr-code.d.ts +22 -0
- package/dist/widgets/random-number.d.ts +17 -0
- package/dist/widgets/timer.d.ts +30 -0
- package/dist/widgies.js +882 -0
- package/dist/widgies.min.js +882 -0
- package/package.json +83 -0
package/README.md
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
# Widgies
|
2
|
+
|
3
|
+
A tiny, zero-dependency set of Web Component widgets you can drop into any web page with one script tag.
|
4
|
+
|
5
|
+
- **Plain English docs**—no jargon.
|
6
|
+
- **Accessible by default**—ARIA labels, keyboard support, high-contrast, `prefers-reduced-motion`.
|
7
|
+
- **Auto light & dark themes**—switches with `prefers-color-scheme`.
|
8
|
+
- **Works everywhere**—React, Vue, Svelte, or just HTML.
|
9
|
+
|
10
|
+
## Quick Start
|
11
|
+
|
12
|
+
```html
|
13
|
+
<!-- 1. Import Widgies from a CDN or your build folder -->
|
14
|
+
<script type="module" src="https://unpkg.com/widgies@0.1.0/dist/widgies.min.js"></script>
|
15
|
+
|
16
|
+
<!-- 2. Optional: override design tokens -->
|
17
|
+
<style>
|
18
|
+
:root {
|
19
|
+
/* universal */
|
20
|
+
--widgies-radius: 0.5rem;
|
21
|
+
--widgies-font: 16px/1.4 Inter, sans-serif;
|
22
|
+
|
23
|
+
/* light mode */
|
24
|
+
--widgies-surface-light: #ffffffe6;
|
25
|
+
--widgies-text-light: #1a1a1a;
|
26
|
+
--widgies-accent-light: #6c4cff;
|
27
|
+
|
28
|
+
/* dark mode */
|
29
|
+
--widgies-surface-dark: #181824e6;
|
30
|
+
--widgies-text-dark: #f5f5ff;
|
31
|
+
--widgies-accent-dark: #a88bff;
|
32
|
+
}
|
33
|
+
</style>
|
34
|
+
|
35
|
+
<!-- 3. Drop a widget – no extra JS needed -->
|
36
|
+
<widgies-timer minutes="25" aria-label="25-minute timer"></widgies-timer>
|
37
|
+
```
|
38
|
+
|
39
|
+
## Widgets in v0.1.0
|
40
|
+
|
41
|
+
| Tag | What it does | Key attributes |
|
42
|
+
| ------------------------- | -------------------------- | ------------------- |
|
43
|
+
| `<widgies-calculator>` | 4-function calculator | – |
|
44
|
+
| `<widgies-random-number>` | Cryptographically safe RNG | `min` `max` |
|
45
|
+
| `<widgies-timer>` | Countdown / Pomodoro | `seconds` `minutes` |
|
46
|
+
| `<widgies-affirmation>` | Random positive message | `interval` (ms) |
|
47
|
+
| `<widgies-qr-code>` | QR code generator | `value` `size` |
|
48
|
+
| `<widgies-ambient>` | Rain, ocean, forest sounds | `sound` |
|
49
|
+
|
50
|
+
All widgets share **theme tokens**, **focus rings**, and **ARIA roles**. Bundle size ≈10 kB gzipped.
|
51
|
+
|
52
|
+
## Installation
|
53
|
+
|
54
|
+
```bash
|
55
|
+
npm install widgies
|
56
|
+
```
|
57
|
+
|
58
|
+
```js
|
59
|
+
// Option 1: Import all widgets (auto-registers)
|
60
|
+
import 'widgies';
|
61
|
+
|
62
|
+
// Option 2: Import individual widgets
|
63
|
+
import 'widgies/calculator';
|
64
|
+
import 'widgies/timer';
|
65
|
+
import 'widgies/random-number';
|
66
|
+
import 'widgies/affirmation';
|
67
|
+
import 'widgies/ambient';
|
68
|
+
import 'widgies/qr-code';
|
69
|
+
|
70
|
+
// Option 3: Import widget classes for manual registration
|
71
|
+
import { CalculatorWidget } from 'widgies';
|
72
|
+
CalculatorWidget.register();
|
73
|
+
```
|
74
|
+
|
75
|
+
Or via CDN:
|
76
|
+
|
77
|
+
```html
|
78
|
+
<script type="module" src="https://unpkg.com/widgies@latest/dist/widgies.min.js"></script>
|
79
|
+
```
|
80
|
+
|
81
|
+
## Development
|
82
|
+
|
83
|
+
```bash
|
84
|
+
# Install dependencies
|
85
|
+
npm install
|
86
|
+
|
87
|
+
# Build the widget bundle
|
88
|
+
npm run build
|
89
|
+
|
90
|
+
# Generate TypeScript declarations
|
91
|
+
npm run types
|
92
|
+
|
93
|
+
# Build and watch for changes
|
94
|
+
npm run dev
|
95
|
+
|
96
|
+
# Run tests
|
97
|
+
npm test
|
98
|
+
|
99
|
+
# Full build (bundle + types)
|
100
|
+
npm run prepare
|
101
|
+
```
|
102
|
+
|
103
|
+
## License
|
104
|
+
|
105
|
+
MIT
|
@@ -0,0 +1 @@
|
|
1
|
+
export { AffirmationWidget, register } from './widgets/affirmation.js';
|
@@ -0,0 +1,129 @@
|
|
1
|
+
import{a as r}from"./chunk-3F3FJ7VN.js";var i=class extends r{constructor(){super(...arguments);this.display=null;this.newButton=null;this.intervalId=null;this.autoInterval=0;this.affirmations=["You are capable of amazing things.","Every challenge is an opportunity to grow.","You have the strength to overcome anything.","Your potential is limitless.","You are exactly where you need to be.","Progress, not perfection, is the goal.","You deserve good things in your life.","Your efforts are making a difference.","You are braver than you believe.","Today is full of possibilities.","You are worthy of love and respect.","Your unique perspective matters.","You have overcome challenges before.","Small steps lead to big changes.","You are learning and growing every day.","Your kindness makes the world better.","You have everything you need within you.","You are creating your own path.","Your dreams are valid and achievable.","You radiate positive energy.","You are enough, just as you are.","Every day is a fresh start.","You choose how to respond to life.","Your creativity knows no bounds.","You make a positive impact on others."];this.currentAffirmation=""}render(){this.shadow.innerHTML="";let e=this.createStyleSheet();e&&this.shadow.appendChild(e),this.autoInterval=parseInt(this.getAttribute("interval")||"0"),this.currentAffirmation=this.getRandomAffirmation();let t=document.createElement("div");t.innerHTML=`
|
2
|
+
<div class="affirmation" role="region" aria-label="Daily affirmation">
|
3
|
+
<div class="display" aria-live="polite" aria-label="Current affirmation">
|
4
|
+
${this.currentAffirmation}
|
5
|
+
</div>
|
6
|
+
<button class="new-btn" aria-label="Get new affirmation">
|
7
|
+
\u2728 New Affirmation
|
8
|
+
</button>
|
9
|
+
${this.autoInterval>0?'<div class="auto-indicator">Auto-refreshing</div>':""}
|
10
|
+
</div>
|
11
|
+
`,this.shadow.appendChild(t),this.display=this.shadow.querySelector(".display"),this.newButton=this.shadow.querySelector(".new-btn")}attachEventListeners(){this.newButton?.addEventListener("click",()=>{this.showNewAffirmation()}),this.addEventListener("keydown",e=>{(e.key==="Enter"||e.key===" ")&&(e.preventDefault(),this.showNewAffirmation())})}getRandomAffirmation(){let e;do{let t=Math.floor(Math.random()*this.affirmations.length);e=this.affirmations[t]}while(e===this.currentAffirmation&&this.affirmations.length>1);return e}showNewAffirmation(){this.display&&(this.display.classList.add("fade-out"),setTimeout(()=>{this.currentAffirmation=this.getRandomAffirmation(),this.display&&(this.display.textContent=this.currentAffirmation,this.display.classList.remove("fade-out"),this.display.classList.add("fade-in"),setTimeout(()=>{this.display?.classList.remove("fade-in")},300)),this.dispatchEvent(new CustomEvent("affirmation-changed",{detail:{affirmation:this.currentAffirmation},bubbles:!0}))},150))}startAutoInterval(){this.autoInterval>0&&(this.intervalId=window.setInterval(()=>{this.showNewAffirmation()},this.autoInterval))}stopAutoInterval(){this.intervalId&&(clearInterval(this.intervalId),this.intervalId=null)}static get observedAttributes(){return["interval"]}attributeChangedCallback(e,t,o){if(e==="interval"){this.stopAutoInterval(),this.autoInterval=parseInt(o||"0"),this.autoInterval>0&&this.startAutoInterval();let a=this.shadow.querySelector(".auto-indicator");a&&(a.style.display=this.autoInterval>0?"block":"none")}}connectedCallback(){super.connectedCallback(),this.startAutoInterval()}disconnectedCallback(){super.disconnectedCallback(),this.stopAutoInterval()}getStyles(){return`
|
12
|
+
${this.getBaseStyles()}
|
13
|
+
|
14
|
+
.affirmation {
|
15
|
+
width: 350px;
|
16
|
+
text-align: center;
|
17
|
+
}
|
18
|
+
|
19
|
+
.display {
|
20
|
+
padding: 2rem 1.5rem;
|
21
|
+
margin-bottom: 1rem;
|
22
|
+
border-radius: var(--widgies-radius, 0.5rem);
|
23
|
+
background: linear-gradient(135deg,
|
24
|
+
var(--widgies-accent, var(--widgies-accent-light, #6c4cff)) 0%,
|
25
|
+
color-mix(in srgb, var(--widgies-accent, var(--widgies-accent-light, #6c4cff)) 80%, var(--widgies-surface, var(--widgies-surface-light, #ffffffe6))) 100%);
|
26
|
+
color: white;
|
27
|
+
font-size: 1.2rem;
|
28
|
+
font-weight: 500;
|
29
|
+
line-height: 1.6;
|
30
|
+
min-height: 4rem;
|
31
|
+
display: flex;
|
32
|
+
align-items: center;
|
33
|
+
justify-content: center;
|
34
|
+
text-align: center;
|
35
|
+
box-shadow: 0 4px 12px color-mix(in srgb, var(--widgies-accent, var(--widgies-accent-light, #6c4cff)) 25%, transparent);
|
36
|
+
transition: opacity 0.15s ease, transform 0.15s ease;
|
37
|
+
}
|
38
|
+
|
39
|
+
.display.fade-out {
|
40
|
+
opacity: 0;
|
41
|
+
transform: translateY(-10px);
|
42
|
+
}
|
43
|
+
|
44
|
+
.display.fade-in {
|
45
|
+
opacity: 1;
|
46
|
+
transform: translateY(0);
|
47
|
+
}
|
48
|
+
|
49
|
+
.new-btn {
|
50
|
+
width: 100%;
|
51
|
+
padding: 0.75rem 1.5rem;
|
52
|
+
font-size: 1rem;
|
53
|
+
font-weight: 600;
|
54
|
+
background: var(--widgies-surface, var(--widgies-surface-light, #ffffffe6));
|
55
|
+
color: var(--widgies-accent, var(--widgies-accent-light, #6c4cff));
|
56
|
+
border: 2px solid var(--widgies-accent, var(--widgies-accent-light, #6c4cff));
|
57
|
+
transition: all 0.2s ease;
|
58
|
+
}
|
59
|
+
|
60
|
+
.new-btn:hover {
|
61
|
+
background: var(--widgies-accent, var(--widgies-accent-light, #6c4cff));
|
62
|
+
color: white;
|
63
|
+
transform: translateY(-2px);
|
64
|
+
box-shadow: 0 4px 12px color-mix(in srgb, var(--widgies-accent, var(--widgies-accent-light, #6c4cff)) 30%, transparent);
|
65
|
+
}
|
66
|
+
|
67
|
+
.new-btn:active {
|
68
|
+
transform: translateY(0);
|
69
|
+
}
|
70
|
+
|
71
|
+
.auto-indicator {
|
72
|
+
margin-top: 0.5rem;
|
73
|
+
font-size: 0.8rem;
|
74
|
+
color: color-mix(in srgb, var(--widgies-text, var(--widgies-text-light, #1a1a1a)) 70%, transparent);
|
75
|
+
font-style: italic;
|
76
|
+
}
|
77
|
+
|
78
|
+
.auto-indicator::before {
|
79
|
+
content: "\u{1F504} ";
|
80
|
+
animation: rotate 2s linear infinite;
|
81
|
+
}
|
82
|
+
|
83
|
+
@keyframes rotate {
|
84
|
+
from { transform: rotate(0deg); }
|
85
|
+
to { transform: rotate(360deg); }
|
86
|
+
}
|
87
|
+
|
88
|
+
@media (prefers-color-scheme: dark) {
|
89
|
+
.display {
|
90
|
+
background: linear-gradient(135deg,
|
91
|
+
var(--widgies-accent, var(--widgies-accent-dark, #a88bff)) 0%,
|
92
|
+
color-mix(in srgb, var(--widgies-accent, var(--widgies-accent-dark, #a88bff)) 80%, var(--widgies-surface, var(--widgies-surface-dark, #181824e6))) 100%);
|
93
|
+
box-shadow: 0 4px 12px color-mix(in srgb, var(--widgies-accent, var(--widgies-accent-dark, #a88bff)) 25%, transparent);
|
94
|
+
}
|
95
|
+
|
96
|
+
.new-btn {
|
97
|
+
background: var(--widgies-surface, var(--widgies-surface-dark, #181824e6));
|
98
|
+
color: var(--widgies-accent, var(--widgies-accent-dark, #a88bff));
|
99
|
+
border-color: var(--widgies-accent, var(--widgies-accent-dark, #a88bff));
|
100
|
+
}
|
101
|
+
|
102
|
+
.new-btn:hover {
|
103
|
+
background: var(--widgies-accent, var(--widgies-accent-dark, #a88bff));
|
104
|
+
box-shadow: 0 4px 12px color-mix(in srgb, var(--widgies-accent, var(--widgies-accent-dark, #a88bff)) 30%, transparent);
|
105
|
+
}
|
106
|
+
|
107
|
+
.auto-indicator {
|
108
|
+
color: color-mix(in srgb, var(--widgies-text, var(--widgies-text-dark, #f5f5ff)) 70%, transparent);
|
109
|
+
}
|
110
|
+
}
|
111
|
+
|
112
|
+
@media (prefers-reduced-motion: reduce) {
|
113
|
+
.display {
|
114
|
+
transition: none;
|
115
|
+
}
|
116
|
+
|
117
|
+
.new-btn {
|
118
|
+
transition: none;
|
119
|
+
}
|
120
|
+
|
121
|
+
.new-btn:hover {
|
122
|
+
transform: none;
|
123
|
+
}
|
124
|
+
|
125
|
+
.auto-indicator::before {
|
126
|
+
animation: none;
|
127
|
+
}
|
128
|
+
}
|
129
|
+
`}};function n(){customElements.get("widgies-affirmation")||customElements.define("widgies-affirmation",i)}n();export{i as AffirmationWidget,n as register};
|
@@ -0,0 +1,129 @@
|
|
1
|
+
import{a as r}from"./chunk-BP7C5X5K.min.js";var i=class extends r{constructor(){super(...arguments);this.display=null;this.newButton=null;this.intervalId=null;this.autoInterval=0;this.affirmations=["You are capable of amazing things.","Every challenge is an opportunity to grow.","You have the strength to overcome anything.","Your potential is limitless.","You are exactly where you need to be.","Progress, not perfection, is the goal.","You deserve good things in your life.","Your efforts are making a difference.","You are braver than you believe.","Today is full of possibilities.","You are worthy of love and respect.","Your unique perspective matters.","You have overcome challenges before.","Small steps lead to big changes.","You are learning and growing every day.","Your kindness makes the world better.","You have everything you need within you.","You are creating your own path.","Your dreams are valid and achievable.","You radiate positive energy.","You are enough, just as you are.","Every day is a fresh start.","You choose how to respond to life.","Your creativity knows no bounds.","You make a positive impact on others."];this.currentAffirmation=""}render(){this.shadow.innerHTML="";let e=this.createStyleSheet();e&&this.shadow.appendChild(e),this.autoInterval=parseInt(this.getAttribute("interval")||"0"),this.currentAffirmation=this.getRandomAffirmation();let t=document.createElement("div");t.innerHTML=`
|
2
|
+
<div class="affirmation" role="region" aria-label="Daily affirmation">
|
3
|
+
<div class="display" aria-live="polite" aria-label="Current affirmation">
|
4
|
+
${this.currentAffirmation}
|
5
|
+
</div>
|
6
|
+
<button class="new-btn" aria-label="Get new affirmation">
|
7
|
+
\u2728 New Affirmation
|
8
|
+
</button>
|
9
|
+
${this.autoInterval>0?'<div class="auto-indicator">Auto-refreshing</div>':""}
|
10
|
+
</div>
|
11
|
+
`,this.shadow.appendChild(t),this.display=this.shadow.querySelector(".display"),this.newButton=this.shadow.querySelector(".new-btn")}attachEventListeners(){this.newButton?.addEventListener("click",()=>{this.showNewAffirmation()}),this.addEventListener("keydown",e=>{(e.key==="Enter"||e.key===" ")&&(e.preventDefault(),this.showNewAffirmation())})}getRandomAffirmation(){let e;do{let t=Math.floor(Math.random()*this.affirmations.length);e=this.affirmations[t]}while(e===this.currentAffirmation&&this.affirmations.length>1);return e}showNewAffirmation(){this.display&&(this.display.classList.add("fade-out"),setTimeout(()=>{this.currentAffirmation=this.getRandomAffirmation(),this.display&&(this.display.textContent=this.currentAffirmation,this.display.classList.remove("fade-out"),this.display.classList.add("fade-in"),setTimeout(()=>{this.display?.classList.remove("fade-in")},300)),this.dispatchEvent(new CustomEvent("affirmation-changed",{detail:{affirmation:this.currentAffirmation},bubbles:!0}))},150))}startAutoInterval(){this.autoInterval>0&&(this.intervalId=window.setInterval(()=>{this.showNewAffirmation()},this.autoInterval))}stopAutoInterval(){this.intervalId&&(clearInterval(this.intervalId),this.intervalId=null)}static get observedAttributes(){return["interval"]}attributeChangedCallback(e,t,o){if(e==="interval"){this.stopAutoInterval(),this.autoInterval=parseInt(o||"0"),this.autoInterval>0&&this.startAutoInterval();let a=this.shadow.querySelector(".auto-indicator");a&&(a.style.display=this.autoInterval>0?"block":"none")}}connectedCallback(){super.connectedCallback(),this.startAutoInterval()}disconnectedCallback(){super.disconnectedCallback(),this.stopAutoInterval()}getStyles(){return`
|
12
|
+
${this.getBaseStyles()}
|
13
|
+
|
14
|
+
.affirmation {
|
15
|
+
width: 350px;
|
16
|
+
text-align: center;
|
17
|
+
}
|
18
|
+
|
19
|
+
.display {
|
20
|
+
padding: 2rem 1.5rem;
|
21
|
+
margin-bottom: 1rem;
|
22
|
+
border-radius: var(--widgies-radius, 0.5rem);
|
23
|
+
background: linear-gradient(135deg,
|
24
|
+
var(--widgies-accent, var(--widgies-accent-light, #6c4cff)) 0%,
|
25
|
+
color-mix(in srgb, var(--widgies-accent, var(--widgies-accent-light, #6c4cff)) 80%, var(--widgies-surface, var(--widgies-surface-light, #ffffffe6))) 100%);
|
26
|
+
color: white;
|
27
|
+
font-size: 1.2rem;
|
28
|
+
font-weight: 500;
|
29
|
+
line-height: 1.6;
|
30
|
+
min-height: 4rem;
|
31
|
+
display: flex;
|
32
|
+
align-items: center;
|
33
|
+
justify-content: center;
|
34
|
+
text-align: center;
|
35
|
+
box-shadow: 0 4px 12px color-mix(in srgb, var(--widgies-accent, var(--widgies-accent-light, #6c4cff)) 25%, transparent);
|
36
|
+
transition: opacity 0.15s ease, transform 0.15s ease;
|
37
|
+
}
|
38
|
+
|
39
|
+
.display.fade-out {
|
40
|
+
opacity: 0;
|
41
|
+
transform: translateY(-10px);
|
42
|
+
}
|
43
|
+
|
44
|
+
.display.fade-in {
|
45
|
+
opacity: 1;
|
46
|
+
transform: translateY(0);
|
47
|
+
}
|
48
|
+
|
49
|
+
.new-btn {
|
50
|
+
width: 100%;
|
51
|
+
padding: 0.75rem 1.5rem;
|
52
|
+
font-size: 1rem;
|
53
|
+
font-weight: 600;
|
54
|
+
background: var(--widgies-surface, var(--widgies-surface-light, #ffffffe6));
|
55
|
+
color: var(--widgies-accent, var(--widgies-accent-light, #6c4cff));
|
56
|
+
border: 2px solid var(--widgies-accent, var(--widgies-accent-light, #6c4cff));
|
57
|
+
transition: all 0.2s ease;
|
58
|
+
}
|
59
|
+
|
60
|
+
.new-btn:hover {
|
61
|
+
background: var(--widgies-accent, var(--widgies-accent-light, #6c4cff));
|
62
|
+
color: white;
|
63
|
+
transform: translateY(-2px);
|
64
|
+
box-shadow: 0 4px 12px color-mix(in srgb, var(--widgies-accent, var(--widgies-accent-light, #6c4cff)) 30%, transparent);
|
65
|
+
}
|
66
|
+
|
67
|
+
.new-btn:active {
|
68
|
+
transform: translateY(0);
|
69
|
+
}
|
70
|
+
|
71
|
+
.auto-indicator {
|
72
|
+
margin-top: 0.5rem;
|
73
|
+
font-size: 0.8rem;
|
74
|
+
color: color-mix(in srgb, var(--widgies-text, var(--widgies-text-light, #1a1a1a)) 70%, transparent);
|
75
|
+
font-style: italic;
|
76
|
+
}
|
77
|
+
|
78
|
+
.auto-indicator::before {
|
79
|
+
content: "\u{1F504} ";
|
80
|
+
animation: rotate 2s linear infinite;
|
81
|
+
}
|
82
|
+
|
83
|
+
@keyframes rotate {
|
84
|
+
from { transform: rotate(0deg); }
|
85
|
+
to { transform: rotate(360deg); }
|
86
|
+
}
|
87
|
+
|
88
|
+
@media (prefers-color-scheme: dark) {
|
89
|
+
.display {
|
90
|
+
background: linear-gradient(135deg,
|
91
|
+
var(--widgies-accent, var(--widgies-accent-dark, #a88bff)) 0%,
|
92
|
+
color-mix(in srgb, var(--widgies-accent, var(--widgies-accent-dark, #a88bff)) 80%, var(--widgies-surface, var(--widgies-surface-dark, #181824e6))) 100%);
|
93
|
+
box-shadow: 0 4px 12px color-mix(in srgb, var(--widgies-accent, var(--widgies-accent-dark, #a88bff)) 25%, transparent);
|
94
|
+
}
|
95
|
+
|
96
|
+
.new-btn {
|
97
|
+
background: var(--widgies-surface, var(--widgies-surface-dark, #181824e6));
|
98
|
+
color: var(--widgies-accent, var(--widgies-accent-dark, #a88bff));
|
99
|
+
border-color: var(--widgies-accent, var(--widgies-accent-dark, #a88bff));
|
100
|
+
}
|
101
|
+
|
102
|
+
.new-btn:hover {
|
103
|
+
background: var(--widgies-accent, var(--widgies-accent-dark, #a88bff));
|
104
|
+
box-shadow: 0 4px 12px color-mix(in srgb, var(--widgies-accent, var(--widgies-accent-dark, #a88bff)) 30%, transparent);
|
105
|
+
}
|
106
|
+
|
107
|
+
.auto-indicator {
|
108
|
+
color: color-mix(in srgb, var(--widgies-text, var(--widgies-text-dark, #f5f5ff)) 70%, transparent);
|
109
|
+
}
|
110
|
+
}
|
111
|
+
|
112
|
+
@media (prefers-reduced-motion: reduce) {
|
113
|
+
.display {
|
114
|
+
transition: none;
|
115
|
+
}
|
116
|
+
|
117
|
+
.new-btn {
|
118
|
+
transition: none;
|
119
|
+
}
|
120
|
+
|
121
|
+
.new-btn:hover {
|
122
|
+
transform: none;
|
123
|
+
}
|
124
|
+
|
125
|
+
.auto-indicator::before {
|
126
|
+
animation: none;
|
127
|
+
}
|
128
|
+
}
|
129
|
+
`}};function n(){customElements.get("widgies-affirmation")||customElements.define("widgies-affirmation",i)}n();export{i as AffirmationWidget,n as register};
|
@@ -0,0 +1 @@
|
|
1
|
+
export { AmbientWidget, register } from './widgets/ambient.js';
|
package/dist/ambient.js
ADDED
@@ -0,0 +1,191 @@
|
|
1
|
+
import{a as o}from"./chunk-3F3FJ7VN.js";var n=class extends o{constructor(){super(...arguments);this.audioContext=null;this.oscillators=[];this.gainNodes=[];this.gainNode=null;this.isPlaying=!1;this.currentSound="rain";this.playButton=null;this.soundSelect=null;this.volumeSlider=null;this.sounds={rain:{name:"Rain",icon:"\u{1F327}\uFE0F"},ocean:{name:"Ocean Waves",icon:"\u{1F30A}"},forest:{name:"Forest",icon:"\u{1F332}"},river:{name:"River",icon:"\u{1F3DE}\uFE0F"},campfire:{name:"Crackling Campfire",icon:"\u{1F525}"}}}render(){this.shadow.innerHTML="";let t=this.createStyleSheet();t&&this.shadow.appendChild(t);let e=this.getAttribute("sound")||"rain";e in this.sounds&&(this.currentSound=e);let i=document.createElement("div");i.innerHTML=`
|
2
|
+
<div class="ambient" role="application" aria-label="Ambient sound player">
|
3
|
+
<div class="sound-display">
|
4
|
+
<span class="sound-icon">${this.sounds[this.currentSound].icon}</span>
|
5
|
+
<span class="sound-name">${this.sounds[this.currentSound].name}</span>
|
6
|
+
</div>
|
7
|
+
|
8
|
+
<div class="controls">
|
9
|
+
<select class="sound-select" aria-label="Choose ambient sound">
|
10
|
+
${Object.entries(this.sounds).map(([a,s])=>`<option value="${a}" ${a===this.currentSound?"selected":""}>${s.icon} ${s.name}</option>`).join("")}
|
11
|
+
</select>
|
12
|
+
|
13
|
+
<button class="play-btn" aria-label="Play or pause ambient sound">
|
14
|
+
<span class="play-icon">\u25B6</span>
|
15
|
+
<span class="pause-icon" style="display: none">\u23F8</span>
|
16
|
+
</button>
|
17
|
+
</div>
|
18
|
+
|
19
|
+
<div class="volume-control">
|
20
|
+
<label>
|
21
|
+
<span class="volume-label">\u{1F50A} Volume</span>
|
22
|
+
<input type="range" class="volume-slider" min="0" max="100" value="50" aria-label="Volume control">
|
23
|
+
</label>
|
24
|
+
</div>
|
25
|
+
|
26
|
+
<div class="status" aria-live="polite" aria-label="Player status">
|
27
|
+
Ready to play
|
28
|
+
</div>
|
29
|
+
</div>
|
30
|
+
`,this.shadow.appendChild(i),this.playButton=this.shadow.querySelector(".play-btn"),this.soundSelect=this.shadow.querySelector(".sound-select"),this.volumeSlider=this.shadow.querySelector(".volume-slider")}attachEventListeners(){this.playButton?.addEventListener("click",()=>{this.togglePlayback()}),this.soundSelect?.addEventListener("change",()=>{this.changeSound(this.soundSelect.value)}),this.volumeSlider?.addEventListener("input",()=>{this.updateVolume()}),this.addEventListener("keydown",t=>{t.key===" "&&(t.preventDefault(),this.togglePlayback())})}async initAudioContext(){this.audioContext||(this.audioContext=new(window.AudioContext||window.webkitAudioContext)),this.audioContext.state==="suspended"&&await this.audioContext.resume(),this.gainNode||(this.gainNode=this.audioContext.createGain(),this.gainNode.connect(this.audioContext.destination))}createWhiteNoise(){if(!this.audioContext)throw new Error("AudioContext not initialized");let t=this.audioContext.sampleRate*2,e=this.audioContext.createBuffer(1,t,this.audioContext.sampleRate),i=e.getChannelData(0);for(let s=0;s<t;s++)i[s]=Math.random()*2-1;let a=this.audioContext.createBufferSource();return a.buffer=e,a.loop=!0,a}createRainSound(){let t=this.createWhiteNoise(),e=this.audioContext.createBiquadFilter();return e.type="lowpass",e.frequency.value=1e3,t.connect(e),e.connect(this.gainNode),t}createOceanSound(){let t=this.createWhiteNoise(),e=this.audioContext.createBiquadFilter();e.type="lowpass",e.frequency.value=400;let i=this.audioContext.createOscillator(),a=this.audioContext.createGain();return i.frequency.value=.1,a.gain.value=200,i.connect(a),a.connect(e.frequency),t.connect(e),e.connect(this.gainNode),i.start(),t}createForestSound(){let t=this.createWhiteNoise(),e=this.audioContext.createBiquadFilter();return e.type="bandpass",e.frequency.value=800,e.Q.value=.5,t.connect(e),e.connect(this.gainNode),t}createCampfireSound(){let t=this.createWhiteNoise(),e=this.audioContext.createBiquadFilter();return e.type="lowpass",e.frequency.value=300,t.connect(e),e.connect(this.gainNode),t}async togglePlayback(){try{await this.initAudioContext(),this.isPlaying?this.stopSound():await this.playSound()}catch{this.updateStatus("Audio not available")}}async playSound(){if(!this.audioContext||!this.gainNode)return;let t=this.sounds[this.currentSound],e=parseInt(this.volumeSlider?.value||"50")/100;this.gainNode.gain.setValueAtTime(e*.3,this.audioContext.currentTime);let i;switch(this.currentSound){case"rain":i=this.createRainSound();break;case"ocean":i=this.createOceanSound();break;case"forest":i=this.createForestSound();break;case"campfire":i=this.createCampfireSound();break;case"river":i=this.createForestSound();break;default:i=this.createRainSound()}i.start(),this.oscillators=[i],this.isPlaying=!0,this.updatePlayButton(),this.updateStatus(`Playing ${t.name}`),this.dispatchEvent(new CustomEvent("ambient-started",{detail:{sound:this.currentSound,volume:e},bubbles:!0}))}stopSound(){this.oscillators.forEach(t=>{this.audioContext&&t.stop&&t.stop(this.audioContext.currentTime+.1)}),this.gainNode&&this.audioContext&&this.gainNode.gain.linearRampToValueAtTime(0,this.audioContext.currentTime+.1),this.oscillators=[],this.gainNodes=[],this.isPlaying=!1,this.updatePlayButton(),this.updateStatus("Stopped"),this.dispatchEvent(new CustomEvent("ambient-stopped",{detail:{sound:this.currentSound},bubbles:!0}))}changeSound(t){let e=this.isPlaying;this.isPlaying&&this.stopSound(),this.currentSound=t,this.updateSoundDisplay(),e&&setTimeout(()=>this.playSound(),200),this.dispatchEvent(new CustomEvent("ambient-changed",{detail:{sound:this.currentSound},bubbles:!0}))}updateVolume(){if(!this.volumeSlider||!this.isPlaying||!this.gainNode||!this.audioContext)return;let t=parseInt(this.volumeSlider.value)/100;this.gainNode.gain.linearRampToValueAtTime(t*.3,this.audioContext.currentTime+.1)}updatePlayButton(){let t=this.shadow.querySelector(".play-icon"),e=this.shadow.querySelector(".pause-icon");t&&e&&(this.isPlaying?(t.style.display="none",e.style.display="inline"):(t.style.display="inline",e.style.display="none"))}updateSoundDisplay(){let t=this.shadow.querySelector(".sound-icon"),e=this.shadow.querySelector(".sound-name"),i=this.sounds[this.currentSound];t&&(t.textContent=i.icon),e&&(e.textContent=i.name)}updateStatus(t){let e=this.shadow.querySelector(".status");e&&(e.textContent=t)}static get observedAttributes(){return["sound"]}attributeChangedCallback(t,e,i){t==="sound"&&i&&i in this.sounds&&(this.changeSound(i),this.soundSelect&&(this.soundSelect.value=i))}disconnectedCallback(){super.disconnectedCallback(),this.isPlaying&&this.stopSound(),this.audioContext&&this.audioContext.close()}getStyles(){return`
|
31
|
+
${this.getBaseStyles()}
|
32
|
+
|
33
|
+
.ambient {
|
34
|
+
width: 300px;
|
35
|
+
text-align: center;
|
36
|
+
}
|
37
|
+
|
38
|
+
.sound-display {
|
39
|
+
display: flex;
|
40
|
+
align-items: center;
|
41
|
+
justify-content: center;
|
42
|
+
gap: 0.75rem;
|
43
|
+
margin-bottom: 1.5rem;
|
44
|
+
padding: 1rem;
|
45
|
+
background: linear-gradient(135deg,
|
46
|
+
var(--widgies-accent, var(--widgies-accent-light, #6c4cff)) 10%,
|
47
|
+
transparent 50%);
|
48
|
+
border-radius: var(--widgies-radius, 0.5rem);
|
49
|
+
border: 1px solid color-mix(in srgb, var(--widgies-accent, var(--widgies-accent-light, #6c4cff)) 30%, transparent);
|
50
|
+
}
|
51
|
+
|
52
|
+
.sound-icon {
|
53
|
+
font-size: 2rem;
|
54
|
+
}
|
55
|
+
|
56
|
+
.sound-name {
|
57
|
+
font-size: 1.2rem;
|
58
|
+
font-weight: 600;
|
59
|
+
color: var(--widgies-accent, var(--widgies-accent-light, #6c4cff));
|
60
|
+
}
|
61
|
+
|
62
|
+
.controls {
|
63
|
+
display: flex;
|
64
|
+
gap: 1rem;
|
65
|
+
margin-bottom: 1.5rem;
|
66
|
+
align-items: center;
|
67
|
+
}
|
68
|
+
|
69
|
+
.sound-select {
|
70
|
+
flex: 1;
|
71
|
+
padding: 0.75rem;
|
72
|
+
border: 1px solid color-mix(in srgb, var(--widgies-text, var(--widgies-text-light, #1a1a1a)) 30%, transparent);
|
73
|
+
border-radius: var(--widgies-radius, 0.5rem);
|
74
|
+
background: var(--widgies-surface, var(--widgies-surface-light, #ffffffe6));
|
75
|
+
color: var(--widgies-text, var(--widgies-text-light, #1a1a1a));
|
76
|
+
font: inherit;
|
77
|
+
}
|
78
|
+
|
79
|
+
.sound-select:focus {
|
80
|
+
outline: 2px solid var(--widgies-accent, var(--widgies-accent-light, #6c4cff));
|
81
|
+
outline-offset: 1px;
|
82
|
+
}
|
83
|
+
|
84
|
+
.play-btn {
|
85
|
+
width: 60px;
|
86
|
+
height: 60px;
|
87
|
+
border-radius: 50%;
|
88
|
+
font-size: 1.5rem;
|
89
|
+
display: flex;
|
90
|
+
align-items: center;
|
91
|
+
justify-content: center;
|
92
|
+
padding: 0;
|
93
|
+
box-shadow: 0 4px 12px color-mix(in srgb, var(--widgies-accent, var(--widgies-accent-light, #6c4cff)) 25%, transparent);
|
94
|
+
}
|
95
|
+
|
96
|
+
.volume-control {
|
97
|
+
margin-bottom: 1rem;
|
98
|
+
}
|
99
|
+
|
100
|
+
.volume-control label {
|
101
|
+
display: flex;
|
102
|
+
flex-direction: column;
|
103
|
+
gap: 0.5rem;
|
104
|
+
align-items: center;
|
105
|
+
}
|
106
|
+
|
107
|
+
.volume-label {
|
108
|
+
font-size: 0.9rem;
|
109
|
+
font-weight: 500;
|
110
|
+
}
|
111
|
+
|
112
|
+
.volume-slider {
|
113
|
+
width: 100%;
|
114
|
+
height: 8px;
|
115
|
+
border-radius: 4px;
|
116
|
+
background: color-mix(in srgb, var(--widgies-text, var(--widgies-text-light, #1a1a1a)) 20%, transparent);
|
117
|
+
outline: none;
|
118
|
+
-webkit-appearance: none;
|
119
|
+
}
|
120
|
+
|
121
|
+
.volume-slider::-webkit-slider-thumb {
|
122
|
+
-webkit-appearance: none;
|
123
|
+
width: 20px;
|
124
|
+
height: 20px;
|
125
|
+
border-radius: 50%;
|
126
|
+
background: var(--widgies-accent, var(--widgies-accent-light, #6c4cff));
|
127
|
+
cursor: pointer;
|
128
|
+
box-shadow: 0 2px 6px color-mix(in srgb, var(--widgies-accent, var(--widgies-accent-light, #6c4cff)) 40%, transparent);
|
129
|
+
}
|
130
|
+
|
131
|
+
.volume-slider::-moz-range-thumb {
|
132
|
+
width: 20px;
|
133
|
+
height: 20px;
|
134
|
+
border-radius: 50%;
|
135
|
+
background: var(--widgies-accent, var(--widgies-accent-light, #6c4cff));
|
136
|
+
cursor: pointer;
|
137
|
+
border: none;
|
138
|
+
box-shadow: 0 2px 6px color-mix(in srgb, var(--widgies-accent, var(--widgies-accent-light, #6c4cff)) 40%, transparent);
|
139
|
+
}
|
140
|
+
|
141
|
+
.status {
|
142
|
+
font-size: 0.9rem;
|
143
|
+
color: color-mix(in srgb, var(--widgies-text, var(--widgies-text-light, #1a1a1a)) 70%, transparent);
|
144
|
+
font-style: italic;
|
145
|
+
}
|
146
|
+
|
147
|
+
@media (prefers-color-scheme: dark) {
|
148
|
+
.sound-display {
|
149
|
+
background: linear-gradient(135deg,
|
150
|
+
var(--widgies-accent, var(--widgies-accent-dark, #a88bff)) 10%,
|
151
|
+
transparent 50%);
|
152
|
+
border-color: color-mix(in srgb, var(--widgies-accent, var(--widgies-accent-dark, #a88bff)) 30%, transparent);
|
153
|
+
}
|
154
|
+
|
155
|
+
.sound-name {
|
156
|
+
color: var(--widgies-accent, var(--widgies-accent-dark, #a88bff));
|
157
|
+
}
|
158
|
+
|
159
|
+
.sound-select {
|
160
|
+
background: var(--widgies-surface, var(--widgies-surface-dark, #181824e6));
|
161
|
+
color: var(--widgies-text, var(--widgies-text-dark, #f5f5ff));
|
162
|
+
border-color: color-mix(in srgb, var(--widgies-text, var(--widgies-text-dark, #f5f5ff)) 30%, transparent);
|
163
|
+
}
|
164
|
+
|
165
|
+
.sound-select:focus {
|
166
|
+
outline-color: var(--widgies-accent, var(--widgies-accent-dark, #a88bff));
|
167
|
+
}
|
168
|
+
|
169
|
+
.play-btn {
|
170
|
+
box-shadow: 0 4px 12px color-mix(in srgb, var(--widgies-accent, var(--widgies-accent-dark, #a88bff)) 25%, transparent);
|
171
|
+
}
|
172
|
+
|
173
|
+
.volume-slider {
|
174
|
+
background: color-mix(in srgb, var(--widgies-text, var(--widgies-text-dark, #f5f5ff)) 20%, transparent);
|
175
|
+
}
|
176
|
+
|
177
|
+
.volume-slider::-webkit-slider-thumb {
|
178
|
+
background: var(--widgies-accent, var(--widgies-accent-dark, #a88bff));
|
179
|
+
box-shadow: 0 2px 6px color-mix(in srgb, var(--widgies-accent, var(--widgies-accent-dark, #a88bff)) 40%, transparent);
|
180
|
+
}
|
181
|
+
|
182
|
+
.volume-slider::-moz-range-thumb {
|
183
|
+
background: var(--widgies-accent, var(--widgies-accent-dark, #a88bff));
|
184
|
+
box-shadow: 0 2px 6px color-mix(in srgb, var(--widgies-accent, var(--widgies-accent-dark, #a88bff)) 40%, transparent);
|
185
|
+
}
|
186
|
+
|
187
|
+
.status {
|
188
|
+
color: color-mix(in srgb, var(--widgies-text, var(--widgies-text-dark, #f5f5ff)) 70%, transparent);
|
189
|
+
}
|
190
|
+
}
|
191
|
+
`}};function r(){customElements.get("widgies-ambient")||customElements.define("widgies-ambient",n)}r();export{n as AmbientWidget,r as register};
|