@dodlhuat/basix 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.
Files changed (430) hide show
  1. package/README.md +482 -0
  2. package/css/accordion.css +109 -0
  3. package/css/accordion.css.map +1 -0
  4. package/css/accordion.scss +78 -0
  5. package/css/alert.css +57 -0
  6. package/css/alert.css.map +1 -0
  7. package/css/alert.scss +86 -0
  8. package/css/button.css +69 -0
  9. package/css/button.css.map +1 -0
  10. package/css/button.scss +102 -0
  11. package/css/card.css +144 -0
  12. package/css/card.css.map +1 -0
  13. package/css/card.scss +66 -0
  14. package/css/carousel.css +118 -0
  15. package/css/carousel.css.map +1 -0
  16. package/css/carousel.scss +87 -0
  17. package/css/chart.css +159 -0
  18. package/css/chart.css.map +1 -0
  19. package/css/chart.scss +159 -0
  20. package/css/chat-bubbles.css +97 -0
  21. package/css/chat-bubbles.css.map +1 -0
  22. package/css/chat-bubbles.scss +68 -0
  23. package/css/checkbox.css +77 -0
  24. package/css/checkbox.css.map +1 -0
  25. package/css/checkbox.scss +55 -0
  26. package/css/chips.css +72 -0
  27. package/css/chips.css.map +1 -0
  28. package/css/chips.scss +52 -0
  29. package/css/code-viewer.css +97 -0
  30. package/css/code-viewer.css.map +1 -0
  31. package/css/code-viewer.scss +98 -0
  32. package/css/colors.css +63 -0
  33. package/css/colors.css.map +1 -0
  34. package/css/colors.scss +33 -0
  35. package/css/datepicker.css +264 -0
  36. package/css/datepicker.css.map +1 -0
  37. package/css/datepicker.scss +317 -0
  38. package/css/defaults.css +118 -0
  39. package/css/defaults.css.map +1 -0
  40. package/css/defaults.scss +91 -0
  41. package/css/dropdown.css +146 -0
  42. package/css/dropdown.css.map +1 -0
  43. package/css/dropdown.scss +137 -0
  44. package/css/editor.css +413 -0
  45. package/css/editor.scss +458 -0
  46. package/css/file-uploader.css +194 -0
  47. package/css/file-uploader.css.map +1 -0
  48. package/css/file-uploader.scss +195 -0
  49. package/css/flyout-menu.css +345 -0
  50. package/css/flyout-menu.css.map +1 -0
  51. package/css/flyout-menu.scss +355 -0
  52. package/css/form-builder.css +9 -0
  53. package/css/form-builder.css.map +1 -0
  54. package/css/form-builder.scss +11 -0
  55. package/css/form.css +130 -0
  56. package/css/form.css.map +1 -0
  57. package/css/form.scss +115 -0
  58. package/css/gallery.css +91 -0
  59. package/css/gallery.css.map +1 -0
  60. package/css/gallery.scss +63 -0
  61. package/css/grid.css +44 -0
  62. package/css/grid.css.map +1 -0
  63. package/css/grid.scss +41 -0
  64. package/css/guitar-chords.css +251 -0
  65. package/css/icons.css +327 -0
  66. package/css/icons.css.map +1 -0
  67. package/css/icons.scss +331 -0
  68. package/css/modal.css +97 -0
  69. package/css/modal.css.map +1 -0
  70. package/css/modal.scss +72 -0
  71. package/css/parameters.css +1 -0
  72. package/css/parameters.css.map +1 -0
  73. package/css/parameters.scss +4 -0
  74. package/css/placeholder.css +50 -0
  75. package/css/placeholder.css.map +1 -0
  76. package/css/placeholder.scss +28 -0
  77. package/css/progress.css +51 -0
  78. package/css/progress.css.map +1 -0
  79. package/css/progress.scss +32 -0
  80. package/css/properties.css +31 -0
  81. package/css/properties.css.map +1 -0
  82. package/css/properties.scss +31 -0
  83. package/css/push-menu.css +145 -0
  84. package/css/push-menu.css.map +1 -0
  85. package/css/push-menu.scss +127 -0
  86. package/css/radiobutton.css +91 -0
  87. package/css/radiobutton.css.map +1 -0
  88. package/css/radiobutton.scss +64 -0
  89. package/css/reset.css +46 -0
  90. package/css/reset.css.map +1 -0
  91. package/css/reset.scss +40 -0
  92. package/css/scrollbar.css +91 -0
  93. package/css/scrollbar.css.map +1 -0
  94. package/css/scrollbar.scss +69 -0
  95. package/css/spinner.css +118 -0
  96. package/css/spinner.css.map +1 -0
  97. package/css/spinner.scss +91 -0
  98. package/css/style.css +3735 -0
  99. package/css/style.css.map +1 -0
  100. package/css/style.min.css +1 -0
  101. package/css/style.scss +38 -0
  102. package/css/switch.css +66 -0
  103. package/css/switch.css.map +1 -0
  104. package/css/switch.scss +42 -0
  105. package/css/table.css +201 -0
  106. package/css/table.css.map +1 -0
  107. package/css/table.scss +178 -0
  108. package/css/tabs.css +135 -0
  109. package/css/tabs.css.map +1 -0
  110. package/css/tabs.scss +118 -0
  111. package/css/timeline.css +69 -0
  112. package/css/timeline.css.map +1 -0
  113. package/css/timeline.scss +69 -0
  114. package/css/timepicker.scss +72 -0
  115. package/css/toast.css +98 -0
  116. package/css/toast.css.map +1 -0
  117. package/css/toast.scss +81 -0
  118. package/css/tooltip.css +151 -0
  119. package/css/tooltip.css.map +1 -0
  120. package/css/tooltip.scss +122 -0
  121. package/css/tree.css +199 -0
  122. package/css/tree.css.map +1 -0
  123. package/css/tree.scss +192 -0
  124. package/css/typography.css +137 -0
  125. package/css/typography.css.map +1 -0
  126. package/css/typography.scss +100 -0
  127. package/css/virtual-dropdown.css +149 -0
  128. package/css/virtual-dropdown.css.map +1 -0
  129. package/css/virtual-dropdown.scss +142 -0
  130. package/fonts/MaterialSymbolsOutlined.woff2 +0 -0
  131. package/fonts/Outfit-VariableFont_wght.woff +0 -0
  132. package/fonts/Outfit-VariableFont_wght.woff2 +0 -0
  133. package/fonts/material-icons.woff2 +0 -0
  134. package/icons/activity-outline.svg +1 -0
  135. package/icons/alert-circle-outline.svg +1 -0
  136. package/icons/alert-triangle-outline.svg +1 -0
  137. package/icons/archive-outline.svg +1 -0
  138. package/icons/arrow-back-outline.svg +1 -0
  139. package/icons/arrow-circle-down-outline.svg +1 -0
  140. package/icons/arrow-circle-left-outline.svg +1 -0
  141. package/icons/arrow-circle-right-outline.svg +1 -0
  142. package/icons/arrow-circle-up-outline.svg +1 -0
  143. package/icons/arrow-down-outline.svg +1 -0
  144. package/icons/arrow-downward-outline.svg +1 -0
  145. package/icons/arrow-forward-outline.svg +1 -0
  146. package/icons/arrow-ios-back-outline.svg +1 -0
  147. package/icons/arrow-ios-downward-outline.svg +1 -0
  148. package/icons/arrow-ios-forward-outline.svg +1 -0
  149. package/icons/arrow-ios-upward-outline.svg +1 -0
  150. package/icons/arrow-left-outline.svg +1 -0
  151. package/icons/arrow-right-outline.svg +1 -0
  152. package/icons/arrow-up-outline.svg +1 -0
  153. package/icons/arrow-upward-outline.svg +1 -0
  154. package/icons/arrowhead-down-outline.svg +1 -0
  155. package/icons/arrowhead-left-outline.svg +1 -0
  156. package/icons/arrowhead-right-outline.svg +1 -0
  157. package/icons/arrowhead-up-outline.svg +1 -0
  158. package/icons/at-outline.svg +1 -0
  159. package/icons/attach-2-outline.svg +1 -0
  160. package/icons/attach-outline.svg +1 -0
  161. package/icons/award-outline.svg +1 -0
  162. package/icons/backspace-outline.svg +1 -0
  163. package/icons/bar-chart-2-outline.svg +1 -0
  164. package/icons/bar-chart-outline.svg +1 -0
  165. package/icons/battery-outline.svg +1 -0
  166. package/icons/behance-outline.svg +1 -0
  167. package/icons/bell-off-outline.svg +1 -0
  168. package/icons/bell-outline.svg +1 -0
  169. package/icons/bluetooth-outline.svg +1 -0
  170. package/icons/book-open-outline.svg +1 -0
  171. package/icons/book-outline.svg +1 -0
  172. package/icons/bookmark-outline.svg +1 -0
  173. package/icons/briefcase-outline.svg +1 -0
  174. package/icons/browser-outline.svg +1 -0
  175. package/icons/brush-outline.svg +1 -0
  176. package/icons/bulb-outline.svg +1 -0
  177. package/icons/calendar-outline.svg +1 -0
  178. package/icons/camera-outline.svg +1 -0
  179. package/icons/car-outline.svg +1 -0
  180. package/icons/cast-outline.svg +1 -0
  181. package/icons/charging-outline.svg +1 -0
  182. package/icons/checkmark-circle-2-outline.svg +1 -0
  183. package/icons/checkmark-circle-outline.svg +1 -0
  184. package/icons/checkmark-outline.svg +1 -0
  185. package/icons/checkmark-square-2-outline.svg +1 -0
  186. package/icons/checkmark-square-outline.svg +1 -0
  187. package/icons/chevron-down-outline.svg +1 -0
  188. package/icons/chevron-left-outline.svg +1 -0
  189. package/icons/chevron-right-outline.svg +1 -0
  190. package/icons/chevron-up-outline.svg +1 -0
  191. package/icons/clipboard-outline.svg +1 -0
  192. package/icons/clock-outline.svg +1 -0
  193. package/icons/close-circle-outline.svg +1 -0
  194. package/icons/close-outline.svg +1 -0
  195. package/icons/close-square-outline.svg +1 -0
  196. package/icons/cloud-download-outline.svg +1 -0
  197. package/icons/cloud-upload-outline.svg +1 -0
  198. package/icons/code-download-outline.svg +1 -0
  199. package/icons/code-outline.svg +1 -0
  200. package/icons/collapse-outline.svg +1 -0
  201. package/icons/color-palette-outline.svg +1 -0
  202. package/icons/color-picker-outline.svg +1 -0
  203. package/icons/compass-outline.svg +1 -0
  204. package/icons/copy-outline.svg +1 -0
  205. package/icons/corner-down-left-outline.svg +1 -0
  206. package/icons/corner-down-right-outline.svg +1 -0
  207. package/icons/corner-left-down-outline.svg +1 -0
  208. package/icons/corner-left-up-outline.svg +1 -0
  209. package/icons/corner-right-down-outline.svg +1 -0
  210. package/icons/corner-right-up-outline.svg +1 -0
  211. package/icons/corner-up-left-outline.svg +1 -0
  212. package/icons/corner-up-right-outline.svg +1 -0
  213. package/icons/credit-card-outline.svg +1 -0
  214. package/icons/crop-outline.svg +1 -0
  215. package/icons/cube-outline.svg +1 -0
  216. package/icons/diagonal-arrow-left-down-outline.svg +1 -0
  217. package/icons/diagonal-arrow-left-up-outline.svg +1 -0
  218. package/icons/diagonal-arrow-right-down-outline.svg +1 -0
  219. package/icons/diagonal-arrow-right-up-outline.svg +1 -0
  220. package/icons/done-all-outline.svg +1 -0
  221. package/icons/download-outline.svg +1 -0
  222. package/icons/droplet-off-outline.svg +1 -0
  223. package/icons/droplet-outline.svg +1 -0
  224. package/icons/edit-2-outline.svg +1 -0
  225. package/icons/edit-outline.svg +1 -0
  226. package/icons/email-outline.svg +1 -0
  227. package/icons/expand-outline.svg +1 -0
  228. package/icons/external-link-outline.svg +1 -0
  229. package/icons/eye-off-2-outline.svg +1 -0
  230. package/icons/eye-off-outline.svg +1 -0
  231. package/icons/eye-outline.svg +1 -0
  232. package/icons/facebook-outline.svg +1 -0
  233. package/icons/file-add-outline.svg +1 -0
  234. package/icons/file-outline.svg +1 -0
  235. package/icons/file-remove-outline.svg +1 -0
  236. package/icons/file-text-outline.svg +1 -0
  237. package/icons/film-outline.svg +1 -0
  238. package/icons/flag-outline.svg +1 -0
  239. package/icons/flash-off-outline.svg +1 -0
  240. package/icons/flash-outline.svg +1 -0
  241. package/icons/flip-2-outline.svg +1 -0
  242. package/icons/flip-outline.svg +1 -0
  243. package/icons/folder-add-outline.svg +1 -0
  244. package/icons/folder-outline.svg +1 -0
  245. package/icons/folder-remove-outline.svg +1 -0
  246. package/icons/funnel-outline.svg +1 -0
  247. package/icons/gift-outline.svg +1 -0
  248. package/icons/github-outline.svg +1 -0
  249. package/icons/globe-2-outline.svg +1 -0
  250. package/icons/globe-outline.svg +1 -0
  251. package/icons/google-outline.svg +1 -0
  252. package/icons/grid-outline.svg +1 -0
  253. package/icons/hard-drive-outline.svg +1 -0
  254. package/icons/hash-outline.svg +1 -0
  255. package/icons/headphones-outline.svg +1 -0
  256. package/icons/heart-outline.svg +1 -0
  257. package/icons/home-outline.svg +1 -0
  258. package/icons/image-outline.svg +1 -0
  259. package/icons/inbox-outline.svg +1 -0
  260. package/icons/info-outline.svg +1 -0
  261. package/icons/keypad-outline.svg +1 -0
  262. package/icons/layers-outline.svg +1 -0
  263. package/icons/layout-outline.svg +1 -0
  264. package/icons/link-2-outline.svg +1 -0
  265. package/icons/link-outline.svg +1 -0
  266. package/icons/linkedin-outline.svg +1 -0
  267. package/icons/list-outline.svg +1 -0
  268. package/icons/loader-outline.svg +1 -0
  269. package/icons/lock-outline.svg +1 -0
  270. package/icons/log-in-outline.svg +1 -0
  271. package/icons/log-out-outline.svg +1 -0
  272. package/icons/map-outline.svg +1 -0
  273. package/icons/maximize-outline.svg +1 -0
  274. package/icons/menu-2-outline.svg +1 -0
  275. package/icons/menu-arrow-outline.svg +1 -0
  276. package/icons/menu-outline.svg +1 -0
  277. package/icons/message-circle-outline.svg +1 -0
  278. package/icons/message-square-outline.svg +1 -0
  279. package/icons/mic-off-outline.svg +1 -0
  280. package/icons/mic-outline.svg +1 -0
  281. package/icons/minimize-outline.svg +1 -0
  282. package/icons/minus-circle-outline.svg +1 -0
  283. package/icons/minus-outline.svg +1 -0
  284. package/icons/minus-square-outline.svg +1 -0
  285. package/icons/monitor-outline.svg +1 -0
  286. package/icons/moon-outline.svg +1 -0
  287. package/icons/more-horizontal-outline.svg +1 -0
  288. package/icons/more-vertical-outline.svg +1 -0
  289. package/icons/move-outline.svg +1 -0
  290. package/icons/music-outline.svg +1 -0
  291. package/icons/navigation-2-outline.svg +1 -0
  292. package/icons/navigation-outline.svg +1 -0
  293. package/icons/npm-outline.svg +1 -0
  294. package/icons/options-2-outline.svg +1 -0
  295. package/icons/options-outline.svg +1 -0
  296. package/icons/pantone-outline.svg +1 -0
  297. package/icons/paper-plane-outline.svg +1 -0
  298. package/icons/pause-circle-outline.svg +1 -0
  299. package/icons/people-outline.svg +1 -0
  300. package/icons/percent-outline.svg +1 -0
  301. package/icons/person-add-outline.svg +1 -0
  302. package/icons/person-delete-outline.svg +1 -0
  303. package/icons/person-done-outline.svg +1 -0
  304. package/icons/person-outline.svg +1 -0
  305. package/icons/person-remove-outline.svg +1 -0
  306. package/icons/phone-call-outline.svg +1 -0
  307. package/icons/phone-missed-outline.svg +1 -0
  308. package/icons/phone-off-outline.svg +1 -0
  309. package/icons/phone-outline.svg +1 -0
  310. package/icons/pie-chart-outline.svg +1 -0
  311. package/icons/pin-outline.svg +1 -0
  312. package/icons/play-circle-outline.svg +1 -0
  313. package/icons/plus-circle-outline.svg +1 -0
  314. package/icons/plus-outline.svg +1 -0
  315. package/icons/plus-square-outline.svg +1 -0
  316. package/icons/power-outline.svg +1 -0
  317. package/icons/pricetags-outline.svg +1 -0
  318. package/icons/printer-outline.svg +1 -0
  319. package/icons/question-mark-circle-outline.svg +1 -0
  320. package/icons/question-mark-outline.svg +1 -0
  321. package/icons/radio-button-off-outline.svg +1 -0
  322. package/icons/radio-button-on-outline.svg +1 -0
  323. package/icons/radio-outline.svg +1 -0
  324. package/icons/recording-outline.svg +1 -0
  325. package/icons/refresh-outline.svg +1 -0
  326. package/icons/repeat-outline.svg +1 -0
  327. package/icons/rewind-left-outline.svg +1 -0
  328. package/icons/rewind-right-outline.svg +1 -0
  329. package/icons/save-outline.svg +1 -0
  330. package/icons/scissors-outline.svg +1 -0
  331. package/icons/search-outline.svg +1 -0
  332. package/icons/settings-2-outline.svg +1 -0
  333. package/icons/settings-outline.svg +1 -0
  334. package/icons/shake-outline.svg +1 -0
  335. package/icons/share-outline.svg +1 -0
  336. package/icons/shield-off-outline.svg +1 -0
  337. package/icons/shield-outline.svg +1 -0
  338. package/icons/shopping-bag-outline.svg +1 -0
  339. package/icons/shopping-cart-outline.svg +1 -0
  340. package/icons/shuffle-2-outline.svg +1 -0
  341. package/icons/shuffle-outline.svg +1 -0
  342. package/icons/skip-back-outline.svg +1 -0
  343. package/icons/skip-forward-outline.svg +1 -0
  344. package/icons/slash-outline.svg +1 -0
  345. package/icons/smartphone-outline.svg +1 -0
  346. package/icons/smiling-face-outline.svg +1 -0
  347. package/icons/speaker-outline.svg +1 -0
  348. package/icons/square-outline.svg +1 -0
  349. package/icons/star-outline.svg +1 -0
  350. package/icons/stop-circle-outline.svg +1 -0
  351. package/icons/sun-outline.svg +1 -0
  352. package/icons/swap-outline.svg +1 -0
  353. package/icons/sync-outline.svg +1 -0
  354. package/icons/text-outline.svg +1 -0
  355. package/icons/thermometer-minus-outline.svg +1 -0
  356. package/icons/thermometer-outline.svg +1 -0
  357. package/icons/thermometer-plus-outline.svg +1 -0
  358. package/icons/toggle-left-outline.svg +1 -0
  359. package/icons/toggle-right-outline.svg +1 -0
  360. package/icons/trash-2-outline.svg +1 -0
  361. package/icons/trash-outline.svg +1 -0
  362. package/icons/trending-down-outline.svg +1 -0
  363. package/icons/trending-up-outline.svg +1 -0
  364. package/icons/tv-outline.svg +1 -0
  365. package/icons/twitter-outline.svg +1 -0
  366. package/icons/umbrella-outline.svg +1 -0
  367. package/icons/undo-outline.svg +1 -0
  368. package/icons/unlock-outline.svg +1 -0
  369. package/icons/upload-outline.svg +1 -0
  370. package/icons/video-off-outline.svg +1 -0
  371. package/icons/video-outline.svg +1 -0
  372. package/icons/volume-down-outline.svg +1 -0
  373. package/icons/volume-mute-outline.svg +1 -0
  374. package/icons/volume-off-outline.svg +1 -0
  375. package/icons/volume-up-outline.svg +1 -0
  376. package/icons/wifi-off-outline.svg +1 -0
  377. package/icons/wifi-outline.svg +1 -0
  378. package/js/carousel.js +133 -0
  379. package/js/carousel.ts +173 -0
  380. package/js/chart.js +257 -0
  381. package/js/code-viewer.js +148 -0
  382. package/js/code-viewer.ts +188 -0
  383. package/js/datepicker.js +497 -0
  384. package/js/datepicker.ts +619 -0
  385. package/js/dropdown.js +122 -0
  386. package/js/dropdown.ts +180 -0
  387. package/js/editor.js +421 -0
  388. package/js/editor.ts +426 -0
  389. package/js/file-uploader.js +268 -0
  390. package/js/file-uploader.ts +350 -0
  391. package/js/flyout-menu.js +195 -0
  392. package/js/flyout-menu.ts +250 -0
  393. package/js/form-builder.js +107 -0
  394. package/js/gallery.js +177 -0
  395. package/js/gallery.ts +231 -0
  396. package/js/guitar-chords.js +268 -0
  397. package/js/index.js +720 -0
  398. package/js/index.ts +874 -0
  399. package/js/lazy-loader.js +121 -0
  400. package/js/modal.js +113 -0
  401. package/js/modal.ts +167 -0
  402. package/js/push-menu.js +101 -0
  403. package/js/push-menu.ts +130 -0
  404. package/js/request.js +51 -0
  405. package/js/scroll.js +27 -0
  406. package/js/scroll.ts +47 -0
  407. package/js/scrollbar.js +219 -0
  408. package/js/scrollbar.ts +308 -0
  409. package/js/select.js +158 -0
  410. package/js/select.ts +217 -0
  411. package/js/table.js +359 -0
  412. package/js/table.ts +453 -0
  413. package/js/tabs.js +225 -0
  414. package/js/tabs.ts +280 -0
  415. package/js/theme.js +194 -0
  416. package/js/theme.ts +225 -0
  417. package/js/timepicker.js +98 -0
  418. package/js/timepicker.ts +131 -0
  419. package/js/toast.js +93 -0
  420. package/js/toast.ts +138 -0
  421. package/js/tooltip.js +193 -0
  422. package/js/tooltip.ts +252 -0
  423. package/js/tree.js +162 -0
  424. package/js/tree.ts +218 -0
  425. package/js/tsconfig.json +18 -0
  426. package/js/utils.js +69 -0
  427. package/js/utils.ts +84 -0
  428. package/js/virtual-dropdown.js +277 -0
  429. package/js/virtual-dropdown.ts +366 -0
  430. package/package.json +38 -0
package/js/gallery.ts ADDED
@@ -0,0 +1,231 @@
1
+ interface ImageData {
2
+ src: string;
3
+ title: string;
4
+ desc: string;
5
+ }
6
+
7
+ interface MasonryGalleryOptions {
8
+ minColumnWidth?: number;
9
+ scrollThreshold?: number;
10
+ loaderSelector?: string;
11
+ reload?: number;
12
+ fetchFunction?: Promise<ImageData[]>;
13
+ }
14
+
15
+ class MasonryGallery {
16
+ private container: HTMLElement;
17
+ private readonly loader: HTMLElement | null;
18
+ private options: Required<Omit<MasonryGalleryOptions, "loaderSelector">>;
19
+ private columns: HTMLDivElement[] = [];
20
+ private isFetching: boolean = false;
21
+ private resizeObserver: ResizeObserver | null = null;
22
+ private abortController: AbortController | null = null;
23
+ private reloaded = 0;
24
+
25
+ constructor(containerId: string, options: MasonryGalleryOptions = {}) {
26
+ const container = document.getElementById(containerId);
27
+ if (!container) {
28
+ throw new Error(`Container with id "${containerId}" not found`);
29
+ }
30
+ this.container = container;
31
+ this.loader = document.querySelector(options.loaderSelector || ".loader");
32
+
33
+ this.options = {
34
+ minColumnWidth: options.minColumnWidth ?? 250,
35
+ scrollThreshold: options.scrollThreshold ?? 100,
36
+ reload: 2,
37
+ fetchFunction: options.fetchFunction ?? this.fetchMockImages(),
38
+ };
39
+
40
+ this.init();
41
+ }
42
+
43
+ private init(): void {
44
+ this.setupLayout();
45
+ this.loadMoreImages();
46
+ this.addEventListeners();
47
+ }
48
+
49
+ private setupLayout(): void {
50
+ const containerWidth = this.container.getBoundingClientRect().width;
51
+ const numColumns = Math.max(
52
+ 1,
53
+ Math.floor(containerWidth / this.options.minColumnWidth),
54
+ );
55
+
56
+ if (this.columns.length !== numColumns) {
57
+ this.container.innerHTML = "";
58
+ this.columns = [];
59
+
60
+ for (let i = 0; i < numColumns; i++) {
61
+ const col = document.createElement("div");
62
+ col.className = "masonry-column";
63
+ this.container.appendChild(col);
64
+ this.columns.push(col);
65
+ }
66
+ }
67
+ }
68
+
69
+ private addEventListeners(): void {
70
+ let resizeTimeout: number;
71
+ window.addEventListener("resize", () => {
72
+ clearTimeout(resizeTimeout);
73
+ resizeTimeout = setTimeout(() => {
74
+ this.reLayout();
75
+ }, 200);
76
+ });
77
+
78
+ this.abortController = new AbortController();
79
+ window.addEventListener("scroll", this.handleScroll, {
80
+ passive: true,
81
+ signal: this.abortController.signal,
82
+ });
83
+ }
84
+
85
+ private reLayout(): void {
86
+ const items: HTMLElement[] = [];
87
+ this.columns.forEach((col) => {
88
+ Array.from(col.children).forEach((child) => {
89
+ items.push(child as HTMLElement);
90
+ });
91
+ col.innerHTML = "";
92
+ });
93
+
94
+ const availableWidth = Math.min(1200, window.innerWidth - 40);
95
+ const numColumns = Math.max(
96
+ 1,
97
+ Math.floor(availableWidth / this.options.minColumnWidth),
98
+ );
99
+
100
+ if (this.columns.length !== numColumns) {
101
+ this.container.innerHTML = "";
102
+ this.columns = [];
103
+
104
+ for (let i = 0; i < numColumns; i++) {
105
+ const col = document.createElement("div");
106
+ col.className = "masonry-column";
107
+ this.container.appendChild(col);
108
+ this.columns.push(col);
109
+ }
110
+ }
111
+
112
+ items.forEach((item) => {
113
+ this.addToShortestColumn(item);
114
+ });
115
+ }
116
+
117
+ private handleScroll = (): void => {
118
+ if (this.isFetching) return;
119
+
120
+ const { scrollTop, scrollHeight, clientHeight } = document.documentElement;
121
+ if (
122
+ scrollTop + clientHeight >=
123
+ scrollHeight - this.options.scrollThreshold
124
+ ) {
125
+ this.loadMoreImages();
126
+ }
127
+ };
128
+
129
+ private async loadMoreImages(): Promise<void> {
130
+ this.reloaded++;
131
+ if (this.options.reload > 0 && this.reloaded > this.options.reload) {
132
+ console.warn("Maximum reload limit reached.");
133
+ return;
134
+ }
135
+ if (this.isFetching) return;
136
+
137
+ this.isFetching = true;
138
+ this.toggleLoader(true);
139
+
140
+ try {
141
+ const newImages = await this.options.fetchFunction;
142
+ this.renderImages(newImages);
143
+ } catch (error) {
144
+ throw new Error("Error loading images: " + error);
145
+ } finally {
146
+ this.isFetching = false;
147
+ this.toggleLoader(false);
148
+ }
149
+ }
150
+
151
+ private toggleLoader(show: boolean): void {
152
+ if (this.loader) {
153
+ this.loader.classList.toggle("hidden", !show);
154
+ }
155
+ }
156
+
157
+ private fetchMockImages(): Promise<ImageData[]> {
158
+ throw Error("Method not implemented.");
159
+ }
160
+
161
+ private renderImages(imageDataList: ImageData[]): void {
162
+ imageDataList.forEach((data) => {
163
+ const item = this.createCard(data);
164
+ this.addToShortestColumn(item);
165
+
166
+ requestAnimationFrame(() => {
167
+ const img = item.querySelector("img");
168
+ if (img) {
169
+ img.addEventListener("load", () => img.classList.add("loaded"), {
170
+ once: true,
171
+ });
172
+ if (img.complete) {
173
+ img.classList.add("loaded");
174
+ }
175
+ }
176
+ });
177
+ });
178
+ }
179
+
180
+ private createCard(data: ImageData): HTMLDivElement {
181
+ const div = document.createElement("div");
182
+ div.className = "masonry-item";
183
+
184
+ div.innerHTML = `
185
+ <img src="${this.escapeHtml(data.src)}" alt="${this.escapeHtml(data.title)}" loading="lazy">
186
+ <div class="masonry-item-info">
187
+ <h3 class="masonry-item-title">${this.escapeHtml(data.title)}</h3>
188
+ <p class="masonry-item-desc">${this.escapeHtml(data.desc)}</p>
189
+ </div>
190
+ `;
191
+
192
+ return div;
193
+ }
194
+
195
+ private escapeHtml(text: string): string {
196
+ const div = document.createElement("div");
197
+ div.textContent = text;
198
+ return div.innerHTML;
199
+ }
200
+
201
+ private addToShortestColumn(element: HTMLElement): void {
202
+ if (this.columns.length === 0) return;
203
+
204
+ let shortestCol = this.columns[0];
205
+ let minHeight = shortestCol.offsetHeight;
206
+
207
+ for (let i = 1; i < this.columns.length; i++) {
208
+ const h = this.columns[i].offsetHeight;
209
+ if (h < minHeight) {
210
+ minHeight = h;
211
+ shortestCol = this.columns[i];
212
+ }
213
+ }
214
+
215
+ shortestCol.appendChild(element);
216
+ }
217
+
218
+ public destroy(): void {
219
+ if (this.resizeObserver) {
220
+ this.resizeObserver.disconnect();
221
+ this.resizeObserver = null;
222
+ }
223
+
224
+ if (this.abortController) {
225
+ this.abortController.abort();
226
+ this.abortController = null;
227
+ }
228
+ }
229
+ }
230
+
231
+ export { MasonryGallery, ImageData };
@@ -0,0 +1,268 @@
1
+ const NOTES = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'];
2
+ const STRINGS = ['E', 'B', 'G', 'D', 'A', 'E']; // High E to Low E
3
+ const FRETS = 15;
4
+
5
+ // Standard tuning offsets from C (C=0)
6
+ // E=4, B=11, G=7, D=2, A=9, E=4
7
+ // But we need absolute pitch to know octaves if we want to be precise,
8
+ // but for simple note names, relative is fine.
9
+ // Let's map open strings to their semitone value (0-11)
10
+ const STRING_TUNING = [4, 11, 7, 2, 9, 4];
11
+
12
+ // Chord Formulas (intervals in semitones)
13
+ const CHORD_FORMULAS = {
14
+ 'Major': [0, 4, 7],
15
+ 'Minor': [0, 3, 7],
16
+ '5': [0, 7],
17
+ '7': [0, 4, 7, 10],
18
+ 'Maj7': [0, 4, 7, 11],
19
+ 'm7': [0, 3, 7, 10],
20
+ 'sus4': [0, 5, 7],
21
+ 'sus2': [0, 2, 7],
22
+ 'dim': [0, 3, 6],
23
+ 'aug': [0, 4, 8]
24
+ };
25
+
26
+ // Common open chords for the dropdown
27
+ const COMMON_CHORDS = {
28
+ 'C Major': [0, 1, 0, 2, 3, -1], // -1 for muted/unused
29
+ 'A Major': [0, 2, 2, 2, 0, -1],
30
+ 'G Major': [3, 0, 0, 0, 2, 3],
31
+ 'E Major': [0, 0, 1, 2, 2, 0],
32
+ 'D Major': [2, 3, 2, 0, -1, -1],
33
+ 'A Minor': [0, 1, 2, 2, 0, -1],
34
+ 'E Minor': [0, 0, 0, 2, 2, 0],
35
+ 'D Minor': [1, 3, 2, 0, -1, -1]
36
+ };
37
+
38
+ // State
39
+ let selectedFrets = [-1, -1, -1, -1, -1, -1];
40
+ let startFret = 0;
41
+ let visibleFrets = 15;
42
+
43
+ function init() {
44
+ handleResize();
45
+ window.addEventListener('resize', handleResize);
46
+
47
+ renderFretboard();
48
+ populateChordSelect();
49
+ setupEventListeners();
50
+ }
51
+
52
+ function handleResize() {
53
+ const isMobile = window.innerWidth <= 768;
54
+ const newVisible = isMobile ? 5 : 15;
55
+ if (newVisible !== visibleFrets) {
56
+ visibleFrets = newVisible;
57
+ renderFretboard();
58
+ }
59
+ }
60
+
61
+ function renderFretboard() {
62
+ const container = document.getElementById('fretboard');
63
+ container.innerHTML = '';
64
+
65
+ STRINGS.forEach((stringName, stringIndex) => {
66
+ const stringDiv = document.createElement('div');
67
+ stringDiv.className = 'string';
68
+
69
+ // Label for string name (optional, but good for context)
70
+ // For now, keeping it simple as before
71
+
72
+ // Create frets (showing visibleFrets count)
73
+ for (let i = 0; i <= visibleFrets; i++) {
74
+ // Actual semantic fret number
75
+ const currentFretNum = startFret + i;
76
+
77
+ // Skip rendering if beyond max reasonable frets (e.g., 24), but let's just stick to logic
78
+
79
+ const fretDiv = document.createElement('div');
80
+ fretDiv.className = 'fret';
81
+
82
+ // Mark if this is the Nut (fret 0)
83
+ if (currentFretNum === 0) {
84
+ fretDiv.classList.add('nut');
85
+ }
86
+
87
+ // Check if selected
88
+ if (selectedFrets[stringIndex] === currentFretNum) {
89
+ fretDiv.classList.add('active');
90
+ }
91
+
92
+ // Note marker
93
+ const marker = document.createElement('div');
94
+ marker.className = 'note-marker';
95
+
96
+ // Calculate note
97
+ const noteIndex = (STRING_TUNING[stringIndex] + currentFretNum) % 12;
98
+ marker.textContent = NOTES[noteIndex];
99
+
100
+ fretDiv.appendChild(marker);
101
+
102
+ // Click handler
103
+ fretDiv.addEventListener('click', () => toggleFret(stringIndex, currentFretNum));
104
+
105
+ // Fret labels (markers)
106
+ // Adding dots logic dynamically might be complex.
107
+ // Simplified: showing note name is good enough?
108
+ // Let's add a small number indicator for the fret number if needed?
109
+ // User didn't request explicit fret numbers, but it helps.
110
+ // Let's leave it clean for now.
111
+
112
+ stringDiv.appendChild(fretDiv);
113
+ }
114
+
115
+ container.appendChild(stringDiv);
116
+ });
117
+
118
+ // Add Fret Numbers Row
119
+ const numberRow = document.createElement('div');
120
+ numberRow.className = 'fret-numbers';
121
+
122
+ for (let i = 0; i <= visibleFrets; i++) {
123
+ const currentFretNum = startFret + i;
124
+ const numberDiv = document.createElement('div');
125
+ numberDiv.className = 'fret-number';
126
+
127
+ // Handle Nut alignment matching
128
+ if (currentFretNum === 0) {
129
+ numberDiv.classList.add('nut-number');
130
+ numberDiv.style.flex = '0 0 50px';
131
+ numberDiv.style.borderRightWidth = '8px'; // Match nut border
132
+ numberDiv.style.borderRightColor = 'transparent';
133
+ numberDiv.textContent = '0';
134
+ } else {
135
+ numberDiv.textContent = currentFretNum;
136
+ }
137
+
138
+ numberRow.appendChild(numberDiv);
139
+ }
140
+ container.appendChild(numberRow);
141
+ }
142
+
143
+ function toggleFret(stringIndex, fretIndex) {
144
+ if (selectedFrets[stringIndex] === fretIndex) {
145
+ // Deselect
146
+ selectedFrets[stringIndex] = -1;
147
+ } else {
148
+ // Select
149
+ selectedFrets[stringIndex] = fretIndex;
150
+ }
151
+ renderFretboard();
152
+ detectChord();
153
+ }
154
+
155
+ function populateChordSelect() {
156
+ const select = document.getElementById('chord-select');
157
+ for (const [name, frets] of Object.entries(COMMON_CHORDS)) {
158
+ const option = document.createElement('option');
159
+ option.value = name;
160
+ option.textContent = name;
161
+ select.appendChild(option);
162
+ }
163
+ }
164
+
165
+ function setupEventListeners() {
166
+ document.getElementById('chord-select').addEventListener('change', (e) => {
167
+ const chordName = e.target.value;
168
+ if (chordName && COMMON_CHORDS[chordName]) {
169
+ selectedFrets = [...COMMON_CHORDS[chordName]];
170
+ // If selected frets are out of view, maybe jump startFret?
171
+ // Let's just render.
172
+ // Find min/max fret to adjust view?
173
+ // Optional polish. For now, leave startFret as user set.
174
+ renderFretboard();
175
+ detectChord();
176
+ }
177
+ });
178
+
179
+ document.getElementById('transpose-up').addEventListener('click', () => transpose(1));
180
+ document.getElementById('transpose-down').addEventListener('click', () => transpose(-1));
181
+
182
+ const startFretInput = document.getElementById('start-fret');
183
+ if (startFretInput) {
184
+ startFretInput.addEventListener('change', (e) => {
185
+ let val = parseInt(e.target.value);
186
+ if (val < 0) val = 0;
187
+ if (val > 15) val = 15; // Arbitrary max
188
+ startFret = val;
189
+ renderFretboard();
190
+ });
191
+ }
192
+ }
193
+
194
+ function transpose(semitones) {
195
+ // Shift all selected frets
196
+ for (let i = 0; i < selectedFrets.length; i++) {
197
+ if (selectedFrets[i] !== -1) { // Don't shift muted strings
198
+ let newFret = selectedFrets[i] + semitones;
199
+ // logic for open strings shifting down implies they can't go below 0 unless muted.
200
+ if (newFret < 0) newFret = 0; // clamp
201
+ if (newFret > 24) newFret = 24; // arbitrary max
202
+ selectedFrets[i] = newFret;
203
+ }
204
+ }
205
+ renderFretboard();
206
+ detectChord();
207
+
208
+ // Reset select to custom because we modified it
209
+ document.getElementById('chord-select').value = "";
210
+ }
211
+
212
+ function detectChord() {
213
+ // Collect all notes being played
214
+ const playedNotes = [];
215
+ const playedIndices = [];
216
+
217
+ selectedFrets.forEach((fret, stringIndex) => {
218
+ if (fret !== -1) {
219
+ const noteIndex = (STRING_TUNING[stringIndex] + fret) % 12;
220
+ playedNotes.push(NOTES[noteIndex]);
221
+ playedIndices.push(noteIndex);
222
+ }
223
+ });
224
+
225
+ if (playedNotes.length === 0) {
226
+ document.getElementById('detected-chord').textContent = "--";
227
+ return;
228
+ }
229
+
230
+ // Remove duplicates and sort
231
+ const uniqueIndices = [...new Set(playedIndices)].sort((a, b) => a - b);
232
+
233
+ // Try to match against formulas
234
+ // We need to check every note as a potential root
235
+ let bestMatch = null;
236
+
237
+ for (const rootIndex of uniqueIndices) {
238
+ const rootNote = NOTES[rootIndex];
239
+
240
+ // Calculate intervals relative to this root
241
+ const currentIntervals = uniqueIndices.map(index => {
242
+ let interval = index - rootIndex;
243
+ if (interval < 0) interval += 12;
244
+ return interval;
245
+ }).sort((a, b) => a - b);
246
+
247
+ // Compare with formulas
248
+ for (const [type, formula] of Object.entries(CHORD_FORMULAS)) {
249
+ if (arraysEqual(currentIntervals, formula)) {
250
+ bestMatch = `${rootNote} ${type}`;
251
+ break;
252
+ }
253
+ }
254
+ if (bestMatch) break;
255
+ }
256
+
257
+ document.getElementById('detected-chord').textContent = bestMatch || "Unknown";
258
+ }
259
+
260
+ function arraysEqual(a, b) {
261
+ if (a.length !== b.length) return false;
262
+ for (let i = 0; i < a.length; i++) {
263
+ if (a[i] !== b[i]) return false;
264
+ }
265
+ return true;
266
+ }
267
+
268
+ init();