Spaces:
Sleeping
Sleeping
Commit ·
004e9ac
1
Parent(s): 30f8f43
Fix menu issues
Browse files- css/styles.css +176 -47
- index.html +114 -160
- sw.js +1 -1
css/styles.css
CHANGED
|
@@ -1,13 +1,13 @@
|
|
| 1 |
/* Chrome, Safari, Edge, Opera */
|
| 2 |
input::-webkit-outer-spin-button,
|
| 3 |
input::-webkit-inner-spin-button {
|
| 4 |
-
|
| 5 |
-
|
| 6 |
}
|
| 7 |
|
| 8 |
/* Firefox */
|
| 9 |
input[type=number] {
|
| 10 |
-
|
| 11 |
}
|
| 12 |
|
| 13 |
* {
|
|
@@ -402,7 +402,7 @@ input[type="checkbox"] {
|
|
| 402 |
display: flex;
|
| 403 |
flex-direction: column; /* <-- stack rows vertically */
|
| 404 |
align-items: flex-start;
|
| 405 |
-
gap: 12px;
|
| 406 |
width: 100%;
|
| 407 |
}
|
| 408 |
|
|
@@ -481,8 +481,6 @@ input[type="checkbox"] {
|
|
| 481 |
}
|
| 482 |
|
| 483 |
|
| 484 |
-
|
| 485 |
-
|
| 486 |
/* Popup Styles */
|
| 487 |
.popup-overlay {
|
| 488 |
position: fixed;
|
|
@@ -498,7 +496,7 @@ input[type="checkbox"] {
|
|
| 498 |
backdrop-filter: blur(5px);
|
| 499 |
}
|
| 500 |
|
| 501 |
-
.popup-content {
|
| 502 |
background: linear-gradient(135deg, #1a2a6c, #b21f1f);
|
| 503 |
border-radius: 15px;
|
| 504 |
padding: 0;
|
|
@@ -522,7 +520,7 @@ input[type="checkbox"] {
|
|
| 522 |
}
|
| 523 |
}
|
| 524 |
|
| 525 |
-
.popup-header {
|
| 526 |
display: flex;
|
| 527 |
justify-content: space-between;
|
| 528 |
align-items: center;
|
|
@@ -532,7 +530,7 @@ input[type="checkbox"] {
|
|
| 532 |
}
|
| 533 |
|
| 534 |
|
| 535 |
-
.popup-header h2 {
|
| 536 |
margin: 0;
|
| 537 |
font-size: 1.5rem;
|
| 538 |
}
|
|
@@ -556,23 +554,23 @@ input[type="checkbox"] {
|
|
| 556 |
background: rgba(255, 255, 255, 0.1);
|
| 557 |
}
|
| 558 |
|
| 559 |
-
.popup-body {
|
| 560 |
padding: 25px;
|
| 561 |
overflow-y: auto;
|
| 562 |
max-height: calc(80vh - 80px);
|
| 563 |
}
|
| 564 |
|
| 565 |
-
.popup-body p {
|
| 566 |
margin-bottom: 15px;
|
| 567 |
line-height: 1.5;
|
| 568 |
}
|
| 569 |
|
| 570 |
-
.popup-body ul {
|
| 571 |
margin: 15px 0;
|
| 572 |
padding-left: 20px;
|
| 573 |
}
|
| 574 |
|
| 575 |
-
.popup-body li {
|
| 576 |
margin-bottom: 8px;
|
| 577 |
line-height: 1.4;
|
| 578 |
}
|
|
@@ -591,20 +589,20 @@ input[type="checkbox"] {
|
|
| 591 |
|
| 592 |
/* Responsive design for popup */
|
| 593 |
@media (max-width: 600px) {
|
| 594 |
-
.popup-content {
|
| 595 |
width: 95%;
|
| 596 |
margin: 20px;
|
| 597 |
}
|
| 598 |
|
| 599 |
-
.popup-body {
|
| 600 |
padding: 20px;
|
| 601 |
}
|
| 602 |
|
| 603 |
-
.popup-header {
|
| 604 |
padding: 15px;
|
| 605 |
}
|
| 606 |
|
| 607 |
-
.popup-header h2 {
|
| 608 |
font-size: 1.3rem;
|
| 609 |
}
|
| 610 |
}
|
|
@@ -625,7 +623,8 @@ input[type="checkbox"] {
|
|
| 625 |
}
|
| 626 |
|
| 627 |
/* Info Button Styles */
|
| 628 |
-
.
|
|
|
|
| 629 |
background: rgba(255, 255, 255, 0.1);
|
| 630 |
border: 1px solid rgba(255, 255, 255, 0.2);
|
| 631 |
border-radius: 50%;
|
|
@@ -638,9 +637,6 @@ input[type="checkbox"] {
|
|
| 638 |
justify-content: center;
|
| 639 |
gap: 2px;
|
| 640 |
transition: all 0.3s ease;
|
| 641 |
-
position: absolute;
|
| 642 |
-
right: 0;
|
| 643 |
-
top: 0;
|
| 644 |
}
|
| 645 |
|
| 646 |
.dot {
|
|
@@ -651,12 +647,12 @@ input[type="checkbox"] {
|
|
| 651 |
transition: all 0.3s ease;
|
| 652 |
}
|
| 653 |
|
| 654 |
-
.
|
| 655 |
background: rgba(255, 255, 255, 0.2);
|
| 656 |
transform: scale(1.1);
|
| 657 |
}
|
| 658 |
|
| 659 |
-
.
|
| 660 |
background: #fff;
|
| 661 |
}
|
| 662 |
|
|
@@ -666,7 +662,7 @@ input[type="checkbox"] {
|
|
| 666 |
border-top: 1px solid #eee;
|
| 667 |
}
|
| 668 |
|
| 669 |
-
.popup-body a {
|
| 670 |
color: #64b5f6;
|
| 671 |
text-decoration: none;
|
| 672 |
transition: all 0.3s ease;
|
|
@@ -674,18 +670,18 @@ input[type="checkbox"] {
|
|
| 674 |
padding-bottom: 1px;
|
| 675 |
}
|
| 676 |
|
| 677 |
-
.popup-body a:hover {
|
| 678 |
color: #90caf9;
|
| 679 |
border-bottom-color: #90caf9;
|
| 680 |
text-shadow: 0 0 8px rgba(144, 202, 249, 0.3);
|
| 681 |
}
|
| 682 |
|
| 683 |
-
.popup-body a:active {
|
| 684 |
color: #42a5f5;
|
| 685 |
transform: translateY(1px);
|
| 686 |
}
|
| 687 |
|
| 688 |
-
.popup-body a:focus {
|
| 689 |
outline: 2px solid rgba(100, 181, 246, 0.5);
|
| 690 |
outline-offset: 2px;
|
| 691 |
border-radius: 2px;
|
|
@@ -704,7 +700,7 @@ input[type="checkbox"] {
|
|
| 704 |
}
|
| 705 |
|
| 706 |
/* Ensure links are visible in the dark theme */
|
| 707 |
-
.popup-body strong {
|
| 708 |
color: #fff;
|
| 709 |
}
|
| 710 |
|
|
@@ -713,17 +709,17 @@ input[type="checkbox"] {
|
|
| 713 |
}
|
| 714 |
|
| 715 |
/* Smooth scrolling for better user experience */
|
| 716 |
-
.popup-body {
|
| 717 |
scroll-behavior: smooth;
|
| 718 |
}
|
| 719 |
|
| 720 |
/* Responsive link styles */
|
| 721 |
@media (max-width: 600px) {
|
| 722 |
-
.popup-body a {
|
| 723 |
padding-bottom: 2px;
|
| 724 |
}
|
| 725 |
|
| 726 |
-
.popup-body a:focus {
|
| 727 |
outline-offset: 1px;
|
| 728 |
}
|
| 729 |
}
|
|
@@ -812,8 +808,24 @@ input[type="checkbox"] {
|
|
| 812 |
}
|
| 813 |
|
| 814 |
/* Info Menu Styles */
|
| 815 |
-
.
|
| 816 |
animation: menuFadeIn 0.2s ease-out;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 817 |
}
|
| 818 |
|
| 819 |
@keyframes menuFadeIn {
|
|
@@ -827,39 +839,156 @@ input[type="checkbox"] {
|
|
| 827 |
}
|
| 828 |
}
|
| 829 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 830 |
/* Recent Files Menu Styles */
|
| 831 |
-
.recent-files-
|
| 832 |
animation: popupFadeIn 0.3s ease-out;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 833 |
}
|
| 834 |
|
| 835 |
.recent-file-item:hover {
|
| 836 |
-
background: rgba(255, 255, 255, 0.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 837 |
}
|
| 838 |
|
| 839 |
.remove-recent-file:hover {
|
| 840 |
-
background: rgba(244, 67, 54, 0.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 841 |
}
|
| 842 |
|
| 843 |
.close-recent-menu:hover {
|
| 844 |
-
background: rgba(255, 255, 255, 0.
|
| 845 |
-
|
| 846 |
}
|
| 847 |
|
| 848 |
-
/* Ensure header has proper positioning for the menu */
|
| 849 |
-
.header-top {
|
| 850 |
-
position: relative;
|
| 851 |
-
}
|
| 852 |
|
| 853 |
/* Responsive design for menus */
|
| 854 |
@media (max-width: 600px) {
|
| 855 |
-
.
|
| 856 |
-
right:
|
| 857 |
-
left:
|
| 858 |
-
min-width:
|
|
|
|
| 859 |
}
|
| 860 |
|
| 861 |
-
.recent-files-
|
| 862 |
width: 95% !important;
|
| 863 |
margin: 10px;
|
| 864 |
}
|
| 865 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
/* Chrome, Safari, Edge, Opera */
|
| 2 |
input::-webkit-outer-spin-button,
|
| 3 |
input::-webkit-inner-spin-button {
|
| 4 |
+
-webkit-appearance: none;
|
| 5 |
+
margin: 0;
|
| 6 |
}
|
| 7 |
|
| 8 |
/* Firefox */
|
| 9 |
input[type=number] {
|
| 10 |
+
-moz-appearance: textfield;
|
| 11 |
}
|
| 12 |
|
| 13 |
* {
|
|
|
|
| 402 |
display: flex;
|
| 403 |
flex-direction: column; /* <-- stack rows vertically */
|
| 404 |
align-items: flex-start;
|
| 405 |
+
gap: 12px; /* spacing between rows */
|
| 406 |
width: 100%;
|
| 407 |
}
|
| 408 |
|
|
|
|
| 481 |
}
|
| 482 |
|
| 483 |
|
|
|
|
|
|
|
| 484 |
/* Popup Styles */
|
| 485 |
.popup-overlay {
|
| 486 |
position: fixed;
|
|
|
|
| 496 |
backdrop-filter: blur(5px);
|
| 497 |
}
|
| 498 |
|
| 499 |
+
.info-popup-content {
|
| 500 |
background: linear-gradient(135deg, #1a2a6c, #b21f1f);
|
| 501 |
border-radius: 15px;
|
| 502 |
padding: 0;
|
|
|
|
| 520 |
}
|
| 521 |
}
|
| 522 |
|
| 523 |
+
.info-popup-header {
|
| 524 |
display: flex;
|
| 525 |
justify-content: space-between;
|
| 526 |
align-items: center;
|
|
|
|
| 530 |
}
|
| 531 |
|
| 532 |
|
| 533 |
+
.info-popup-header h2 {
|
| 534 |
margin: 0;
|
| 535 |
font-size: 1.5rem;
|
| 536 |
}
|
|
|
|
| 554 |
background: rgba(255, 255, 255, 0.1);
|
| 555 |
}
|
| 556 |
|
| 557 |
+
.info-popup-body {
|
| 558 |
padding: 25px;
|
| 559 |
overflow-y: auto;
|
| 560 |
max-height: calc(80vh - 80px);
|
| 561 |
}
|
| 562 |
|
| 563 |
+
.info-popup-body p {
|
| 564 |
margin-bottom: 15px;
|
| 565 |
line-height: 1.5;
|
| 566 |
}
|
| 567 |
|
| 568 |
+
.info-popup-body ul {
|
| 569 |
margin: 15px 0;
|
| 570 |
padding-left: 20px;
|
| 571 |
}
|
| 572 |
|
| 573 |
+
.info-popup-body li {
|
| 574 |
margin-bottom: 8px;
|
| 575 |
line-height: 1.4;
|
| 576 |
}
|
|
|
|
| 589 |
|
| 590 |
/* Responsive design for popup */
|
| 591 |
@media (max-width: 600px) {
|
| 592 |
+
.info-popup-content {
|
| 593 |
width: 95%;
|
| 594 |
margin: 20px;
|
| 595 |
}
|
| 596 |
|
| 597 |
+
.info-popup-body {
|
| 598 |
padding: 20px;
|
| 599 |
}
|
| 600 |
|
| 601 |
+
.info-popup-header {
|
| 602 |
padding: 15px;
|
| 603 |
}
|
| 604 |
|
| 605 |
+
.info-popup-header h2 {
|
| 606 |
font-size: 1.3rem;
|
| 607 |
}
|
| 608 |
}
|
|
|
|
| 623 |
}
|
| 624 |
|
| 625 |
/* Info Button Styles */
|
| 626 |
+
.menu-button {
|
| 627 |
+
position: relative;
|
| 628 |
background: rgba(255, 255, 255, 0.1);
|
| 629 |
border: 1px solid rgba(255, 255, 255, 0.2);
|
| 630 |
border-radius: 50%;
|
|
|
|
| 637 |
justify-content: center;
|
| 638 |
gap: 2px;
|
| 639 |
transition: all 0.3s ease;
|
|
|
|
|
|
|
|
|
|
| 640 |
}
|
| 641 |
|
| 642 |
.dot {
|
|
|
|
| 647 |
transition: all 0.3s ease;
|
| 648 |
}
|
| 649 |
|
| 650 |
+
.menu-button:hover {
|
| 651 |
background: rgba(255, 255, 255, 0.2);
|
| 652 |
transform: scale(1.1);
|
| 653 |
}
|
| 654 |
|
| 655 |
+
.menu-button:hover .dot {
|
| 656 |
background: #fff;
|
| 657 |
}
|
| 658 |
|
|
|
|
| 662 |
border-top: 1px solid #eee;
|
| 663 |
}
|
| 664 |
|
| 665 |
+
.info-popup-body a {
|
| 666 |
color: #64b5f6;
|
| 667 |
text-decoration: none;
|
| 668 |
transition: all 0.3s ease;
|
|
|
|
| 670 |
padding-bottom: 1px;
|
| 671 |
}
|
| 672 |
|
| 673 |
+
.info-popup-body a:hover {
|
| 674 |
color: #90caf9;
|
| 675 |
border-bottom-color: #90caf9;
|
| 676 |
text-shadow: 0 0 8px rgba(144, 202, 249, 0.3);
|
| 677 |
}
|
| 678 |
|
| 679 |
+
.info-popup-body a:active {
|
| 680 |
color: #42a5f5;
|
| 681 |
transform: translateY(1px);
|
| 682 |
}
|
| 683 |
|
| 684 |
+
.info-popup-body a:focus {
|
| 685 |
outline: 2px solid rgba(100, 181, 246, 0.5);
|
| 686 |
outline-offset: 2px;
|
| 687 |
border-radius: 2px;
|
|
|
|
| 700 |
}
|
| 701 |
|
| 702 |
/* Ensure links are visible in the dark theme */
|
| 703 |
+
.info-popup-body strong {
|
| 704 |
color: #fff;
|
| 705 |
}
|
| 706 |
|
|
|
|
| 709 |
}
|
| 710 |
|
| 711 |
/* Smooth scrolling for better user experience */
|
| 712 |
+
.info-popup-body {
|
| 713 |
scroll-behavior: smooth;
|
| 714 |
}
|
| 715 |
|
| 716 |
/* Responsive link styles */
|
| 717 |
@media (max-width: 600px) {
|
| 718 |
+
.info-popup-body a {
|
| 719 |
padding-bottom: 2px;
|
| 720 |
}
|
| 721 |
|
| 722 |
+
.info-popup-body a:focus {
|
| 723 |
outline-offset: 1px;
|
| 724 |
}
|
| 725 |
}
|
|
|
|
| 808 |
}
|
| 809 |
|
| 810 |
/* Info Menu Styles */
|
| 811 |
+
.app-menu {
|
| 812 |
animation: menuFadeIn 0.2s ease-out;
|
| 813 |
+
position: absolute;
|
| 814 |
+
background: linear-gradient(135deg, rgba(26, 42, 108, 0.95), rgba(178, 31, 31, 0.95));
|
| 815 |
+
backdrop-filter: blur(10px);
|
| 816 |
+
border-radius: 10px;
|
| 817 |
+
padding: 8px 0;
|
| 818 |
+
min-width: 200px;
|
| 819 |
+
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
|
| 820 |
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
| 821 |
+
display: none;
|
| 822 |
+
z-index: 9999;
|
| 823 |
+
color: white;
|
| 824 |
+
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
| 825 |
+
}
|
| 826 |
+
|
| 827 |
+
.app-menu.active {
|
| 828 |
+
display: block;
|
| 829 |
}
|
| 830 |
|
| 831 |
@keyframes menuFadeIn {
|
|
|
|
| 839 |
}
|
| 840 |
}
|
| 841 |
|
| 842 |
+
.app-menu .menu-item {
|
| 843 |
+
padding: 12px 16px;
|
| 844 |
+
cursor: pointer;
|
| 845 |
+
transition: all 0.3s ease;
|
| 846 |
+
font-size: 14px;
|
| 847 |
+
border: none;
|
| 848 |
+
background: none;
|
| 849 |
+
width: 100%;
|
| 850 |
+
text-align: left;
|
| 851 |
+
color: white;
|
| 852 |
+
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
| 853 |
+
}
|
| 854 |
+
|
| 855 |
+
.app-menu .menu-item:last-child {
|
| 856 |
+
border-bottom: none;
|
| 857 |
+
}
|
| 858 |
+
|
| 859 |
+
.app-menu .menu-item:hover {
|
| 860 |
+
background: rgba(255, 255, 255, 0.1);
|
| 861 |
+
color: #fff;
|
| 862 |
+
}
|
| 863 |
+
|
| 864 |
+
.app-menu .menu-item:active {
|
| 865 |
+
background: rgba(255, 255, 255, 0.2);
|
| 866 |
+
}
|
| 867 |
+
|
| 868 |
/* Recent Files Menu Styles */
|
| 869 |
+
.recent-files-content {
|
| 870 |
animation: popupFadeIn 0.3s ease-out;
|
| 871 |
+
position: fixed;
|
| 872 |
+
background: linear-gradient(135deg, rgba(26, 42, 108, 0.98), rgba(178, 31, 31, 0.98));
|
| 873 |
+
border-radius: 15px;
|
| 874 |
+
padding: 25px;
|
| 875 |
+
max-width: 500px;
|
| 876 |
+
width: 90%;
|
| 877 |
+
max-height: 70vh;
|
| 878 |
+
overflow-y: auto;
|
| 879 |
+
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
|
| 880 |
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
| 881 |
+
z-index: 1001;
|
| 882 |
+
color: white;
|
| 883 |
+
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
| 884 |
+
}
|
| 885 |
+
|
| 886 |
+
.recent-files-header {
|
| 887 |
+
display: flex;
|
| 888 |
+
justify-content: space-between;
|
| 889 |
+
align-items: center;
|
| 890 |
+
margin-bottom: 20px;
|
| 891 |
+
padding-bottom: 15px;
|
| 892 |
+
border-bottom: 1px solid rgba(255, 255, 255, 0.2)
|
| 893 |
+
}
|
| 894 |
+
|
| 895 |
+
.recent-files-header h3 {
|
| 896 |
+
margin: 0;
|
| 897 |
+
font-size: 1.3rem;
|
| 898 |
+
color: white;
|
| 899 |
+
}
|
| 900 |
+
|
| 901 |
+
.recent-files-body {
|
| 902 |
+
text-align: center;
|
| 903 |
+
padding: 40px 20px;
|
| 904 |
+
opacity: 0.8;
|
| 905 |
+
}
|
| 906 |
+
|
| 907 |
+
.recent-file-item {
|
| 908 |
+
transition: all 0.3s ease;
|
| 909 |
+
border: 1px solid rgba(255, 255, 255, 0.1) !important;
|
| 910 |
+
display: flex;
|
| 911 |
+
justify-content: space-between;
|
| 912 |
+
align-items: center;
|
| 913 |
+
padding: 15px;
|
| 914 |
+
background: rgba(255, 255, 255, 0.08);
|
| 915 |
+
border-radius: 10px;
|
| 916 |
+
cursor: pointer;
|
| 917 |
}
|
| 918 |
|
| 919 |
.recent-file-item:hover {
|
| 920 |
+
background: rgba(255, 255, 255, 0.15) !important;
|
| 921 |
+
border-color: rgba(255, 255, 255, 0.3) !important;
|
| 922 |
+
transform: translateY(-1px);
|
| 923 |
+
}
|
| 924 |
+
|
| 925 |
+
.remove-recent-file {
|
| 926 |
+
transition: all 0.3s ease !important;
|
| 927 |
+
border: 1px solid rgba(244, 67, 54, 0.3) !important;
|
| 928 |
+
background: rgba(244, 67, 54, 0.3);
|
| 929 |
+
color: white;
|
| 930 |
+
border-radius: 6px;
|
| 931 |
+
padding: 6px 12px;
|
| 932 |
+
cursor: pointer;
|
| 933 |
+
font-size: 0.8rem;
|
| 934 |
}
|
| 935 |
|
| 936 |
.remove-recent-file:hover {
|
| 937 |
+
background: rgba(244, 67, 54, 0.6) !important;
|
| 938 |
+
border-color: rgba(244, 67, 54, 0.6) !important;
|
| 939 |
+
transform: scale(1.05);
|
| 940 |
+
}
|
| 941 |
+
|
| 942 |
+
.close-recent-menu {
|
| 943 |
+
transition: all 0.3s ease !important;
|
| 944 |
+
border-radius: 50% !important;
|
| 945 |
+
width: 35px !important;
|
| 946 |
+
height: 35px !important;
|
| 947 |
+
display: flex !important;
|
| 948 |
+
align-items: center !important;
|
| 949 |
+
justify-content: center !important;
|
| 950 |
+
background: rgba(255, 255, 255, 0.1);
|
| 951 |
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
| 952 |
+
color: white;
|
| 953 |
+
font-size: 1.5rem;
|
| 954 |
+
cursor: pointer;
|
| 955 |
+
padding: 0;
|
| 956 |
}
|
| 957 |
|
| 958 |
.close-recent-menu:hover {
|
| 959 |
+
background: rgba(255, 255, 255, 0.15) !important;
|
| 960 |
+
transform: scale(1.1);
|
| 961 |
}
|
| 962 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 963 |
|
| 964 |
/* Responsive design for menus */
|
| 965 |
@media (max-width: 600px) {
|
| 966 |
+
.app-menu {
|
| 967 |
+
right: 0 !important;
|
| 968 |
+
left: auto !important;
|
| 969 |
+
min-width: 180px !important;
|
| 970 |
+
top: 45px !important;
|
| 971 |
}
|
| 972 |
|
| 973 |
+
.recent-files-content {
|
| 974 |
width: 95% !important;
|
| 975 |
margin: 10px;
|
| 976 |
}
|
| 977 |
+
|
| 978 |
+
.menu-button {
|
| 979 |
+
width: 36px;
|
| 980 |
+
height: 36px;
|
| 981 |
+
}
|
| 982 |
+
}
|
| 983 |
+
|
| 984 |
+
/*!* Menu backdrop *!*/
|
| 985 |
+
/*.menu-backdrop {*/
|
| 986 |
+
/* position: fixed;*/
|
| 987 |
+
/* top: 0;*/
|
| 988 |
+
/* left: 0;*/
|
| 989 |
+
/* width: 100%;*/
|
| 990 |
+
/* height: 100%;*/
|
| 991 |
+
/* background: transparent;*/
|
| 992 |
+
/* z-index: 9998;*/
|
| 993 |
+
/* display: none;*/
|
| 994 |
+
/*}*/
|
index.html
CHANGED
|
@@ -19,7 +19,7 @@
|
|
| 19 |
<header>
|
| 20 |
<div class="header-top">
|
| 21 |
<h1>Loop Maestro</h1>
|
| 22 |
-
<button id="
|
| 23 |
<span class="dot"></span>
|
| 24 |
<span class="dot"></span>
|
| 25 |
<span class="dot"></span>
|
|
@@ -28,14 +28,34 @@
|
|
| 28 |
<p class="subtitle">Upload a song, detect beats and bars, then loop any part</p>
|
| 29 |
</header>
|
| 30 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
<!-- Info Popup -->
|
| 32 |
<div id="infoPopup" class="popup-overlay">
|
| 33 |
-
<div class="popup-content">
|
| 34 |
-
<div class="popup-header">
|
| 35 |
<h2>About Loop Maestro</h2>
|
| 36 |
<button id="closePopup" class="close-button">×</button>
|
| 37 |
</div>
|
| 38 |
-
<div class="popup-body">
|
| 39 |
<p><strong>Loop Maestro</strong> is a Progressive Web App that allows you to:</p>
|
| 40 |
<ul>
|
| 41 |
<li>Upload audio files</li>
|
|
@@ -271,7 +291,7 @@
|
|
| 271 |
request.onupgradeneeded = (event) => {
|
| 272 |
const db = event.target.result;
|
| 273 |
if (!db.objectStoreNames.contains('fileHandles')) {
|
| 274 |
-
db.createObjectStore('fileHandles', {
|
| 275 |
}
|
| 276 |
};
|
| 277 |
});
|
|
@@ -645,121 +665,109 @@
|
|
| 645 |
});
|
| 646 |
|
| 647 |
// Enhanced Info Popup functionality with menu
|
| 648 |
-
|
| 649 |
-
|
|
|
|
|
|
|
| 650 |
const closePopup = document.getElementById('closePopup');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 651 |
|
| 652 |
-
//
|
| 653 |
-
this.
|
|
|
|
|
|
|
| 654 |
|
| 655 |
// Open popup
|
| 656 |
-
|
| 657 |
e.stopPropagation();
|
| 658 |
-
this.
|
| 659 |
});
|
| 660 |
|
| 661 |
// Close popup
|
| 662 |
closePopup.addEventListener('click', function () {
|
| 663 |
-
infoPopup.classList.remove('active');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 664 |
document.body.style.overflow = ''; // Restore scrolling
|
| 665 |
});
|
| 666 |
|
| 667 |
// Close popup when clicking outside content
|
| 668 |
-
infoPopup.addEventListener('click', function (e) {
|
|
|
|
| 669 |
if (e.target === infoPopup) {
|
| 670 |
infoPopup.classList.remove('active');
|
| 671 |
document.body.style.overflow = '';
|
| 672 |
}
|
| 673 |
});
|
| 674 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 675 |
// Close popup and menu with Escape key
|
| 676 |
document.addEventListener('keydown', (e) => {
|
| 677 |
if (e.key === 'Escape') {
|
| 678 |
-
infoPopup.classList.remove('active');
|
| 679 |
document.body.style.overflow = '';
|
| 680 |
-
this.
|
| 681 |
}
|
| 682 |
});
|
| 683 |
|
| 684 |
// Close menu when clicking outside
|
| 685 |
document.addEventListener('click', () => {
|
| 686 |
-
this.
|
| 687 |
});
|
| 688 |
}
|
| 689 |
|
| 690 |
-
|
| 691 |
-
this.
|
| 692 |
-
|
| 693 |
-
this.infoMenu.innerHTML = `
|
| 694 |
-
<div class="menu-item" data-action="about">About Loop Maestro</div>
|
| 695 |
-
<div class="menu-item" data-action="recent">Recent Songs</div>
|
| 696 |
-
`;
|
| 697 |
-
this.infoMenu.style.cssText = `
|
| 698 |
-
position: absolute;
|
| 699 |
-
top: 60px;
|
| 700 |
-
right: 0;
|
| 701 |
-
background: rgba(255, 255, 255, 0.95);
|
| 702 |
-
backdrop-filter: blur(10px);
|
| 703 |
-
border-radius: 8px;
|
| 704 |
-
padding: 8px 0;
|
| 705 |
-
min-width: 180px;
|
| 706 |
-
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
|
| 707 |
-
border: 1px solid rgba(255, 255, 255, 0.2);
|
| 708 |
-
display: none;
|
| 709 |
-
z-index: 1000;
|
| 710 |
-
color: #333;
|
| 711 |
-
`;
|
| 712 |
-
|
| 713 |
-
// Style menu items
|
| 714 |
-
const menuItems = this.infoMenu.querySelectorAll('.menu-item');
|
| 715 |
-
menuItems.forEach(item => {
|
| 716 |
-
item.style.cssText = `
|
| 717 |
-
padding: 12px 16px;
|
| 718 |
-
cursor: pointer;
|
| 719 |
-
transition: background-color 0.2s;
|
| 720 |
-
font-size: 14px;
|
| 721 |
-
border: none;
|
| 722 |
-
background: none;
|
| 723 |
-
width: 100%;
|
| 724 |
-
text-align: left;
|
| 725 |
-
`;
|
| 726 |
-
item.addEventListener('mouseenter', () => {
|
| 727 |
-
item.style.backgroundColor = 'rgba(33, 150, 243, 0.1)';
|
| 728 |
-
});
|
| 729 |
-
item.addEventListener('mouseleave', () => {
|
| 730 |
-
item.style.backgroundColor = 'transparent';
|
| 731 |
-
});
|
| 732 |
-
item.addEventListener('click', (e) => {
|
| 733 |
-
e.stopPropagation();
|
| 734 |
-
this.handleMenuAction(item.dataset.action);
|
| 735 |
-
});
|
| 736 |
-
});
|
| 737 |
-
|
| 738 |
-
document.body.appendChild(this.infoMenu);
|
| 739 |
-
}
|
| 740 |
-
|
| 741 |
-
toggleInfoMenu() {
|
| 742 |
-
if (this.infoMenu.style.display === 'block') {
|
| 743 |
-
this.hideInfoMenu();
|
| 744 |
} else {
|
| 745 |
-
this.
|
| 746 |
}
|
| 747 |
}
|
| 748 |
|
| 749 |
-
|
| 750 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 751 |
}
|
| 752 |
|
| 753 |
-
|
| 754 |
-
this.
|
| 755 |
}
|
| 756 |
|
| 757 |
async handleMenuAction(action) {
|
| 758 |
-
this.
|
| 759 |
|
| 760 |
switch (action) {
|
| 761 |
case 'about':
|
| 762 |
-
|
| 763 |
document.body.style.overflow = 'hidden';
|
| 764 |
break;
|
| 765 |
case 'recent':
|
|
@@ -771,115 +779,61 @@
|
|
| 771 |
async showRecentFilesMenu() {
|
| 772 |
await this.loadRecentFiles();
|
| 773 |
|
| 774 |
-
const
|
| 775 |
-
recentFilesMenu.className = 'recent-files-menu';
|
| 776 |
-
recentFilesMenu.style.cssText = `
|
| 777 |
-
position: fixed;
|
| 778 |
-
top: 50%;
|
| 779 |
-
left: 50%;
|
| 780 |
-
transform: translate(-50%, -50%);
|
| 781 |
-
background: rgba(26, 42, 108, 0.95);
|
| 782 |
-
backdrop-filter: blur(10px);
|
| 783 |
-
border-radius: 15px;
|
| 784 |
-
padding: 20px;
|
| 785 |
-
max-width: 500px;
|
| 786 |
-
width: 90%;
|
| 787 |
-
max-height: 70vh;
|
| 788 |
-
overflow-y: auto;
|
| 789 |
-
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
|
| 790 |
-
border: 1px solid rgba(255, 255, 255, 0.2);
|
| 791 |
-
z-index: 1001;
|
| 792 |
-
color: white;
|
| 793 |
-
`;
|
| 794 |
|
| 795 |
-
|
| 796 |
-
|
| 797 |
-
<h3 style="margin: 0;">Recent Songs</h3>
|
| 798 |
-
<button class="close-recent-menu" style="background: none; border: none; color: white; font-size: 1.5rem; cursor: pointer; padding: 0; width: 30px; height: 30px; display: flex; align-items: center; justify-content: center;">×</button>
|
| 799 |
-
</div>
|
| 800 |
-
`;
|
| 801 |
|
| 802 |
if (this.recentFiles.length === 0) {
|
| 803 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 804 |
} else {
|
| 805 |
-
|
| 806 |
|
| 807 |
for (const file of this.recentFiles) {
|
| 808 |
-
|
| 809 |
-
|
| 810 |
-
|
| 811 |
-
|
| 812 |
-
|
| 813 |
-
|
| 814 |
-
|
| 815 |
-
|
| 816 |
-
|
| 817 |
-
transition: background-color 0.2s;
|
| 818 |
-
">
|
| 819 |
-
<div>
|
| 820 |
-
<div style="font-weight: bold;">${file.fileName}</div>
|
| 821 |
-
<div style="font-size: 0.8rem; opacity: 0.8;">${this.formatFileSize(file.fileSize)}</div>
|
| 822 |
-
</div>
|
| 823 |
-
<button class="remove-recent-file" style="
|
| 824 |
-
background: rgba(244, 67, 54, 0.3);
|
| 825 |
-
border: none;
|
| 826 |
-
color: white;
|
| 827 |
-
border-radius: 4px;
|
| 828 |
-
padding: 4px 8px;
|
| 829 |
-
cursor: pointer;
|
| 830 |
-
font-size: 0.8rem;
|
| 831 |
-
">Remove</button>
|
| 832 |
-
</div>
|
| 833 |
-
`;
|
| 834 |
}
|
| 835 |
|
| 836 |
-
|
|
|
|
| 837 |
}
|
| 838 |
|
| 839 |
-
recentFilesMenu.innerHTML = menuContent;
|
| 840 |
-
document.body.appendChild(recentFilesMenu);
|
| 841 |
-
|
| 842 |
-
// Add event listeners
|
| 843 |
-
recentFilesMenu.querySelector('.close-recent-menu').addEventListener('click', () => {
|
| 844 |
-
document.body.removeChild(recentFilesMenu);
|
| 845 |
-
});
|
| 846 |
-
|
| 847 |
-
recentFilesMenu.addEventListener('click', (e) => {
|
| 848 |
-
if (e.target === recentFilesMenu) {
|
| 849 |
-
document.body.removeChild(recentFilesMenu);
|
| 850 |
-
}
|
| 851 |
-
});
|
| 852 |
-
|
| 853 |
// Load file when clicked
|
| 854 |
-
|
| 855 |
item.addEventListener('click', async (e) => {
|
| 856 |
if (!e.target.classList.contains('remove-recent-file')) {
|
| 857 |
const fileId = item.dataset.fileId;
|
| 858 |
await this.loadFileFromHandle(fileId);
|
| 859 |
-
|
| 860 |
}
|
| 861 |
});
|
| 862 |
});
|
| 863 |
|
| 864 |
// Remove file when remove button clicked
|
| 865 |
-
|
| 866 |
button.addEventListener('click', async (e) => {
|
| 867 |
e.stopPropagation();
|
| 868 |
const fileId = button.closest('.recent-file-item').dataset.fileId;
|
| 869 |
await this.removeFromRecentFiles(fileId);
|
| 870 |
-
document.body.removeChild(recentFilesMenu);
|
| 871 |
await this.showRecentFilesMenu(); // Refresh the menu
|
| 872 |
});
|
| 873 |
});
|
| 874 |
|
| 875 |
-
|
| 876 |
-
|
| 877 |
-
if (e.key === 'Escape') {
|
| 878 |
-
document.body.removeChild(recentFilesMenu);
|
| 879 |
-
document.removeEventListener('keydown', closeHandler);
|
| 880 |
-
}
|
| 881 |
-
};
|
| 882 |
-
document.addEventListener('keydown', closeHandler);
|
| 883 |
}
|
| 884 |
|
| 885 |
async openFileWithFileSystemAPI() {
|
|
@@ -914,8 +868,8 @@
|
|
| 914 |
}
|
| 915 |
|
| 916 |
// Verify we still have permission to read the file
|
| 917 |
-
if (await fileRecord.handle.queryPermission({
|
| 918 |
-
const permission = await fileRecord.handle.requestPermission({
|
| 919 |
if (permission !== 'granted') {
|
| 920 |
throw new Error('Permission denied to read the file');
|
| 921 |
}
|
|
|
|
| 19 |
<header>
|
| 20 |
<div class="header-top">
|
| 21 |
<h1>Loop Maestro</h1>
|
| 22 |
+
<button id="menuButton" class="menu-button" aria-label="About this app">
|
| 23 |
<span class="dot"></span>
|
| 24 |
<span class="dot"></span>
|
| 25 |
<span class="dot"></span>
|
|
|
|
| 28 |
<p class="subtitle">Upload a song, detect beats and bars, then loop any part</p>
|
| 29 |
</header>
|
| 30 |
|
| 31 |
+
<div id="appMenu" class="app-menu" style="top:0; left:0">
|
| 32 |
+
<div class="menu-item" data-action="about">About Loop Maestro</div>
|
| 33 |
+
<div class="menu-item" data-action="recent">Recent Songs</div>
|
| 34 |
+
</div>
|
| 35 |
+
|
| 36 |
+
<div id="recentFilesPopup" class="popup-overlay">
|
| 37 |
+
<div class="recent-files-content">
|
| 38 |
+
<div class="recent-files-header">
|
| 39 |
+
<h3>🎵 Recent Songs</h3>
|
| 40 |
+
<button id="closeRecentMenu" class="close-recent-menu">×</button>
|
| 41 |
+
</div>
|
| 42 |
+
|
| 43 |
+
<div id="recentFilesBody" class="recent-files-body">
|
| 44 |
+
<div style="font-size: 3rem; margin-bottom: 10px;">🎵</div>
|
| 45 |
+
<p style="margin: 0; font-size: 1.1rem;">No recent files</p>
|
| 46 |
+
<p style="margin: 10px 0 0 0; font-size: 0.9rem; opacity: 0.7;">Files you open will appear here</p>
|
| 47 |
+
</div>
|
| 48 |
+
</div>
|
| 49 |
+
</div>
|
| 50 |
+
|
| 51 |
<!-- Info Popup -->
|
| 52 |
<div id="infoPopup" class="popup-overlay">
|
| 53 |
+
<div class="info-popup-content">
|
| 54 |
+
<div class="info-popup-header">
|
| 55 |
<h2>About Loop Maestro</h2>
|
| 56 |
<button id="closePopup" class="close-button">×</button>
|
| 57 |
</div>
|
| 58 |
+
<div class="info-popup-body">
|
| 59 |
<p><strong>Loop Maestro</strong> is a Progressive Web App that allows you to:</p>
|
| 60 |
<ul>
|
| 61 |
<li>Upload audio files</li>
|
|
|
|
| 291 |
request.onupgradeneeded = (event) => {
|
| 292 |
const db = event.target.result;
|
| 293 |
if (!db.objectStoreNames.contains('fileHandles')) {
|
| 294 |
+
db.createObjectStore('fileHandles', {keyPath: 'id'});
|
| 295 |
}
|
| 296 |
};
|
| 297 |
});
|
|
|
|
| 665 |
});
|
| 666 |
|
| 667 |
// Enhanced Info Popup functionality with menu
|
| 668 |
+
this.menuButton = document.getElementById('menuButton');
|
| 669 |
+
this.appMenu = document.getElementById('appMenu');
|
| 670 |
+
|
| 671 |
+
this.infoPopup = document.getElementById('infoPopup');
|
| 672 |
const closePopup = document.getElementById('closePopup');
|
| 673 |
+
this.recentFilesPopup = document.getElementById('recentFilesPopup');
|
| 674 |
+
const closeRecentMenu = document.getElementById('closeRecentMenu');
|
| 675 |
+
|
| 676 |
+
// Menu item events
|
| 677 |
+
const menuItems = this.appMenu.querySelectorAll('.menu-item');
|
| 678 |
+
menuItems.forEach(item => {
|
| 679 |
+
item.addEventListener('click', (e) => {
|
| 680 |
+
e.stopPropagation();
|
| 681 |
+
this.handleMenuAction(item.dataset.action);
|
| 682 |
+
this.hideAppMenu();
|
| 683 |
+
});
|
| 684 |
+
});
|
| 685 |
|
| 686 |
+
// Backdrop for closing
|
| 687 |
+
this.recentFilesPopup.addEventListener('click', () => {
|
| 688 |
+
this.hideAppMenu();
|
| 689 |
+
});
|
| 690 |
|
| 691 |
// Open popup
|
| 692 |
+
this.menuButton.addEventListener('click', (e) => {
|
| 693 |
e.stopPropagation();
|
| 694 |
+
this.toggleAppMenu();
|
| 695 |
});
|
| 696 |
|
| 697 |
// Close popup
|
| 698 |
closePopup.addEventListener('click', function () {
|
| 699 |
+
document.getElementById('infoPopup').classList.remove('active');
|
| 700 |
+
document.body.style.overflow = ''; // Restore scrolling
|
| 701 |
+
});
|
| 702 |
+
|
| 703 |
+
closeRecentMenu.addEventListener('click', function () {
|
| 704 |
+
document.getElementById('recentFilesPopup').classList.remove('active');
|
| 705 |
document.body.style.overflow = ''; // Restore scrolling
|
| 706 |
});
|
| 707 |
|
| 708 |
// Close popup when clicking outside content
|
| 709 |
+
this.infoPopup.addEventListener('click', function (e) {
|
| 710 |
+
const infoPopup = document.getElementById('infoPopup')
|
| 711 |
if (e.target === infoPopup) {
|
| 712 |
infoPopup.classList.remove('active');
|
| 713 |
document.body.style.overflow = '';
|
| 714 |
}
|
| 715 |
});
|
| 716 |
|
| 717 |
+
// Close popup when clicking outside content
|
| 718 |
+
this.recentFilesPopup.addEventListener('click', function (e) {
|
| 719 |
+
const recentFilesPopup = document.getElementById('recentFilesPopup')
|
| 720 |
+
if (e.target === recentFilesPopup) {
|
| 721 |
+
recentFilesPopup.classList.remove('active');
|
| 722 |
+
document.body.style.overflow = '';
|
| 723 |
+
}
|
| 724 |
+
});
|
| 725 |
+
|
| 726 |
// Close popup and menu with Escape key
|
| 727 |
document.addEventListener('keydown', (e) => {
|
| 728 |
if (e.key === 'Escape') {
|
| 729 |
+
this.infoPopup.classList.remove('active');
|
| 730 |
document.body.style.overflow = '';
|
| 731 |
+
this.hideAppMenu();
|
| 732 |
}
|
| 733 |
});
|
| 734 |
|
| 735 |
// Close menu when clicking outside
|
| 736 |
document.addEventListener('click', () => {
|
| 737 |
+
this.hideAppMenu();
|
| 738 |
});
|
| 739 |
}
|
| 740 |
|
| 741 |
+
toggleAppMenu() {
|
| 742 |
+
if (this.appMenu.style.display === 'block') {
|
| 743 |
+
this.hideAppMenu();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 744 |
} else {
|
| 745 |
+
this.showAppMenu();
|
| 746 |
}
|
| 747 |
}
|
| 748 |
|
| 749 |
+
showAppMenu() {
|
| 750 |
+
const rect = this.menuButton.getBoundingClientRect();
|
| 751 |
+
|
| 752 |
+
const menuWidth = 150;
|
| 753 |
+
|
| 754 |
+
// Position menu in final location
|
| 755 |
+
this.appMenu.style.top = `${rect.bottom + window.scrollY}px`;
|
| 756 |
+
this.appMenu.style.left = `${rect.right - menuWidth}px`;
|
| 757 |
+
|
| 758 |
+
appMenu.classList.add('active');
|
| 759 |
}
|
| 760 |
|
| 761 |
+
hideAppMenu() {
|
| 762 |
+
this.appMenu.classList.remove('active');
|
| 763 |
}
|
| 764 |
|
| 765 |
async handleMenuAction(action) {
|
| 766 |
+
this.hideAppMenu();
|
| 767 |
|
| 768 |
switch (action) {
|
| 769 |
case 'about':
|
| 770 |
+
this.infoPopup.classList.add('active');
|
| 771 |
document.body.style.overflow = 'hidden';
|
| 772 |
break;
|
| 773 |
case 'recent':
|
|
|
|
| 779 |
async showRecentFilesMenu() {
|
| 780 |
await this.loadRecentFiles();
|
| 781 |
|
| 782 |
+
const recentFilesBody = document.getElementById('recentFilesBody');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 783 |
|
| 784 |
+
// Clear existing content first
|
| 785 |
+
recentFilesBody.innerHTML = '';
|
|
|
|
|
|
|
|
|
|
|
|
|
| 786 |
|
| 787 |
if (this.recentFiles.length === 0) {
|
| 788 |
+
recentFilesBody.innerHTML = `
|
| 789 |
+
<div style="text-align: center; padding: 40px 20px; opacity: 0.8;">
|
| 790 |
+
<div style="font-size: 3rem; margin-bottom: 10px;">🎵</div>
|
| 791 |
+
<p style="margin: 0; font-size: 1.1rem;">No recent files</p>
|
| 792 |
+
<p style="margin: 10px 0 0 0; font-size: 0.9rem; opacity: 0.7;">Files you open will appear here</p>
|
| 793 |
+
</div>
|
| 794 |
+
`;
|
| 795 |
} else {
|
| 796 |
+
let filesHTML = '<div class="recent-files-list" style="display: flex; flex-direction: column; gap: 10px;">';
|
| 797 |
|
| 798 |
for (const file of this.recentFiles) {
|
| 799 |
+
filesHTML += `
|
| 800 |
+
<div class="recent-file-item" data-file-id="${file.id}">
|
| 801 |
+
<div style="flex: 1;">
|
| 802 |
+
<div style="font-weight: bold; font-size: 1rem; margin-bottom: 4px;">${file.fileName}</div>
|
| 803 |
+
<div style="font-size: 0.8rem; opacity: 0.8;">${this.formatFileSize(file.fileSize)}</div>
|
| 804 |
+
</div>
|
| 805 |
+
<button class="remove-recent-file">Remove</button>
|
| 806 |
+
</div>
|
| 807 |
+
`;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 808 |
}
|
| 809 |
|
| 810 |
+
filesHTML += '</div>';
|
| 811 |
+
recentFilesBody.innerHTML = filesHTML;
|
| 812 |
}
|
| 813 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 814 |
// Load file when clicked
|
| 815 |
+
recentFilesBody.querySelectorAll('.recent-file-item').forEach(item => {
|
| 816 |
item.addEventListener('click', async (e) => {
|
| 817 |
if (!e.target.classList.contains('remove-recent-file')) {
|
| 818 |
const fileId = item.dataset.fileId;
|
| 819 |
await this.loadFileFromHandle(fileId);
|
| 820 |
+
this.recentFilesPopup.classList.remove('active');
|
| 821 |
}
|
| 822 |
});
|
| 823 |
});
|
| 824 |
|
| 825 |
// Remove file when remove button clicked
|
| 826 |
+
recentFilesBody.querySelectorAll('.remove-recent-file').forEach(button => {
|
| 827 |
button.addEventListener('click', async (e) => {
|
| 828 |
e.stopPropagation();
|
| 829 |
const fileId = button.closest('.recent-file-item').dataset.fileId;
|
| 830 |
await this.removeFromRecentFiles(fileId);
|
|
|
|
| 831 |
await this.showRecentFilesMenu(); // Refresh the menu
|
| 832 |
});
|
| 833 |
});
|
| 834 |
|
| 835 |
+
this.recentFilesPopup.classList.add('active');
|
| 836 |
+
document.body.style.overflow = 'hidden';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 837 |
}
|
| 838 |
|
| 839 |
async openFileWithFileSystemAPI() {
|
|
|
|
| 868 |
}
|
| 869 |
|
| 870 |
// Verify we still have permission to read the file
|
| 871 |
+
if (await fileRecord.handle.queryPermission({mode: 'read'}) !== 'granted') {
|
| 872 |
+
const permission = await fileRecord.handle.requestPermission({mode: 'read'});
|
| 873 |
if (permission !== 'granted') {
|
| 874 |
throw new Error('Permission denied to read the file');
|
| 875 |
}
|
sw.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
// Use a version that you can update with each release
|
| 2 |
-
const APP_VERSION = '0.1.
|
| 3 |
const CACHE_NAME = `my-pwa-cache-${APP_VERSION}`;
|
| 4 |
|
| 5 |
// List of files to cache
|
|
|
|
| 1 |
// Use a version that you can update with each release
|
| 2 |
+
const APP_VERSION = '0.1.7';
|
| 3 |
const CACHE_NAME = `my-pwa-cache-${APP_VERSION}`;
|
| 4 |
|
| 5 |
// List of files to cache
|