@parent-tobias/chord-component 1.0.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/LICENSE +21 -0
- package/README.md +359 -0
- package/dist/chord-data-service.js +190 -0
- package/dist/chord-diagram.js +181 -0
- package/dist/chord-editor.js +691 -0
- package/dist/chord-list.js +119 -0
- package/dist/default-chords.js +322 -0
- package/dist/index.js +26 -0
- package/dist/indexed-db-service.js +228 -0
- package/dist/music-utils.js +128 -0
- package/dist/node_modules/@lit/reactive-element/css-tag.js +42 -0
- package/dist/node_modules/@lit/reactive-element/decorators/base.js +9 -0
- package/dist/node_modules/@lit/reactive-element/decorators/custom-element.js +13 -0
- package/dist/node_modules/@lit/reactive-element/decorators/property.js +37 -0
- package/dist/node_modules/@lit/reactive-element/decorators/query.js +20 -0
- package/dist/node_modules/@lit/reactive-element/decorators/state.js +12 -0
- package/dist/node_modules/@lit/reactive-element/reactive-element.js +251 -0
- package/package.json +83 -0
- package/src/chord-data-service.ts +275 -0
- package/src/chord-diagram.ts +255 -0
- package/src/chord-editor.ts +919 -0
- package/src/chord-list.ts +145 -0
- package/src/default-chords.ts +333 -0
- package/src/index.ts +7 -0
- package/src/indexed-db-service.ts +356 -0
- package/src/music-utils.ts +216 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Tobias Padilla
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
# chord-component
|
|
2
|
+
|
|
3
|
+
Lit-based web components for displaying musical chord diagrams and chord lists across various string instruments.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🎸 Support for multiple instruments (Ukulele, Guitar, Mandolin)
|
|
8
|
+
- 🎵 Comprehensive chord library with major, minor, 7th, and extended chords
|
|
9
|
+
- ✏️ **Interactive chord editor** for creating custom fingerings
|
|
10
|
+
- 💾 **Persistent storage** with IndexedDB for user-defined chords
|
|
11
|
+
- 🎯 **High-position chord support** with automatic position markers
|
|
12
|
+
- 📱 Responsive design with container queries
|
|
13
|
+
- 🎨 Dark theme optimized
|
|
14
|
+
- ⚡ Built with Lit for fast, efficient rendering
|
|
15
|
+
- 🔧 TypeScript support with full type definitions
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install chord-component
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
### Import and use in HTML
|
|
26
|
+
|
|
27
|
+
```html
|
|
28
|
+
<!DOCTYPE html>
|
|
29
|
+
<html>
|
|
30
|
+
<head>
|
|
31
|
+
<script type="module">
|
|
32
|
+
import 'chord-component';
|
|
33
|
+
</script>
|
|
34
|
+
</head>
|
|
35
|
+
<body>
|
|
36
|
+
<!-- Single chord diagram -->
|
|
37
|
+
<chord-diagram chord="C" instrument="Standard Ukulele"></chord-diagram>
|
|
38
|
+
|
|
39
|
+
<!-- Chord list -->
|
|
40
|
+
<chord-list
|
|
41
|
+
instrument="Standard Ukulele"
|
|
42
|
+
chords='["C", "F", "G", "Am"]'>
|
|
43
|
+
</chord-list>
|
|
44
|
+
</body>
|
|
45
|
+
</html>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Import specific components
|
|
49
|
+
|
|
50
|
+
```javascript
|
|
51
|
+
import 'chord-component/chord-diagram';
|
|
52
|
+
import 'chord-component/chord-list';
|
|
53
|
+
import 'chord-component/chord-editor';
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Import utilities and services
|
|
57
|
+
|
|
58
|
+
```javascript
|
|
59
|
+
import {
|
|
60
|
+
instruments,
|
|
61
|
+
chordToNotes,
|
|
62
|
+
systemDefaultChords,
|
|
63
|
+
chordDataService, // Data management service
|
|
64
|
+
indexedDBService // IndexedDB wrapper
|
|
65
|
+
} from 'chord-component';
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Components
|
|
69
|
+
|
|
70
|
+
### `<chord-diagram>`
|
|
71
|
+
|
|
72
|
+
Displays a single chord diagram with fretboard visualization.
|
|
73
|
+
|
|
74
|
+
#### Attributes
|
|
75
|
+
|
|
76
|
+
- **`chord`** (string, required): The chord name (e.g., "C", "Am7", "F#dim")
|
|
77
|
+
- **`instrument`** (string, optional): The instrument type (default: "Standard Ukulele")
|
|
78
|
+
|
|
79
|
+
#### Examples
|
|
80
|
+
|
|
81
|
+
```html
|
|
82
|
+
<!-- Basic usage -->
|
|
83
|
+
<chord-diagram chord="C"></chord-diagram>
|
|
84
|
+
|
|
85
|
+
<!-- Guitar chord -->
|
|
86
|
+
<chord-diagram chord="Em" instrument="Standard Guitar"></chord-diagram>
|
|
87
|
+
|
|
88
|
+
<!-- Complex chord -->
|
|
89
|
+
<chord-diagram chord="Cmaj7" instrument="Standard Ukulele"></chord-diagram>
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### `<chord-list>`
|
|
93
|
+
|
|
94
|
+
Displays multiple chord diagrams in a responsive grid layout.
|
|
95
|
+
|
|
96
|
+
#### Attributes
|
|
97
|
+
|
|
98
|
+
- **`instrument`** (string, optional): The instrument type (default: "Standard Ukulele")
|
|
99
|
+
- **`chords`** (string|array, required): JSON string or array of chord names
|
|
100
|
+
|
|
101
|
+
#### Examples
|
|
102
|
+
|
|
103
|
+
```html
|
|
104
|
+
<!-- Array of chords -->
|
|
105
|
+
<chord-list
|
|
106
|
+
instrument="Standard Ukulele"
|
|
107
|
+
chords='["C", "F", "G", "Am"]'>
|
|
108
|
+
</chord-list>
|
|
109
|
+
|
|
110
|
+
<!-- More complex chord progression -->
|
|
111
|
+
<chord-list
|
|
112
|
+
instrument="Standard Guitar"
|
|
113
|
+
chords='["Cmaj7", "Dm7", "G7", "Em7", "Am7"]'>
|
|
114
|
+
</chord-list>
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### `<chord-editor>` ✨ NEW
|
|
118
|
+
|
|
119
|
+
**Interactive editor for creating and customizing chord diagrams.**
|
|
120
|
+
|
|
121
|
+
Create custom chord fingerings with visual and text-based editing. All custom chords are automatically saved to IndexedDB and persist across sessions.
|
|
122
|
+
|
|
123
|
+
#### Attributes
|
|
124
|
+
|
|
125
|
+
- **`chord`** (string, required): The chord name to edit
|
|
126
|
+
- **`instrument`** (string, optional): The instrument type (default: "Standard Ukulele")
|
|
127
|
+
|
|
128
|
+
#### Events
|
|
129
|
+
|
|
130
|
+
- **`chord-saved`**: Fired when user saves a custom chord
|
|
131
|
+
- **`chord-reset`**: Fired when user resets to default
|
|
132
|
+
|
|
133
|
+
#### Examples
|
|
134
|
+
|
|
135
|
+
```html
|
|
136
|
+
<!-- Basic editor -->
|
|
137
|
+
<chord-editor chord="C" instrument="Standard Ukulele"></chord-editor>
|
|
138
|
+
|
|
139
|
+
<!-- Listen for save events -->
|
|
140
|
+
<script type="module">
|
|
141
|
+
const editor = document.querySelector('chord-editor');
|
|
142
|
+
|
|
143
|
+
editor.addEventListener('chord-saved', (e) => {
|
|
144
|
+
console.log('Saved:', e.detail.chord, e.detail.data);
|
|
145
|
+
});
|
|
146
|
+
</script>
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
#### Features
|
|
150
|
+
|
|
151
|
+
- **Visual editing**: Click on diagram to add/remove finger positions
|
|
152
|
+
- **Text-based editing**: Edit finger and barre positions with input fields
|
|
153
|
+
- **Add buttons**: Quickly add new fingers or barres
|
|
154
|
+
- **View position control**: Adjust display window for high-position chords
|
|
155
|
+
- **Auto-save to IndexedDB**: Custom chords persist across sessions
|
|
156
|
+
- **Reset to default**: Revert to system defaults anytime
|
|
157
|
+
|
|
158
|
+
See [CHORD_EDITOR.md](./CHORD_EDITOR.md) for complete documentation.
|
|
159
|
+
|
|
160
|
+
#### Creating Custom Chords
|
|
161
|
+
|
|
162
|
+
```javascript
|
|
163
|
+
import { chordDataService } from 'chord-component';
|
|
164
|
+
|
|
165
|
+
// Programmatically save a custom chord
|
|
166
|
+
await chordDataService.saveUserChord('Standard Ukulele', 'C', {
|
|
167
|
+
fingers: [[4, 0], [3, 0], [2, 0], [1, 3]],
|
|
168
|
+
barres: []
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
// Get all user-defined chords
|
|
172
|
+
const userChords = await chordDataService.getAllUserChords();
|
|
173
|
+
|
|
174
|
+
// Delete a custom chord (revert to default)
|
|
175
|
+
await chordDataService.deleteUserChord('Standard Ukulele', 'C');
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Supported Instruments
|
|
179
|
+
|
|
180
|
+
- **Standard Ukulele** (G-C-E-A tuning)
|
|
181
|
+
- **Baritone Ukulele** (D-G-B-E tuning)
|
|
182
|
+
- **5ths tuned Ukulele** (C-G-D-A tuning)
|
|
183
|
+
- **Standard Guitar** (E-A-D-G-B-E tuning)
|
|
184
|
+
- **Drop-D Guitar** (D-A-D-G-B-E tuning)
|
|
185
|
+
- **Standard Mandolin** (G-D-A-E tuning)
|
|
186
|
+
|
|
187
|
+
## Supported Chord Types
|
|
188
|
+
|
|
189
|
+
- **Major**: C, D, E, F, G, A, B
|
|
190
|
+
- **Minor**: Cm, Dm, Em, etc.
|
|
191
|
+
- **Dominant 7th**: C7, D7, G7, etc.
|
|
192
|
+
- **Major 7th**: Cmaj7, Fmaj7, etc.
|
|
193
|
+
- **Minor 7th**: Cm7, Am7, etc.
|
|
194
|
+
- **Diminished**: Cdim, F#dim, etc.
|
|
195
|
+
- **Augmented**: Caug, etc.
|
|
196
|
+
- **Suspended**: Csus2, Csus4, etc.
|
|
197
|
+
- **Extended**: C9, C11, C13, etc.
|
|
198
|
+
- **Add chords**: Cadd9, etc.
|
|
199
|
+
|
|
200
|
+
## Development
|
|
201
|
+
|
|
202
|
+
### Setup
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
git clone <repository-url>
|
|
206
|
+
cd chord-components
|
|
207
|
+
npm install
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Development Server
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
npm run dev
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
This starts a development server with the demo page at `http://localhost:5173/demo/`
|
|
217
|
+
|
|
218
|
+
### Build
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
npm run build
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Lint
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
npm run lint
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## Customization
|
|
231
|
+
|
|
232
|
+
### Custom Chord Definitions
|
|
233
|
+
|
|
234
|
+
#### Using the Chord Editor (Recommended)
|
|
235
|
+
|
|
236
|
+
The easiest way to create custom chords is using the interactive `<chord-editor>` component:
|
|
237
|
+
|
|
238
|
+
```html
|
|
239
|
+
<chord-editor chord="Csus2" instrument="Standard Ukulele"></chord-editor>
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Custom chords are automatically saved to IndexedDB and will be used by all `<chord-diagram>` components.
|
|
243
|
+
|
|
244
|
+
See the [interactive demo](./demo/editor.html) for hands-on examples.
|
|
245
|
+
|
|
246
|
+
#### Programmatic API
|
|
247
|
+
|
|
248
|
+
```javascript
|
|
249
|
+
import { chordDataService } from 'chord-component';
|
|
250
|
+
|
|
251
|
+
// Save a custom chord
|
|
252
|
+
await chordDataService.saveUserChord('Standard Ukulele', 'Csus2', {
|
|
253
|
+
barres: [],
|
|
254
|
+
fingers: [[4, 0], [3, 2], [2, 3], [1, 0]]
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
// Get chord data (user override if exists, otherwise system default)
|
|
258
|
+
const chord = await chordDataService.getChord('Standard Ukulele', 'C');
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
#### Modifying System Defaults
|
|
262
|
+
|
|
263
|
+
You can also extend the system defaults (not recommended for user preferences):
|
|
264
|
+
|
|
265
|
+
```javascript
|
|
266
|
+
import { systemDefaultChords } from 'chord-component';
|
|
267
|
+
|
|
268
|
+
// Add to system defaults
|
|
269
|
+
systemDefaultChords["Standard Ukulele"]["Csus2"] = {
|
|
270
|
+
barres: [],
|
|
271
|
+
fingers: [[4, 0], [3, 2], [2, 3], [1, 0]]
|
|
272
|
+
};
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Styling
|
|
276
|
+
|
|
277
|
+
The components use CSS custom properties for theming. You can override the default dark theme:
|
|
278
|
+
|
|
279
|
+
```css
|
|
280
|
+
chord-diagram {
|
|
281
|
+
--chord-bg-color: #ffffff;
|
|
282
|
+
--chord-text-color: #000000;
|
|
283
|
+
--chord-border-color: #cccccc;
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
## API Reference
|
|
288
|
+
|
|
289
|
+
### Music Utilities
|
|
290
|
+
|
|
291
|
+
The package exports several utility functions for working with music theory:
|
|
292
|
+
|
|
293
|
+
```javascript
|
|
294
|
+
import {
|
|
295
|
+
instruments, // Array of supported instruments
|
|
296
|
+
chordToNotes, // Convert chord name to note array
|
|
297
|
+
parseChords, // Parse chords from ChordPro notation
|
|
298
|
+
scaleTones, // Get notes in a scale
|
|
299
|
+
findBase // Find note index in chromatic scale
|
|
300
|
+
} from 'chord-component';
|
|
301
|
+
|
|
302
|
+
// Example usage
|
|
303
|
+
const chordData = chordToNotes("Cmaj7");
|
|
304
|
+
console.log(chordData); // { name: "Cmaj7", notes: ["C", "E", "G", "B"] }
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### Data Management Services
|
|
308
|
+
|
|
309
|
+
The package includes services for managing chord data:
|
|
310
|
+
|
|
311
|
+
```javascript
|
|
312
|
+
import { chordDataService, indexedDBService } from 'chord-component';
|
|
313
|
+
|
|
314
|
+
// Chord Data Service
|
|
315
|
+
await chordDataService.getChordData('Standard Ukulele');
|
|
316
|
+
await chordDataService.saveUserChord(instrument, chord, data);
|
|
317
|
+
await chordDataService.getAllUserChords();
|
|
318
|
+
await chordDataService.clearCache();
|
|
319
|
+
|
|
320
|
+
// IndexedDB Service (low-level)
|
|
321
|
+
await indexedDBService.saveUserChord(instrument, chord, data);
|
|
322
|
+
await indexedDBService.getUserChord(instrument, chord);
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
See [DATA_SERVICE.md](./DATA_SERVICE.md) for complete API documentation.
|
|
326
|
+
|
|
327
|
+
## Documentation
|
|
328
|
+
|
|
329
|
+
Comprehensive guides for advanced features:
|
|
330
|
+
|
|
331
|
+
- **[CHORD_EDITOR.md](./CHORD_EDITOR.md)** - Complete chord editor documentation
|
|
332
|
+
- **[INTERACTIVE_EDITING.md](./INTERACTIVE_EDITING.md)** - Visual and text-based editing workflows
|
|
333
|
+
- **[VIEW_POSITION.md](./VIEW_POSITION.md)** - Understanding the display window system
|
|
334
|
+
- **[DATA_SERVICE.md](./DATA_SERVICE.md)** - Data caching and API integration
|
|
335
|
+
- **[POSITION_SUPPORT.md](./POSITION_SUPPORT.md)** - High-position chords and neck positions
|
|
336
|
+
|
|
337
|
+
## Demo
|
|
338
|
+
|
|
339
|
+
Run the demo locally:
|
|
340
|
+
|
|
341
|
+
```bash
|
|
342
|
+
npm run dev
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
Then visit:
|
|
346
|
+
- `http://localhost:5173/demo/` - Chord diagram and list examples
|
|
347
|
+
- `http://localhost:5173/demo/editor.html` - Interactive chord editor
|
|
348
|
+
|
|
349
|
+
## License
|
|
350
|
+
|
|
351
|
+
MIT
|
|
352
|
+
|
|
353
|
+
## Contributing
|
|
354
|
+
|
|
355
|
+
Contributions are welcome! Please feel free to submit issues and pull requests.
|
|
356
|
+
|
|
357
|
+
## Support
|
|
358
|
+
|
|
359
|
+
For questions and support, please open an issue on the GitHub repository.
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { indexedDBService as t } from "./indexed-db-service.js";
|
|
2
|
+
import { systemDefaultChords as c } from "./default-chords.js";
|
|
3
|
+
class i {
|
|
4
|
+
constructor() {
|
|
5
|
+
this.useRemoteAPI = !1, this.apiEndpoint = "";
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Configure the service to use a remote API endpoint
|
|
9
|
+
*/
|
|
10
|
+
configureAPI(a) {
|
|
11
|
+
this.apiEndpoint = a, this.useRemoteAPI = !0;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Disable remote API and use local data
|
|
15
|
+
*/
|
|
16
|
+
disableAPI() {
|
|
17
|
+
this.useRemoteAPI = !1;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Get chord data for a specific instrument
|
|
21
|
+
* This method implements the fallback chain: IndexedDB -> API -> Local
|
|
22
|
+
*/
|
|
23
|
+
async getChordData(a) {
|
|
24
|
+
try {
|
|
25
|
+
const e = await t.getChordData(a);
|
|
26
|
+
if (e && e.chords)
|
|
27
|
+
return console.log(`[ChordDataService] Loaded ${a} from IndexedDB cache`), {
|
|
28
|
+
data: e.chords,
|
|
29
|
+
source: { type: "indexeddb", timestamp: e.timestamp }
|
|
30
|
+
};
|
|
31
|
+
} catch (e) {
|
|
32
|
+
console.warn("[ChordDataService] IndexedDB error, falling back:", e);
|
|
33
|
+
}
|
|
34
|
+
if (this.useRemoteAPI && this.apiEndpoint)
|
|
35
|
+
try {
|
|
36
|
+
const e = await this.fetchFromAPI(a);
|
|
37
|
+
if (e)
|
|
38
|
+
return console.log(`[ChordDataService] Loaded ${a} from remote API`), await this.cacheChordData(a, e), {
|
|
39
|
+
data: e,
|
|
40
|
+
source: { type: "api", timestamp: Date.now() }
|
|
41
|
+
};
|
|
42
|
+
} catch (e) {
|
|
43
|
+
console.warn("[ChordDataService] API fetch error, falling back to local:", e);
|
|
44
|
+
}
|
|
45
|
+
console.log(`[ChordDataService] Loaded ${a} from local defaults`);
|
|
46
|
+
const r = c[a] || {};
|
|
47
|
+
return await this.cacheChordData(a, r), {
|
|
48
|
+
data: r,
|
|
49
|
+
source: { type: "local", timestamp: Date.now() }
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Fetch chord data from remote API
|
|
54
|
+
* This is a placeholder that can be implemented when API is ready
|
|
55
|
+
*/
|
|
56
|
+
async fetchFromAPI(a) {
|
|
57
|
+
if (!this.apiEndpoint)
|
|
58
|
+
return null;
|
|
59
|
+
try {
|
|
60
|
+
const r = `${this.apiEndpoint}?instrument=${encodeURIComponent(a)}`, e = await fetch(r);
|
|
61
|
+
if (!e.ok)
|
|
62
|
+
throw new Error(`API request failed: ${e.status} ${e.statusText}`);
|
|
63
|
+
const s = await e.json();
|
|
64
|
+
return s.chords || s;
|
|
65
|
+
} catch (r) {
|
|
66
|
+
return console.error("[ChordDataService] API fetch error:", r), null;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Cache chord data in IndexedDB
|
|
71
|
+
*/
|
|
72
|
+
async cacheChordData(a, r) {
|
|
73
|
+
try {
|
|
74
|
+
await t.setChordData(a, r), console.log(`[ChordDataService] Cached ${a} in IndexedDB`);
|
|
75
|
+
} catch (e) {
|
|
76
|
+
console.warn("[ChordDataService] Failed to cache in IndexedDB:", e);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Get all available instruments from local defaults
|
|
81
|
+
* In the future, this could also query the API
|
|
82
|
+
*/
|
|
83
|
+
getAvailableInstruments() {
|
|
84
|
+
return Object.keys(c);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Clear all cached data from IndexedDB
|
|
88
|
+
*/
|
|
89
|
+
async clearCache() {
|
|
90
|
+
await t.clearAll(), console.log("[ChordDataService] Cache cleared");
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Force refresh data from source (API or local) and update cache
|
|
94
|
+
*/
|
|
95
|
+
async refreshData(a) {
|
|
96
|
+
if (this.useRemoteAPI && this.apiEndpoint)
|
|
97
|
+
try {
|
|
98
|
+
const e = await this.fetchFromAPI(a);
|
|
99
|
+
if (e)
|
|
100
|
+
return await this.cacheChordData(a, e), {
|
|
101
|
+
data: e,
|
|
102
|
+
source: { type: "api", timestamp: Date.now() }
|
|
103
|
+
};
|
|
104
|
+
} catch (e) {
|
|
105
|
+
console.warn("[ChordDataService] Refresh from API failed:", e);
|
|
106
|
+
}
|
|
107
|
+
const r = c[a] || {};
|
|
108
|
+
return await this.cacheChordData(a, r), {
|
|
109
|
+
data: r,
|
|
110
|
+
source: { type: "local", timestamp: Date.now() }
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Check if a specific chord exists for an instrument
|
|
115
|
+
*/
|
|
116
|
+
async hasChord(a, r) {
|
|
117
|
+
const e = await this.getChordData(a);
|
|
118
|
+
return r in e.data;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Get data for a specific chord
|
|
122
|
+
* @param instrument - The instrument name
|
|
123
|
+
* @param chordName - The chord name
|
|
124
|
+
* @param preferUser - If true, returns user override if it exists; if false, returns system default only
|
|
125
|
+
*/
|
|
126
|
+
async getChord(a, r, e = !0) {
|
|
127
|
+
if (e)
|
|
128
|
+
try {
|
|
129
|
+
const o = await t.getUserChord(a, r);
|
|
130
|
+
if (o)
|
|
131
|
+
return {
|
|
132
|
+
fingers: o.fingers,
|
|
133
|
+
barres: o.barres,
|
|
134
|
+
position: o.position
|
|
135
|
+
};
|
|
136
|
+
} catch (o) {
|
|
137
|
+
console.warn("[ChordDataService] Failed to get user chord:", o);
|
|
138
|
+
}
|
|
139
|
+
return (await this.getChordData(a)).data[r] || null;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Save a user-defined chord override
|
|
143
|
+
*/
|
|
144
|
+
async saveUserChord(a, r, e) {
|
|
145
|
+
await t.saveUserChord(a, r, e), console.log(`[ChordDataService] Saved user chord: ${a} - ${r}`);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Delete a user-defined chord override (revert to system default)
|
|
149
|
+
*/
|
|
150
|
+
async deleteUserChord(a, r) {
|
|
151
|
+
await t.deleteUserChord(a, r), console.log(`[ChordDataService] Deleted user chord: ${a} - ${r}`);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Get all user-defined chords for an instrument
|
|
155
|
+
*/
|
|
156
|
+
async getUserChordsByInstrument(a) {
|
|
157
|
+
return (await t.getUserChordsByInstrument(a)).map((e) => ({
|
|
158
|
+
chordName: e.chordName,
|
|
159
|
+
data: {
|
|
160
|
+
fingers: e.fingers,
|
|
161
|
+
barres: e.barres,
|
|
162
|
+
position: e.position
|
|
163
|
+
}
|
|
164
|
+
}));
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Get all user-defined chords across all instruments
|
|
168
|
+
*/
|
|
169
|
+
async getAllUserChords() {
|
|
170
|
+
return (await t.getAllUserChords()).map((r) => ({
|
|
171
|
+
instrument: r.instrument,
|
|
172
|
+
chordName: r.chordName,
|
|
173
|
+
data: {
|
|
174
|
+
fingers: r.fingers,
|
|
175
|
+
barres: r.barres,
|
|
176
|
+
position: r.position
|
|
177
|
+
}
|
|
178
|
+
}));
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Clear all user-defined chord overrides
|
|
182
|
+
*/
|
|
183
|
+
async clearUserChords() {
|
|
184
|
+
await t.clearUserChords(), console.log("[ChordDataService] Cleared all user chords");
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
const l = new i();
|
|
188
|
+
export {
|
|
189
|
+
l as chordDataService
|
|
190
|
+
};
|