lyraxis-notification 1.0.0 → 1.0.2

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/index.html CHANGED
@@ -1,34 +1,1573 @@
1
1
  <!DOCTYPE html>
2
- <html lang="id">
2
+ <html lang="en">
3
3
  <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <meta name="robots" content="index, follow" />
7
- <meta name="theme-color" content="#627254" />
8
- <meta name="keywords" content="Belum tau, Mimin belum tau, Halaman utama, Belum tau utama, Belum tau my id" />
9
- <meta name="description" content="Fakta unik dan ilmu baru yang jarang diketahui banyak orang, disajikan dari sumber terpercaya untuk menambah wawasanmu." />
10
-
11
- <meta property="og:title" content="Belum tau - Gali Ilmu–mu disini!" />
12
- <meta property="og:description" content="Ga paham? Yuk sini mimin Belum tau." />
13
- <meta property="og:image" content="https://belumtau.com/upload/image/preview-image.png" />
14
- <meta property="og:url" content="https://belumtau.com" />
15
- <meta property="og:type" content="website" />
16
-
17
- <meta name="twitter:card" content="summary_large_image" />
18
- <meta name="twitter:title" content="Belum tau - Home" />
19
- <meta name="twitter:description" content="Ga paham? Yuk sini mimin Belum tau." />
20
- <meta name="twitter:image" content="https://belumtau.com/upload/image/preview-image.png" />
21
- <meta name="twitter:url" content="https://belumtau.com" />
22
- <meta name="twitter:site" content="@KeztOfficial" />
23
-
24
- <link rel="shortcut icon" href="https://belumtau.com/upload/image/main.png" type="image/x-icon" />
25
- <link rel="stylesheet" href="../styles.css" type="text/css" />
26
- <title>Lyraxis | Library Notification</title>
27
-
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Lyraxis — Documentation</title>
7
+ <link rel="icon" href="assets/main.png" type="image/png">
8
+ <style>
9
+ :root {
10
+ --primary: #d0e505;
11
+ --primary-soft: rgba(208, 229, 5, .10);
12
+ --primary-border: rgba(208, 229, 5, .28);
13
+ --bg: #0c0d0f;
14
+ --surface: #111317;
15
+ --surface-2: #17191e;
16
+ --surface-3: #1d2026;
17
+ --border: #292d35;
18
+ --text: #f2f3f5;
19
+ --muted: #9b9fa8;
20
+ --muted-2: #6e737d;
21
+ --success: #22c55e;
22
+ --warning: #eab308;
23
+ --danger: #ef4444;
24
+ --active: #3b82f6;
25
+ --radius: 14px;
26
+ }
27
+
28
+ * {
29
+ box-sizing: border-box;
30
+ }
31
+
32
+ html {
33
+ scroll-behavior: smooth;
34
+ scroll-padding-top: 80px;
35
+ }
36
+
37
+ body {
38
+ margin: 0;
39
+ background: var(--bg);
40
+ color: var(--text);
41
+ font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
42
+ line-height: 1.65;
43
+ }
44
+
45
+ a {
46
+ color: inherit;
47
+ text-decoration: none;
48
+ }
49
+
50
+ code {
51
+ font-family: "SFMono-Regular", Consolas, "Liberation Mono", monospace;
52
+ }
53
+
54
+ .topbar {
55
+ position: sticky;
56
+ top: 0;
57
+ height: 64px;
58
+ display: flex;
59
+ align-items: center;
60
+ justify-content: space-between;
61
+ padding: 0 28px;
62
+ background: rgba(12, 13, 15, .92);
63
+ border-bottom: 1px solid var(--border);
64
+ backdrop-filter: blur(18px);
65
+ z-index: 1000;
66
+ }
67
+
68
+ .brand {
69
+ display: flex;
70
+ align-items: center;
71
+ transition: .2s;
72
+ }
73
+
74
+ .brand:hover {
75
+ opacity: 0.8;
76
+ }
77
+
78
+ .brand img {
79
+ width: 36px;
80
+ height: 36px;
81
+ object-fit: contain;
82
+ }
83
+
84
+ .top-actions {
85
+ display: flex;
86
+ align-items: center;
87
+ gap: 22px;
88
+ font-size: 13px;
89
+ color: var(--muted);
90
+ }
91
+
92
+ .top-actions a {
93
+ transition: .2s;
94
+ }
95
+
96
+ .top-actions a:hover {
97
+ color: var(--primary);
98
+ }
99
+
100
+ .layout {
101
+ display: flex;
102
+ max-width: 1440px;
103
+ margin: auto;
104
+ }
105
+
106
+ .sidebar {
107
+ position: sticky;
108
+ top: 64px;
109
+ width: 240px;
110
+ height: calc(100vh - 64px);
111
+ padding: 30px 20px;
112
+ border-right: 1px solid var(--border);
113
+ overflow-y: auto;
114
+ flex-shrink: 0;
115
+ }
116
+
117
+ .side-title {
118
+ margin-bottom: 16px;
119
+ color: var(--text);
120
+ font-size: 13px;
121
+ font-weight: 750;
122
+ text-transform: uppercase;
123
+ letter-spacing: .8px;
124
+ }
125
+
126
+ .sidebar > a {
127
+ display: block;
128
+ padding: 6px 10px;
129
+ border-radius: 7px;
130
+ color: var(--muted);
131
+ font-size: 13px;
132
+ transition: .18s;
133
+ }
134
+
135
+ .sidebar > a:hover {
136
+ color: var(--primary);
137
+ background: var(--primary-soft);
138
+ }
139
+
140
+ .side-group {
141
+ margin-top: 24px;
142
+ margin-bottom: 6px;
143
+ padding-left: 10px;
144
+ color: var(--muted-2);
145
+ font-size: 11px;
146
+ font-weight: 750;
147
+ text-transform: uppercase;
148
+ letter-spacing: 1px;
149
+ }
150
+
151
+ .content {
152
+ width: 100%;
153
+ min-width: 0;
154
+ padding: 55px 70px 80px;
155
+ }
156
+
157
+ section {
158
+ max-width: 900px;
159
+ margin: 0 auto 95px;
160
+ }
161
+
162
+ .hero {
163
+ max-width: 1000px;
164
+ padding: 45px 0 65px;
165
+ }
166
+
167
+ .eyebrow,
168
+ .section-label {
169
+ color: var(--primary);
170
+ font-size: 11px;
171
+ font-weight: 800;
172
+ letter-spacing: 1.5px;
173
+ }
174
+
175
+ .hero h1 {
176
+ margin: 4px 0 10px;
177
+ font-size: clamp(42px, 7vw, 72px);
178
+ line-height: 1;
179
+ letter-spacing: -3px;
180
+ }
181
+
182
+ .hero p {
183
+ max-width: 680px;
184
+ color: var(--muted);
185
+ font-size: 17px;
186
+ }
187
+
188
+ .hero-buttons {
189
+ display: flex;
190
+ gap: 10px;
191
+ margin-top: 25px;
192
+ }
193
+
194
+ .primary-btn,
195
+ .secondary-btn {
196
+ padding: 10px 18px;
197
+ border-radius: 9px;
198
+ font-size: 13px;
199
+ font-weight: 700;
200
+ transition: .2s;
201
+ }
202
+
203
+ .primary-btn {
204
+ background: var(--primary);
205
+ color: #111;
206
+ }
207
+
208
+ .primary-btn:hover {
209
+ filter: brightness(1.08);
210
+ transform: translateY(-1px);
211
+ }
212
+
213
+ .secondary-btn {
214
+ border: 1px solid var(--border);
215
+ background: var(--surface);
216
+ color: var(--text);
217
+ }
218
+
219
+ .secondary-btn:hover {
220
+ border-color: var(--primary-border);
221
+ color: var(--primary);
222
+ }
223
+
224
+ h2 {
225
+ margin: 4px 0 14px;
226
+ font-size: 31px;
227
+ line-height: 1.2;
228
+ letter-spacing: -.8px;
229
+ }
230
+
231
+ h3 {
232
+ margin: 32px 0 12px;
233
+ font-size: 17px;
234
+ }
235
+
236
+ p {
237
+ color: var(--muted);
238
+ }
239
+
240
+ p code,
241
+ li code {
242
+ padding: 2px 6px;
243
+ border-radius: 5px;
244
+ background: var(--surface-3);
245
+ color: var(--primary);
246
+ font-size: .9em;
247
+ }
248
+
249
+ .signature {
250
+ display: inline-block;
251
+ margin: 12px 0 15px;
252
+ padding: 9px 13px;
253
+ border: 1px solid var(--border);
254
+ border-radius: 8px;
255
+ background: var(--surface);
256
+ color: var(--primary);
257
+ font-size: 13px;
258
+ }
259
+
260
+ .code-box {
261
+ margin: 20px 0;
262
+ overflow: hidden;
263
+ border: 1px solid var(--border);
264
+ border-radius: var(--radius);
265
+ background: #0a0b0d;
266
+ box-shadow: 0 15px 35px rgba(0, 0, 0, .18);
267
+ }
268
+
269
+ .code-head {
270
+ height: 44px;
271
+ display: flex;
272
+ align-items: center;
273
+ justify-content: space-between;
274
+ padding: 0 13px;
275
+ border-bottom: 1px solid var(--border);
276
+ background: var(--surface);
277
+ }
278
+
279
+ .code-head > span {
280
+ color: var(--muted);
281
+ font-size: 11px;
282
+ font-weight: 750;
283
+ text-transform: uppercase;
284
+ letter-spacing: .8px;
285
+ }
286
+
287
+ .code-head div {
288
+ display: flex;
289
+ gap: 6px;
290
+ }
291
+
292
+ .code-head button {
293
+ padding: 5px 9px;
294
+ border: 1px solid var(--border);
295
+ border-radius: 6px;
296
+ background: var(--surface-3);
297
+ color: var(--muted);
298
+ font-size: 11px;
299
+ font-weight: 700;
300
+ cursor: pointer;
301
+ transition: .18s;
302
+ }
303
+
304
+ .code-head button:hover {
305
+ border-color: var(--primary-border);
306
+ color: var(--primary);
307
+ }
308
+
309
+ pre {
310
+ margin: 0;
311
+ padding: 20px;
312
+ overflow-x: auto;
313
+ font-size: 13px;
314
+ line-height: 1.75;
315
+ tab-size: 2;
316
+ }
317
+
318
+ pre code {
319
+ color: #d8dbe1;
320
+ white-space: pre;
321
+ }
322
+
323
+ .quick-grid {
324
+ display: grid;
325
+ grid-template-columns: repeat(3, 1fr);
326
+ gap: 10px;
327
+ margin-top: 25px;
328
+ }
329
+
330
+ .quick-card {
331
+ padding: 17px;
332
+ border: 1px solid var(--border);
333
+ border-radius: 11px;
334
+ background: var(--surface);
335
+ transition: .2s;
336
+ }
337
+
338
+ .quick-card:hover {
339
+ border-color: var(--primary-border);
340
+ transform: translateY(-2px);
341
+ }
342
+
343
+ .quick-card strong {
344
+ display: block;
345
+ color: var(--primary);
346
+ font-size: 13px;
347
+ }
348
+
349
+ .quick-card span {
350
+ color: var(--muted-2);
351
+ font-size: 12px;
352
+ }
353
+
354
+ .api-table {
355
+ margin-top: 22px;
356
+ border: 1px solid var(--border);
357
+ border-radius: 12px;
358
+ overflow: hidden;
359
+ }
360
+
361
+ .api-row {
362
+ display: grid;
363
+ grid-template-columns: 220px 1fr;
364
+ gap: 20px;
365
+ padding: 13px 16px;
366
+ border-bottom: 1px solid var(--border);
367
+ background: var(--surface);
368
+ font-size: 13px;
369
+ }
370
+
371
+ .api-row:last-child {
372
+ border-bottom: 0;
373
+ }
374
+
375
+ .api-row code {
376
+ color: var(--primary);
377
+ }
378
+
379
+ .api-row span {
380
+ color: var(--muted);
381
+ }
382
+
383
+ .api-header {
384
+ background: var(--surface-3);
385
+ color: var(--muted-2);
386
+ font-size: 11px;
387
+ font-weight: 800;
388
+ text-transform: uppercase;
389
+ letter-spacing: .7px;
390
+ }
391
+
392
+ .option-list {
393
+ display: flex;
394
+ flex-direction: column;
395
+ border: 1px solid var(--border);
396
+ border-radius: 11px;
397
+ overflow: hidden;
398
+ margin: 15px 0 25px;
399
+ }
400
+
401
+ .option-list > div {
402
+ display: grid;
403
+ grid-template-columns: 200px 1fr;
404
+ gap: 20px;
405
+ padding: 12px 15px;
406
+ border-bottom: 1px solid var(--border);
407
+ background: var(--surface);
408
+ font-size: 13px;
409
+ }
410
+
411
+ .option-list > div:last-child {
412
+ border-bottom: 0;
413
+ }
414
+
415
+ .option-list code {
416
+ color: var(--primary);
417
+ }
418
+
419
+ .option-list span {
420
+ color: var(--muted);
421
+ }
422
+
423
+ .badge-opt {
424
+ display: inline-block;
425
+ margin-left: 6px;
426
+ padding: 1px 5px;
427
+ border-radius: 4px;
428
+ background: var(--surface-3);
429
+ color: var(--muted-2);
430
+ font-size: 10px;
431
+ font-weight: 700;
432
+ text-transform: uppercase;
433
+ }
434
+
435
+ .tag-list,
436
+ .icon-list {
437
+ display: flex;
438
+ flex-wrap: wrap;
439
+ gap: 7px;
440
+ margin: 15px 0;
441
+ }
442
+
443
+ .tag-list code,
444
+ .icon-list code {
445
+ padding: 6px 9px;
446
+ border: 1px solid var(--border);
447
+ border-radius: 7px;
448
+ background: var(--surface);
449
+ color: var(--primary);
450
+ font-size: 12px;
451
+ }
452
+
453
+ .status-grid {
454
+ display: grid;
455
+ grid-template-columns: repeat(3, 1fr);
456
+ gap: 9px;
457
+ margin: 20px 0;
458
+ }
459
+
460
+ .status-card {
461
+ padding: 15px;
462
+ border: 1px solid var(--border);
463
+ border-radius: 10px;
464
+ background: var(--surface);
465
+ }
466
+
467
+ .status-card strong {
468
+ display: block;
469
+ font-size: 13px;
470
+ }
471
+
472
+ .status-card span {
473
+ color: var(--muted);
474
+ font-size: 11px;
475
+ }
476
+
477
+ .status-card.default strong { color: var(--primary); }
478
+ .status-card.active strong { color: var(--active); }
479
+ .status-card.success strong { color: var(--success); }
480
+ .status-card.warning strong { color: var(--warning); }
481
+ .status-card.failed strong { color: var(--danger); }
482
+ .status-card.waiting strong { color: #9ca3af; }
483
+
484
+ .translation-grid {
485
+ display: grid;
486
+ grid-template-columns: repeat(2, 1fr);
487
+ gap: 8px;
488
+ }
489
+
490
+ .translation-grid > div {
491
+ display: flex;
492
+ flex-direction: column;
493
+ padding: 12px;
494
+ border: 1px solid var(--border);
495
+ border-radius: 8px;
496
+ background: var(--surface);
497
+ }
498
+
499
+ .translation-grid code {
500
+ color: var(--primary);
501
+ font-size: 12px;
502
+ }
503
+
504
+ .translation-grid span {
505
+ color: var(--muted);
506
+ font-size: 11px;
507
+ }
508
+
509
+ .footer-note {
510
+ padding-top: 25px;
511
+ border-top: 1px solid var(--border);
512
+ text-align: center;
513
+ }
514
+
515
+ .footer-brand {
516
+ display: flex;
517
+ align-items: center;
518
+ justify-content: center;
519
+ gap: 8px;
520
+ }
521
+
522
+ .footer-brand img {
523
+ width: 24px;
524
+ height: 24px;
525
+ object-fit: contain;
526
+ }
527
+
528
+ .footer-note p {
529
+ margin: 5px 0;
530
+ font-size: 12px;
531
+ }
532
+
533
+ .footer-note > a {
534
+ color: var(--primary);
535
+ font-size: 12px;
536
+ }
537
+
538
+ .copyright {
539
+ margin-top: 30px;
540
+ color: var(--muted-2);
541
+ font-size: 12px;
542
+ }
543
+
544
+ @keyframes lyCustomPulse {
545
+ 0% { transform: scale(1) rotate(0); }
546
+ 50% { transform: scale(1.25) rotate(180deg); }
547
+ 100% { transform: scale(1) rotate(360deg); }
548
+ }
549
+
550
+ @media (max-width: 900px) {
551
+ .top-actions { display: none; }
552
+ .sidebar { display: none; }
553
+ .content { padding: 35px 22px 60px; }
554
+ .hero { grid-template-columns: 1fr; gap: 20px; }
555
+ .quick-grid { grid-template-columns: repeat(2, 1fr); }
556
+ .status-grid { grid-template-columns: repeat(2, 1fr); }
557
+ }
558
+
559
+ @media (max-width: 560px) {
560
+ .topbar { padding: 0 17px; }
561
+ .content { padding: 28px 15px 50px; }
562
+ section { margin-bottom: 70px; }
563
+ .hero { padding-top: 25px; }
564
+ .hero h1 { letter-spacing: -2px; }
565
+ .quick-grid, .status-grid, .translation-grid { grid-template-columns: 1fr; }
566
+ .api-row { grid-template-columns: 1fr; gap: 3px; }
567
+ .option-list > div { grid-template-columns: 1fr; gap: 3px; }
568
+ pre { padding: 15px; font-size: 12px; }
569
+ }
570
+ </style>
571
+ </head>
572
+ <body>
573
+
574
+ <header class="topbar">
575
+ <a class="brand" href="https://www.lyraxis.my.id" target="_blank" rel="noopener noreferrer">
576
+ <img src="assets/main.png" alt="Lyraxis Logo">
577
+ </a>
578
+
579
+ <div class="top-actions">
580
+ <a href="#installation">Documentation</a>
581
+ <a href="#vanilla">Vanilla</a>
582
+ <a href="#react">React</a>
583
+ <a href="#api">API</a>
584
+ </div>
585
+ </header>
586
+
587
+ <div class="layout">
588
+ <aside class="sidebar">
589
+ <div class="side-title">Documentation</div>
590
+ <a href="#introduction">Introduction</a>
591
+ <a href="#installation">Installation</a>
592
+
593
+ <div class="side-group">Vanilla</div>
594
+ <a href="#vanilla">Setup</a>
595
+ <a href="#vanilla-usage">Usage</a>
596
+
597
+ <div class="side-group">React</div>
598
+ <a href="#react">Setup</a>
599
+ <a href="#react-usage">Usage</a>
600
+
601
+ <div class="side-group">API</div>
602
+ <a href="#api">Overview</a>
603
+ <a href="#log">lyn.log()</a>
604
+ <a href="#info">lyn.info()</a>
605
+ <a href="#confirm">lyn.confirm()</a>
606
+ <a href="#prompt">lyn.prompt()</a>
607
+ <a href="#toast">lyn.toast()</a>
608
+ <a href="#dynamic">lyn.dynamicIsland()</a>
609
+ <a href="#language">lyn.setLang()</a>
610
+ <a href="#sound">lyn.soundNotification()</a>
611
+
612
+ <div class="side-group">Dynamic Island</div>
613
+ <a href="#dynamic-status">Status</a>
614
+ <a href="#dynamic-icons">Icons</a>
615
+ <a href="#dynamic-custom">Custom</a>
616
+ <a href="#dynamic-animation">Animation</a>
617
+ </aside>
618
+
619
+ <main class="content">
620
+
621
+ <section class="hero" id="introduction">
622
+ <div>
623
+ <div class="eyebrow">JAVASCRIPT NOTIFICATION LIBRARY</div>
624
+ <h1>Lyraxis</h1>
625
+ <p>
626
+ A lightweight notification system for JavaScript featuring Log, Info, Confirm, Prompt, Toast, Dynamic Island, multi-language support, and sound effects.
627
+ </p>
628
+
629
+ <div class="hero-buttons">
630
+ <a href="#installation" class="primary-btn">Get Started</a>
631
+ <a href="https://www.lyraxis.my.id" target="_blank" rel="noopener noreferrer" class="secondary-btn">Website</a>
632
+ </div>
633
+ </div>
634
+ </section>
635
+
636
+ <section id="installation">
637
+ <div class="section-label">GETTING STARTED</div>
638
+ <code>Installation</code>
639
+ <p>Lyraxis can be integrated directly via Vanilla JavaScript or installed in React projects.</p>
640
+
641
+ <h3>Vanilla JavaScript</h3>
642
+ <p>Simply include the script tag at the bottom of your HTML <code>&lt;body&gt;</code> (styles are automatically injected).</p>
643
+
644
+ <div class="code-box" data-code-id="install-vanilla">
645
+ <div class="code-head">
646
+ <span>HTML</span>
647
+ <div>
648
+ <button onclick="copyCode('install-vanilla')">Copy</button>
649
+ </div>
650
+ </div>
651
+ <pre><code id="install-vanilla">&lt;script src="https://lib.lyraxis.my.id/notification/script.js"&gt;&lt;/script&gt;</code></pre>
652
+ </div>
653
+
654
+ <h3>npm</h3>
655
+ <p>Install the package via npm for module bundlers or React apps.</p>
656
+
657
+ <div class="code-box" data-code-id="install-npm">
658
+ <div class="code-head">
659
+ <span>Terminal</span>
660
+ <div>
661
+ <button onclick="copyCode('install-npm')">Copy</button>
662
+ </div>
663
+ </div>
664
+ <pre><code id="install-npm">npm install lyraxis-notification</code></pre>
665
+ </div>
666
+ </section>
667
+
668
+ <section id="vanilla">
669
+ <div class="section-label">VANILLA JAVASCRIPT</div>
670
+ <h2>Vanilla Setup</h2>
671
+ <p>In Vanilla JavaScript environments, Lyraxis auto-injects its styling and exposes the global <code>lyn</code> object.</p>
672
+
673
+ <div class="code-box" data-code-id="vanilla-setup">
674
+ <div class="code-head">
675
+ <span>HTML</span>
676
+ <div>
677
+ <button onclick="runCode('vanilla-setup')">Run</button>
678
+ <button onclick="copyCode('vanilla-setup')">Copy</button>
679
+ </div>
680
+ </div>
681
+ <pre><code id="vanilla-setup">&lt;!DOCTYPE html&gt;
682
+ &lt;html lang="en"&gt;
683
+ &lt;head&gt;
684
+ &lt;meta charset="UTF-8"&gt;
685
+ &lt;title&gt;Lyraxis Example&lt;/title&gt;
686
+ &lt;/head&gt;
687
+ &lt;body&gt;
688
+
689
+ &lt;button onclick="showNotification()"&gt;Show Notification&lt;/button&gt;
690
+
691
+ &lt;script src="https://lib.lyraxis.my.id/notification/script.js"&gt;&lt;/script&gt;
692
+ &lt;script&gt;
693
+ lyn.soundNotification("allow");
694
+
695
+ function showNotification() {
696
+ lyn.toast({
697
+ Title: "Hello!",
698
+ Mess: "Lyraxis loaded successfully.",
699
+ Status: "success"
700
+ });
701
+ }
702
+ &lt;/script&gt;
703
+
704
+ &lt;/body&gt;
705
+ &lt;/html&gt;</code></pre>
706
+ </div>
707
+ </section>
708
+
709
+ <section id="vanilla-usage">
710
+ <h2>Vanilla Usage</h2>
711
+ <p>All core notification methods are accessible directly through the <code>lyn</code> object.</p>
712
+
713
+ <div class="quick-grid">
714
+ <div class="quick-card">
715
+ <strong>lyn.log()</strong>
716
+ <span>Simple bottom notification</span>
717
+ </div>
718
+ <div class="quick-card">
719
+ <strong>lyn.info()</strong>
720
+ <span>Information modal dialog</span>
721
+ </div>
722
+ <div class="quick-card">
723
+ <strong>lyn.confirm()</strong>
724
+ <span>Confirmation modal dialog</span>
725
+ </div>
726
+ <div class="quick-card">
727
+ <strong>lyn.prompt()</strong>
728
+ <span>Promise-based input modal</span>
729
+ </div>
730
+ <div class="quick-card">
731
+ <strong>lyn.toast()</strong>
732
+ <span>Stackable toast notification</span>
733
+ </div>
734
+ <div class="quick-card">
735
+ <strong>lyn.dynamicIsland()</strong>
736
+ <span>Animated Dynamic Island</span>
737
+ </div>
738
+ </div>
739
+ </section>
740
+
741
+ <section id="react">
742
+ <div class="section-label">REACT</div>
743
+ <h2>React Setup</h2>
744
+ <p>Import and call <code>lyn</code> methods inside your React event handlers.</p>
745
+
746
+ <div class="code-box" data-code-id="react-setup">
747
+ <div class="code-head">
748
+ <span>JSX</span>
749
+ <div>
750
+ <button onclick="copyCode('react-setup')">Copy</button>
751
+ </div>
752
+ </div>
753
+ <pre><code id="react-setup">import lyn from "lyraxis-notification";
754
+
755
+ function App() {
756
+ function showNotification() {
757
+ lyn.toast({
758
+ Title: "Success",
759
+ Mess: "Hello from React!",
760
+ Status: "success"
761
+ });
762
+ }
763
+
764
+ return (
765
+ &lt;button onClick={showNotification}&gt;
766
+ Show Notification
767
+ &lt;/button&gt;
768
+ );
769
+ }
770
+
771
+ export default App;</code></pre>
772
+ </div>
773
+ </section>
774
+
775
+ <section id="react-usage">
776
+ <h2>React Usage</h2>
777
+ <p>Attach methods directly to standard React synthetic events like <code>onClick</code>.</p>
778
+
779
+ <div class="code-box" data-code-id="react-toast">
780
+ <div class="code-head">
781
+ <span>React</span>
782
+ <div>
783
+ <button onclick="copyCode('react-toast')">Copy</button>
784
+ </div>
785
+ </div>
786
+ <pre><code id="react-toast">function App() {
787
+ const notify = () =&gt; {
788
+ lyn.toast({
789
+ Title: "Data Saved",
790
+ Mess: "Your changes have been saved successfully.",
791
+ Status: "success"
792
+ });
793
+ };
794
+
795
+ return (
796
+ &lt;button onClick={notify}&gt;
797
+ Save Changes
798
+ &lt;/button&gt;
799
+ );
800
+ }</code></pre>
801
+ </div>
802
+ </section>
803
+
804
+ <section id="api">
805
+ <div class="section-label">API REFERENCE</div>
806
+ <h2>API Overview</h2>
807
+ <p>Comprehensive list of methods available on the <code>lyn</code> instance. Most parameters are optional and fall back to default values automatically if omitted.</p>
808
+
809
+ <div class="api-table">
810
+ <div class="api-row api-header">
811
+ <span>Method</span>
812
+ <span>Description</span>
813
+ </div>
814
+ <div class="api-row">
815
+ <code>lyn.log()</code>
816
+ <span>Displays a subtle status bar at the bottom of the screen.</span>
817
+ </div>
818
+ <div class="api-row">
819
+ <code>lyn.info()</code>
820
+ <span>Displays an informational modal with title and subtitle.</span>
821
+ </div>
822
+ <div class="api-row">
823
+ <code>lyn.confirm()</code>
824
+ <span>Displays a confirmation modal with callback options.</span>
825
+ </div>
826
+ <div class="api-row">
827
+ <code>lyn.prompt()</code>
828
+ <span>Displays an input modal that resolves a JavaScript Promise.</span>
829
+ </div>
830
+ <div class="api-row">
831
+ <code>lyn.toast()</code>
832
+ <span>Displays a toast notification on the top-right screen.</span>
833
+ </div>
834
+ <div class="api-row">
835
+ <code>lyn.dynamicIsland()</code>
836
+ <span>Displays an expandable Dynamic Island banner.</span>
837
+ </div>
838
+ <div class="api-row">
839
+ <code>lyn.setLang()</code>
840
+ <span>Switches the internal system language ("en" or "id").</span>
841
+ </div>
842
+ <div class="api-row">
843
+ <code>lyn.soundNotification()</code>
844
+ <span>Enables or disables sound effects for notifications.</span>
845
+ </div>
846
+ </div>
847
+ </section>
848
+
849
+ <section id="log">
850
+ <h2>lyn.log()</h2>
851
+ <p>Displays lightweight log bar notifications at the bottom of the viewport.</p>
852
+ <div class="signature">lyn.log(options)</div>
853
+
854
+ <h3>Options</h3>
855
+ <div class="option-list">
856
+ <div>
857
+ <div><code>Mess</code> <span class="badge-opt">Optional</span></div>
858
+ <span>The message text content. Defaults to an empty log line.</span>
859
+ </div>
860
+ <div>
861
+ <div><code>Status</code> <span class="badge-opt">Optional</span></div>
862
+ <span>Notification state ("default" or "error"). Defaults to <code>"default"</code>.</span>
863
+ </div>
864
+ </div>
865
+
866
+ <div class="code-box" data-code-id="log-example">
867
+ <div class="code-head">
868
+ <span>JavaScript</span>
869
+ <div>
870
+ <button onclick="runCode('log-example')">Run</button>
871
+ <button onclick="copyCode('log-example')">Copy</button>
872
+ </div>
873
+ </div>
874
+ <pre><code id="log-example">lyn.log({
875
+ Mess: "Request sent successfully, please wait."
876
+ });
877
+
878
+ lyn.log({
879
+ Status: "error",
880
+ Mess: "Failed to connect to server."
881
+ });</code></pre>
882
+ </div>
883
+ </section>
884
+
885
+ <section id="info">
886
+ <h2>lyn.info()</h2>
887
+ <p>Opens a structured modal dialog containing subtitle, title, and detailed message text.</p>
888
+ <div class="signature">lyn.info(options)</div>
889
+
890
+ <h3>Options</h3>
891
+ <div class="option-list">
892
+ <div>
893
+ <div><code>Subtitle</code> <span class="badge-opt">Optional</span></div>
894
+ <span>Header text shown above the main title. Defaults to the system localized subtitle.</span>
895
+ </div>
896
+ <div>
897
+ <div><code>Title</code> <span class="badge-opt">Optional</span></div>
898
+ <span>Main title text of the modal. Defaults to the system localized title.</span>
899
+ </div>
900
+ <div>
901
+ <div><code>Mess</code> <span class="badge-opt">Optional</span></div>
902
+ <span>Main message body (supports newlines).</span>
903
+ </div>
904
+ </div>
905
+
906
+ <div class="code-box" data-code-id="info-example">
907
+ <div class="code-head">
908
+ <span>JavaScript</span>
909
+ <div>
910
+ <button onclick="runCode('info-example')">Run</button>
911
+ <button onclick="copyCode('info-example')">Copy</button>
912
+ </div>
913
+ </div>
914
+ <pre><code id="info-example">lyn.info({
915
+ Subtitle: "Lyraxis Demo",
916
+ Title: "Information",
917
+ Mess: "This is an informational dialog from lyn.info.\nSecond line text is also supported."
918
+ });</code></pre>
919
+ </div>
920
+ </section>
921
+
922
+ <section id="confirm">
923
+ <h2>lyn.confirm()</h2>
924
+ <p>Displays an interactive confirmation dialog with action callbacks.</p>
925
+ <div class="signature">lyn.confirm(options)</div>
926
+
927
+ <h3>Options</h3>
928
+ <div class="option-list">
929
+ <div>
930
+ <div><code>Mess</code> <span class="badge-opt">Optional</span></div>
931
+ <span>Confirmation prompt message. Defaults to localized default confirm text.</span>
932
+ </div>
933
+ <div>
934
+ <div><code>Event</code> <span class="badge-opt">Optional</span></div>
935
+ <span>Callback function or redirect URL executed when "Continue" is clicked.</span>
936
+ </div>
937
+ </div>
938
+
939
+ <div class="code-box" data-code-id="confirm-example">
940
+ <div class="code-head">
941
+ <span>JavaScript</span>
942
+ <div>
943
+ <button onclick="runCode('confirm-example')">Run</button>
944
+ <button onclick="copyCode('confirm-example')">Copy</button>
945
+ </div>
946
+ </div>
947
+ <pre><code id="confirm-example">lyn.confirm({
948
+ Mess: "Are you sure you want to proceed?",
949
+ Event: function() {
950
+ lyn.log({
951
+ Status: "success",
952
+ Mess: "You pressed Continue."
953
+ });
954
+ }
955
+ });</code></pre>
956
+ </div>
957
+ </section>
958
+
959
+ <section id="prompt">
960
+ <h2>lyn.prompt()</h2>
961
+ <p>Opens an input modal dialog. Returns a Promise that resolves with user input or rejects if cancelled.</p>
962
+ <div class="signature">await lyn.prompt(options)</div>
963
+
964
+ <h3>Options</h3>
965
+ <div class="option-list">
966
+ <div>
967
+ <div><code>Mess</code> <span class="badge-opt">Optional</span></div>
968
+ <span>Input label prompt text. Defaults to localized prompt title.</span>
969
+ </div>
970
+ <div>
971
+ <div><code>Type</code> <span class="badge-opt">Optional</span></div>
972
+ <span>HTML input field type. Defaults to <code>"text"</code>.</span>
973
+ </div>
974
+ </div>
975
+
976
+ <h3>Input Types</h3>
977
+ <div class="tag-list">
978
+ <code>text</code>
979
+ <code>number</code>
980
+ <code>num</code>
981
+ <code>email</code>
982
+ <code>url</code>
983
+ <code>date</code>
984
+ <code>time</code>
985
+ <code>tel</code>
986
+ <code>range</code>
987
+ <code>password</code>
988
+ </div>
989
+
990
+ <div class="code-box" data-code-id="prompt-example">
991
+ <div class="code-head">
992
+ <span>JavaScript</span>
993
+ <div>
994
+ <button onclick="runCode('prompt-example')">Run</button>
995
+ <button onclick="copyCode('prompt-example')">Copy</button>
996
+ </div>
997
+ </div>
998
+ <pre><code id="prompt-example">async function askNumber() {
999
+ try {
1000
+ const number = await lyn.prompt({
1001
+ Mess: "Enter your phone number:",
1002
+ Type: "num"
1003
+ });
1004
+
1005
+ lyn.log({
1006
+ Status: "success",
1007
+ Mess: "You entered: " + number
1008
+ });
1009
+ } catch (err) {
1010
+ lyn.log({
1011
+ Status: "error",
1012
+ Mess: "User cancelled the prompt."
1013
+ });
1014
+ }
1015
+ }
1016
+
1017
+ askNumber();</code></pre>
1018
+ </div>
1019
+ </section>
1020
+
1021
+ <section id="toast">
1022
+ <h2>lyn.toast()</h2>
1023
+ <p>Displays stackable toast notifications at the top-right corner with queued auto-dismissal.</p>
1024
+ <div class="signature">lyn.toast(options)</div>
1025
+
1026
+ <h3>Options</h3>
1027
+ <div class="option-list">
1028
+ <div>
1029
+ <div><code>Title</code> <span class="badge-opt">Optional</span></div>
1030
+ <span>Toast header title. Defaults to status label or localized text.</span>
1031
+ </div>
1032
+ <div>
1033
+ <div><code>Mess</code> <span class="badge-opt">Optional</span></div>
1034
+ <span>Toast body text content.</span>
1035
+ </div>
1036
+ <div>
1037
+ <div><code>Status</code> <span class="badge-opt">Optional</span></div>
1038
+ <span>Toast status theme. Defaults to <code>"default"</code>.</span>
1039
+ </div>
1040
+ <div>
1041
+ <div><code>Permanent</code> <span class="badge-opt">Optional</span></div>
1042
+ <span>If true, the toast will stay until closed manually. Defaults to <code>false</code>.</span>
1043
+ </div>
1044
+ </div>
1045
+
1046
+ <h3>Status Values</h3>
1047
+ <div class="tag-list">
1048
+ <code>default</code>
1049
+ <code>success</code>
1050
+ <code>ok</code>
1051
+ <code>error</code>
1052
+ <code>err</code>
1053
+ <code>failed</code>
1054
+ </div>
1055
+
1056
+ <div class="code-box" data-code-id="toast-example">
1057
+ <div class="code-head">
1058
+ <span>JavaScript</span>
1059
+ <div>
1060
+ <button onclick="runCode('toast-example')">Run</button>
1061
+ <button onclick="copyCode('toast-example')">Copy</button>
1062
+ </div>
1063
+ </div>
1064
+ <pre><code id="toast-example">lyn.toast({
1065
+ Title: "Information",
1066
+ Mess: "This is a default toast.",
1067
+ Status: "default"
1068
+ });
1069
+
1070
+ lyn.toast({
1071
+ Title: "Success",
1072
+ Mess: "Data saved successfully.",
1073
+ Status: "success"
1074
+ });
1075
+
1076
+ lyn.toast({
1077
+ Title: "Error",
1078
+ Mess: "Server error occurred.",
1079
+ Status: "error"
1080
+ });
1081
+
1082
+ lyn.toast({
1083
+ Title: "Permanent",
1084
+ Mess: "This toast will not auto-dismiss.",
1085
+ Status: "default",
1086
+ Permanent: true
1087
+ });</code></pre>
1088
+ </div>
1089
+ </section>
1090
+
1091
+ <section id="dynamic">
1092
+ <h2>lyn.dynamicIsland()</h2>
1093
+ <p>Displays an interactive Dynamic Island banner with smooth expand and collapse animations.</p>
1094
+ <div class="signature">lyn.dynamicIsland(options)</div>
1095
+
1096
+ <h3>Options</h3>
1097
+ <div class="option-list">
1098
+ <div>
1099
+ <div><code>Status</code> <span class="badge-opt">Optional</span></div>
1100
+ <span>Defines color accent and status state. Defaults to <code>"default"</code>.</span>
1101
+ </div>
1102
+ <div>
1103
+ <div><code>Mess</code> <span class="badge-opt">Optional</span></div>
1104
+ <span>Primary message content.</span>
1105
+ </div>
1106
+ <div>
1107
+ <div><code>Label</code> <span class="badge-opt">Optional</span></div>
1108
+ <span>Built-in icon and preset type. Defaults to <code>"info"</code>.</span>
1109
+ </div>
1110
+ <div>
1111
+ <div><code>Duration</code> <span class="badge-opt">Optional</span></div>
1112
+ <span>Display duration in milliseconds.</span>
1113
+ </div>
1114
+ <div>
1115
+ <div><code>CustomIcon</code> <span class="badge-opt">Optional</span></div>
1116
+ <span>Custom SVG or HTML icon string. Requires <code>Label: "custom"</code>.</span>
1117
+ </div>
1118
+ <div>
1119
+ <div><code>CustomColor</code> <span class="badge-opt">Optional</span></div>
1120
+ <span>Custom icon accent color. Requires <code>Label: "custom"</code>.</span>
1121
+ </div>
1122
+ <div>
1123
+ <div><code>CustomAnimation</code> <span class="badge-opt">Optional</span></div>
1124
+ <span>Custom CSS animation rule. Requires <code>Label: "custom"</code>.</span>
1125
+ </div>
1126
+ </div>
1127
+
1128
+ <div class="code-box" data-code-id="dynamic-example">
1129
+ <div class="code-head">
1130
+ <span>JavaScript</span>
1131
+ <div>
1132
+ <button onclick="runCode('dynamic-example')">Run</button>
1133
+ <button onclick="copyCode('dynamic-example')">Copy</button>
1134
+ </div>
1135
+ </div>
1136
+ <pre><code id="dynamic-example">lyn.dynamicIsland({
1137
+ Status: "success",
1138
+ Mess: "File downloaded successfully",
1139
+ Label: "download",
1140
+ Duration: 3000
1141
+ });</code></pre>
1142
+ </div>
1143
+ </section>
1144
+
1145
+ <section id="dynamic-status">
1146
+ <h2>Dynamic Island Statuses</h2>
1147
+ <p>Supported status themes for customizing Dynamic Island visuals.</p>
1148
+
1149
+ <div class="status-grid">
1150
+ <div class="status-card default">
1151
+ <strong>default</strong>
1152
+ <span>Default theme</span>
1153
+ </div>
1154
+ <div class="status-card active">
1155
+ <strong>active</strong>
1156
+ <span>Active theme</span>
1157
+ </div>
1158
+ <div class="status-card success">
1159
+ <strong>success</strong>
1160
+ <span>Success theme</span>
1161
+ </div>
1162
+ <div class="status-card warning">
1163
+ <strong>warning</strong>
1164
+ <span>Warning theme</span>
1165
+ </div>
1166
+ <div class="status-card failed">
1167
+ <strong>failed</strong>
1168
+ <span>Error theme</span>
1169
+ </div>
1170
+ <div class="status-card waiting">
1171
+ <strong>waiting</strong>
1172
+ <span>Pending state</span>
1173
+ </div>
1174
+ </div>
1175
+
1176
+ <div class="code-box" data-code-id="dynamic-status-example">
1177
+ <div class="code-head">
1178
+ <span>JavaScript</span>
1179
+ <div>
1180
+ <button onclick="runCode('dynamic-status-example')">Run</button>
1181
+ <button onclick="copyCode('dynamic-status-example')">Copy</button>
1182
+ </div>
1183
+ </div>
1184
+ <pre><code id="dynamic-status-example">const statuses = [
1185
+ { Status: "default", Label: "info", Mess: "Default status" },
1186
+ { Status: "active", Label: "info", Mess: "Active status" },
1187
+ { Status: "success", Label: "success", Mess: "Success status" },
1188
+ { Status: "warning", Label: "warning", Mess: "Warning status" },
1189
+ { Status: "failed", Label: "failed", Mess: "Failed status" },
1190
+ { Status: "waiting", Label: "wait", Mess: "Waiting status" }
1191
+ ];
1192
+
1193
+ statuses.forEach(item => lyn.dynamicIsland(item));</code></pre>
1194
+ </div>
1195
+ </section>
1196
+
1197
+ <section id="dynamic-icons">
1198
+ <h2>Dynamic Island Icons</h2>
1199
+ <p>Built-in icon choices mapped to the <code>Label</code> parameter.</p>
1200
+
1201
+ <div class="icon-list">
1202
+ <code>home</code>
1203
+ <code>notification</code>
1204
+ <code>music</code>
1205
+ <code>info</code>
1206
+ <code>download</code>
1207
+ <code>upload</code>
1208
+ <code>settings</code>
1209
+ <code>success</code>
1210
+ <code>failed</code>
1211
+ <code>warning</code>
1212
+ <code>wait</code>
1213
+ </div>
1214
+
1215
+ <div class="code-box" data-code-id="dynamic-icons-example">
1216
+ <div class="code-head">
1217
+ <span>JavaScript</span>
1218
+ <div>
1219
+ <button onclick="runCode('dynamic-icons-example')">Run</button>
1220
+ <button onclick="copyCode('dynamic-icons-example')">Copy</button>
1221
+ </div>
1222
+ </div>
1223
+ <pre><code id="dynamic-icons-example">const icons = [
1224
+ "home", "notification", "music", "info",
1225
+ "download", "upload", "settings", "success",
1226
+ "failed", "warning", "wait"
1227
+ ];
1228
+
1229
+ icons.forEach(icon => {
1230
+ lyn.dynamicIsland({
1231
+ Status: "default",
1232
+ Label: icon,
1233
+ Mess: "Icon: " + icon
1234
+ });
1235
+ });</code></pre>
1236
+ </div>
1237
+ </section>
1238
+
1239
+ <section id="dynamic-custom">
1240
+ <h2>Custom Dynamic Island</h2>
1241
+ <p>Set <code>Label: "custom"</code> to insert custom SVG graphics, colors, and keyframe animations.</p>
1242
+
1243
+ <div class="code-box" data-code-id="dynamic-custom-example">
1244
+ <div class="code-head">
1245
+ <span>JavaScript</span>
1246
+ <div>
1247
+ <button onclick="runCode('dynamic-custom-example')">Run</button>
1248
+ <button onclick="copyCode('dynamic-custom-example')">Copy</button>
1249
+ </div>
1250
+ </div>
1251
+ <pre><code id="dynamic-custom-example">lyn.dynamicIsland({
1252
+ Label: "custom",
1253
+ Mess: "Custom Dynamic Island!",
1254
+ CustomIcon: `
1255
+ &lt;svg viewBox="0 0 24 24"&gt;
1256
+ &lt;path d="M12 2 14.5 9.5 22 12l-7.5 2.5L12 22l-2.5-7.5L2 12l7.5-2.5L12 2Z"/&gt;
1257
+ &lt;/svg&gt;
1258
+ `,
1259
+ CustomColor: "#a855f7",
1260
+ CustomAnimation: "lyCustomPulse 1s ease-in-out infinite"
1261
+ });</code></pre>
1262
+ </div>
1263
+ </section>
1264
+
1265
+ <section id="dynamic-animation">
1266
+ <h2>Custom Animation</h2>
1267
+ <p>Pass custom CSS animation property values and declare keyframe styles in your stylesheet.</p>
1268
+
1269
+ <div class="code-box" data-code-id="dynamic-animation-example">
1270
+ <div class="code-head">
1271
+ <span>JavaScript + CSS</span>
1272
+ <div>
1273
+ <button onclick="runCode('dynamic-animation-example')">Run</button>
1274
+ <button onclick="copyCode('dynamic-animation-example')">Copy</button>
1275
+ </div>
1276
+ </div>
1277
+ <pre><code id="dynamic-animation-example">lyn.dynamicIsland({
1278
+ Label: "custom",
1279
+ Mess: "Custom pulse animation!",
1280
+ CustomIcon: '&lt;svg viewBox="0 0 24 24"&gt;&lt;path d="M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20Z"/&gt;&lt;/svg&gt;',
1281
+ CustomColor: "#d0e505",
1282
+ CustomAnimation: "lyCustomPulse 1s ease-in-out infinite"
1283
+ });
1284
+
1285
+ /*
1286
+ CSS Keyframes:
1287
+ @keyframes lyCustomPulse {
1288
+ 0% { transform: scale(1) rotate(0); }
1289
+ 50% { transform: scale(1.25) rotate(180deg); }
1290
+ 100% { transform: scale(1) rotate(360deg); }
1291
+ }
1292
+ */</code></pre>
1293
+ </div>
1294
+ </section>
1295
+
1296
+ <section id="language">
1297
+ <h2>lyn.setLang()</h2>
1298
+ <p>Switch between supported localization presets (English and Indonesian).</p>
1299
+ <div class="signature">lyn.setLang(language)</div>
1300
+
1301
+ <div class="tag-list">
1302
+ <code>en</code>
1303
+ <code>id</code>
1304
+ </div>
1305
+
1306
+ <div class="code-box" data-code-id="language-example">
1307
+ <div class="code-head">
1308
+ <span>JavaScript</span>
1309
+ <div>
1310
+ <button onclick="runCode('language-example')">Run</button>
1311
+ <button onclick="copyCode('language-example')">Copy</button>
1312
+ </div>
1313
+ </div>
1314
+ <pre><code id="language-example">lyn.setLang("en");
1315
+
1316
+ lyn.info({
1317
+ Mess: "Language is now set to English."
1318
+ });
1319
+
1320
+ lyn.setLang("id");
1321
+
1322
+ lyn.info({
1323
+ Mess: "Bahasa sekarang menggunakan Indonesia."
1324
+ });</code></pre>
1325
+ </div>
1326
+
1327
+ <h3>Localization Keys</h3>
1328
+ <div class="translation-grid">
1329
+ <div><code>title_info</code><span>Info modal title</span></div>
1330
+ <div><code>subtitle_info</code><span>Info modal subtitle</span></div>
1331
+ <div><code>title_confirm</code><span>Confirm modal title</span></div>
1332
+ <div><code>subtitle_confirm</code><span>Confirm modal subtitle</span></div>
1333
+ <div><code>default_confirm</code><span>Default confirm message</span></div>
1334
+ <div><code>cancel</code><span>Cancel button text</span></div>
1335
+ <div><code>continue</code><span>Continue button text</span></div>
1336
+ <div><code>ok</code><span>OK button text</span></div>
1337
+ <div><code>prompt_title</code><span>Prompt title</span></div>
1338
+ <div><code>prompt_subtitle</code><span>Prompt subtitle</span></div>
1339
+ <div><code>send</code><span>Send button text</span></div>
1340
+ <div><code>bye</code><span>Completion message</span></div>
1341
+ <div><code>error</code><span>Error message</span></div>
1342
+ <div><code>default_titleqr</code><span>Default QR title</span></div>
1343
+ <div><code>any_info</code><span>Custom button info</span></div>
1344
+ </div>
1345
+ </section>
1346
+
1347
+ <section id="sound">
1348
+ <h2>lyn.soundNotification()</h2>
1349
+ <p>Controls global sound effects when triggering notifications.</p>
1350
+ <div class="signature">lyn.soundNotification(value)</div>
1351
+
1352
+ <h3>Supported Values</h3>
1353
+ <div class="tag-list">
1354
+ <code>allow</code>
1355
+ <code>on</code>
1356
+ <code>enable</code>
1357
+ <code>off</code>
1358
+ <code>false</code>
1359
+ <code>true</code>
1360
+ </div>
1361
+
1362
+ <div class="code-box" data-code-id="sound-example">
1363
+ <div class="code-head">
1364
+ <span>JavaScript</span>
1365
+ <div>
1366
+ <button onclick="runCode('sound-example')">Run</button>
1367
+ <button onclick="copyCode('sound-example')">Copy</button>
1368
+ </div>
1369
+ </div>
1370
+ <pre><code id="sound-example">lyn.soundNotification("allow");
1371
+
1372
+ lyn.toast({
1373
+ Title: "Sound ON",
1374
+ Mess: "Notification sounds enabled.",
1375
+ Status: "success"
1376
+ });
1377
+
1378
+ lyn.soundNotification("off");
1379
+
1380
+ lyn.toast({
1381
+ Title: "Sound OFF",
1382
+ Mess: "Notification sounds disabled."
1383
+ });</code></pre>
1384
+ </div>
1385
+ </section>
1386
+
1387
+ <section>
1388
+ <div class="section-label">COMPLETE EXAMPLE</div>
1389
+ <h2>Example Project</h2>
1390
+ <p>A full integration example demonstrating multiple Lyraxis notification types together.</p>
1391
+
1392
+ <div class="code-box" data-code-id="complete-example">
1393
+ <div class="code-head">
1394
+ <span>HTML</span>
1395
+ <div>
1396
+ <button onclick="runCode('complete-example')">Run</button>
1397
+ <button onclick="copyCode('complete-example')">Copy</button>
1398
+ </div>
1399
+ </div>
1400
+ <pre><code id="complete-example">&lt;button onclick="showToast()"&gt;Toast&lt;/button&gt;
1401
+ &lt;button onclick="showConfirm()"&gt;Confirm&lt;/button&gt;
1402
+ &lt;button onclick="showDynamic()"&gt;Dynamic Island&lt;/button&gt;
1403
+
1404
+ &lt;script src="https://lib.lyraxis.my.id/notification/script.js"&gt;&lt;/script&gt;
1405
+
1406
+ &lt;script&gt;
1407
+ lyn.soundNotification("allow");
1408
+
1409
+ function showToast() {
1410
+ lyn.toast({
1411
+ Title: "Lyraxis",
1412
+ Mess: "Hello from Lyraxis!",
1413
+ Status: "success"
1414
+ });
1415
+ }
1416
+
1417
+ function showConfirm() {
1418
+ lyn.confirm({
1419
+ Mess: "Are you sure you want to proceed?",
1420
+ Event: function() {
1421
+ lyn.log({
1422
+ Status: "success",
1423
+ Mess: "Proceeded successfully."
1424
+ });
1425
+ }
1426
+ });
1427
+ }
1428
+
1429
+ function showDynamic() {
1430
+ lyn.dynamicIsland({
1431
+ Status: "success",
1432
+ Label: "download",
1433
+ Mess: "Download finished!",
1434
+ Duration: 3000
1435
+ });
1436
+ }
1437
+ &lt;/script&gt;</code></pre>
1438
+ </div>
1439
+ </section>
1440
+
1441
+ <section class="footer-note">
1442
+ <div class="footer-brand">
1443
+ <img src="assets/main.png" alt="Lyraxis Logo">
1444
+ <strong>Lyraxis</strong>
1445
+ </div>
1446
+ <p>Lightweight notification system for modern web projects.</p>
1447
+ <a href="https://www.lyraxis.my.id" target="_blank" rel="noopener noreferrer">www.lyraxis.my.id</a>
1448
+ <div class="copyright">© Lyraxis 2026.</div>
1449
+ </section>
1450
+
1451
+ </main>
1452
+ </div>
1453
+
1454
+ <!-- Local Script Path for index.html -->
1455
+ <script src="./script.js"></script>
1456
+
1457
+ <script>
1458
+ const CDN_SCRIPT = "https://lib.lyraxis.my.id/notification/script.js";
1459
+
1460
+ function getCode(id) {
1461
+ const element = document.getElementById(id);
1462
+ return element ? element.textContent : "";
1463
+ }
1464
+
1465
+ async function copyCode(id) {
1466
+ const code = getCode(id);
1467
+ if (!code) return;
1468
+
1469
+ try {
1470
+ await navigator.clipboard.writeText(code);
1471
+ if (typeof lyn !== "undefined") {
1472
+ lyn.toast({
1473
+ Title: "Copied",
1474
+ Mess: "Code copied to clipboard.",
1475
+ Status: "success"
1476
+ });
1477
+ }
1478
+ } catch (error) {
1479
+ const textarea = document.createElement("textarea");
1480
+ textarea.value = code;
1481
+ textarea.style.position = "fixed";
1482
+ textarea.style.opacity = "0";
1483
+ document.body.appendChild(textarea);
1484
+ textarea.select();
1485
+ document.execCommand("copy");
1486
+ textarea.remove();
1487
+
1488
+ if (typeof lyn !== "undefined") {
1489
+ lyn.toast({
1490
+ Title: "Copied",
1491
+ Mess: "Code copied to clipboard.",
1492
+ Status: "success"
1493
+ });
1494
+ }
1495
+ }
1496
+ }
1497
+
1498
+ function runCode(id) {
1499
+ const code = getCode(id);
1500
+ if (!code) return;
1501
+
1502
+ try {
1503
+ const cleanCode = code
1504
+ .replace(/&lt;/g, "<")
1505
+ .replace(/&gt;/g, ">")
1506
+ .replace(/&amp;/g, "&");
1507
+
1508
+ // Single JS snippet executed directly on page
1509
+ if (!cleanCode.includes("<!DOCTYPE") && !cleanCode.includes("<html") && !cleanCode.includes("<button")) {
1510
+ if (typeof lyn !== "undefined") {
1511
+ new Function(cleanCode)();
1512
+ } else {
1513
+ alert("Lyraxis script is not ready yet!");
1514
+ }
1515
+ return;
1516
+ }
1517
+
1518
+ // Full HTML blocks opened safely in a new tab using CDN
1519
+ let fullHtml = cleanCode;
1520
+ if (!cleanCode.includes("<html")) {
1521
+ fullHtml = `<!DOCTYPE html>
1522
+ <html lang="en">
1523
+ <head>
1524
+ <meta charset="UTF-8">
1525
+ <title>Lyraxis Test Run</title>
1526
+ <style>
1527
+ body {
1528
+ background: #0c0d0f;
1529
+ color: #f2f3f5;
1530
+ font-family: sans-serif;
1531
+ padding: 40px;
1532
+ display: flex;
1533
+ gap: 12px;
1534
+ align-items: center;
1535
+ }
1536
+ button {
1537
+ padding: 10px 18px;
1538
+ background: #d0e505;
1539
+ color: #111;
1540
+ border: none;
1541
+ border-radius: 8px;
1542
+ font-weight: bold;
1543
+ cursor: pointer;
1544
+ }
1545
+ </style>
28
1546
  </head>
29
1547
  <body>
30
- <script src="../main.js"></script>
1548
+ ${cleanCode}
1549
+ <script src="${CDN_SCRIPT}"><\/script>
1550
+ </body>
1551
+ </html>`;
1552
+ }
31
1553
 
32
-
1554
+ const blob = new Blob([fullHtml], { type: "text/html" });
1555
+ const url = URL.createObjectURL(blob);
1556
+ window.open(url, "_blank", "noopener,noreferrer");
1557
+ setTimeout(() => URL.revokeObjectURL(url), 10000);
1558
+ } catch (error) {
1559
+ if (typeof lyn !== "undefined") {
1560
+ lyn.toast({
1561
+ Title: "Run Error",
1562
+ Mess: error.message || "An error occurred.",
1563
+ Status: "error",
1564
+ Permanent: true
1565
+ });
1566
+ } else {
1567
+ console.error(error);
1568
+ }
1569
+ }
1570
+ }
1571
+ </script>
33
1572
  </body>
34
- </html>
1573
+ </html>