@kerkhoff-ict/solora 2.0.8 → 2.1.1
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/dist/index.css +236 -53
- package/dist/index.js +354 -6
- package/package.json +2 -1
package/dist/index.css
CHANGED
|
@@ -1,22 +1,20 @@
|
|
|
1
1
|
/* src/components/button.css */
|
|
2
|
-
:root {
|
|
3
|
-
--color-primary: #0071e3;
|
|
4
|
-
--color-secondary: #f5f5f5;
|
|
5
|
-
--color-success: #28a745;
|
|
6
|
-
--color-warning: #ffc107;
|
|
7
|
-
--color-danger: #dc3545;
|
|
8
|
-
--color-text-light: #ffffff;
|
|
9
|
-
--color-text-dark: #000000;
|
|
10
|
-
}
|
|
11
2
|
.btn {
|
|
12
3
|
font-weight: 600;
|
|
13
4
|
border: none;
|
|
14
5
|
border-radius: 9999px;
|
|
15
6
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
16
|
-
border-radius: 9999px;
|
|
17
7
|
cursor: pointer;
|
|
18
8
|
transition: background 0.2s, filter 0.2s;
|
|
19
9
|
}
|
|
10
|
+
.btn-rounded {
|
|
11
|
+
padding: 0 !important;
|
|
12
|
+
display: flex;
|
|
13
|
+
align-items: center;
|
|
14
|
+
justify-content: center;
|
|
15
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
16
|
+
cursor: pointer;
|
|
17
|
+
}
|
|
20
18
|
.btn-sm {
|
|
21
19
|
padding: 0.1875rem 1rem;
|
|
22
20
|
font-size: 0.9375rem;
|
|
@@ -115,7 +113,7 @@
|
|
|
115
113
|
[class*="btn-["]:hover {
|
|
116
114
|
filter: brightness(0.85);
|
|
117
115
|
}
|
|
118
|
-
|
|
116
|
+
:root.dark {
|
|
119
117
|
.btn-primary {
|
|
120
118
|
background: #0558be;
|
|
121
119
|
color: var(--color-text-light, #fff);
|
|
@@ -367,7 +365,7 @@
|
|
|
367
365
|
.codeblock pre::-webkit-scrollbar-track {
|
|
368
366
|
background: transparent;
|
|
369
367
|
}
|
|
370
|
-
|
|
368
|
+
:root.dark {
|
|
371
369
|
.codeblock {
|
|
372
370
|
background: #1e1e2f88;
|
|
373
371
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5);
|
|
@@ -474,12 +472,14 @@
|
|
|
474
472
|
min-width: 10rem;
|
|
475
473
|
border-radius: 12px;
|
|
476
474
|
margin-top: 0.5rem;
|
|
477
|
-
|
|
475
|
+
overflow: hidden;
|
|
476
|
+
overflow-y: auto;
|
|
477
|
+
background: transparent;
|
|
478
|
+
border: 1px solid rgba(255, 255, 255, 0.3);
|
|
478
479
|
backdrop-filter: blur(12px);
|
|
479
480
|
-webkit-backdrop-filter: blur(12px);
|
|
480
|
-
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.
|
|
481
|
+
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.12);
|
|
481
482
|
max-height: 15rem;
|
|
482
|
-
overflow-y: auto;
|
|
483
483
|
scrollbar-width: thin;
|
|
484
484
|
scrollbar-color: rgba(0, 0, 0, 0.2) transparent;
|
|
485
485
|
opacity: 0;
|
|
@@ -536,44 +536,227 @@
|
|
|
536
536
|
color: rgba(0, 0, 0, 0.6);
|
|
537
537
|
cursor: default;
|
|
538
538
|
}
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
.
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
.
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
.
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
.
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
.
|
|
575
|
-
background: rgba(255, 255, 255, 0.2);
|
|
576
|
-
}
|
|
539
|
+
:root.dark .dropdown-btn {
|
|
540
|
+
background: #1c1c1e;
|
|
541
|
+
color: #f0f0f0;
|
|
542
|
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
543
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.5);
|
|
544
|
+
}
|
|
545
|
+
:root.dark .dropdown-btn:hover {
|
|
546
|
+
background: rgba(255, 255, 255, 0.05);
|
|
547
|
+
}
|
|
548
|
+
:root.dark .dropdown-content {
|
|
549
|
+
background: transparent;
|
|
550
|
+
backdrop-filter: blur(12px);
|
|
551
|
+
-webkit-backdrop-filter: blur(12px);
|
|
552
|
+
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.6);
|
|
553
|
+
}
|
|
554
|
+
:root.dark .dropdown-item {
|
|
555
|
+
color: #f0f0f0;
|
|
556
|
+
}
|
|
557
|
+
:root.dark .dropdown-item:hover {
|
|
558
|
+
background: rgba(255, 255, 255, 0.08);
|
|
559
|
+
}
|
|
560
|
+
:root.dark .dropdown-item.active {
|
|
561
|
+
background: rgba(255, 255, 255, 0.12);
|
|
562
|
+
}
|
|
563
|
+
:root.dark .dropdown-divider {
|
|
564
|
+
background: rgba(255, 255, 255, 0.2);
|
|
565
|
+
}
|
|
566
|
+
:root.dark .dropdown-item[aria-disabled=true],
|
|
567
|
+
:root.dark .dropdown-item.placeholder {
|
|
568
|
+
color: rgba(255, 255, 255, 0.4);
|
|
569
|
+
}
|
|
570
|
+
:root.dark .dropdown-label {
|
|
571
|
+
color: rgba(255, 255, 255, 0.6);
|
|
572
|
+
}
|
|
573
|
+
:root.dark .dropdown-content::-webkit-scrollbar-thumb {
|
|
574
|
+
background: rgba(255, 255, 255, 0.2);
|
|
577
575
|
}
|
|
578
576
|
|
|
577
|
+
/* src/components/input.css */
|
|
578
|
+
.sol-input-group {
|
|
579
|
+
display: flex;
|
|
580
|
+
flex-direction: column;
|
|
581
|
+
gap: 0.4rem;
|
|
582
|
+
font-family:
|
|
583
|
+
-apple-system,
|
|
584
|
+
BlinkMacSystemFont,
|
|
585
|
+
"Segoe UI",
|
|
586
|
+
Roboto,
|
|
587
|
+
Helvetica,
|
|
588
|
+
Arial,
|
|
589
|
+
sans-serif;
|
|
590
|
+
width: 100%;
|
|
591
|
+
}
|
|
592
|
+
.sol-label {
|
|
593
|
+
font-size: 0.85rem;
|
|
594
|
+
font-weight: 500;
|
|
595
|
+
color: var(--color-text-dark, #000);
|
|
596
|
+
opacity: 0.6;
|
|
597
|
+
margin-left: 0.2rem;
|
|
598
|
+
}
|
|
599
|
+
.sol-input {
|
|
600
|
+
appearance: none;
|
|
601
|
+
-webkit-appearance: none;
|
|
602
|
+
width: 100%;
|
|
603
|
+
padding: 0.3rem 0.4rem;
|
|
604
|
+
font-size: 0.95rem;
|
|
605
|
+
border-radius: 12px;
|
|
606
|
+
border: 1px solid rgba(0, 0, 0, 0.1);
|
|
607
|
+
background: var(--color-bg, #fefefe);
|
|
608
|
+
color: var(--color-text-dark, #000);
|
|
609
|
+
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.05), 0 2px 8px rgba(0, 0, 0, 0.05);
|
|
610
|
+
transition: all 0.2s cubic-bezier(0.25, 0.8, 0.25, 1);
|
|
611
|
+
outline: none;
|
|
612
|
+
}
|
|
613
|
+
.sol-input::placeholder {
|
|
614
|
+
color: var(--color-text-dark, #000);
|
|
615
|
+
opacity: 0.3;
|
|
616
|
+
}
|
|
617
|
+
.sol-input:hover {
|
|
618
|
+
border-color: rgba(0, 0, 0, 0.2);
|
|
619
|
+
background: var(--color-bg-hover, #ffffff);
|
|
620
|
+
}
|
|
621
|
+
.sol-input:focus {
|
|
622
|
+
border-color: var(--color-primary, #0071e3);
|
|
623
|
+
box-shadow: 0 0 0 4px var(--color-focus-glow, rgba(0, 113, 227, 0.15)), 0 2px 8px rgba(0, 0, 0, 0.05);
|
|
624
|
+
background: var(--color-bg-hover, #ffffff);
|
|
625
|
+
}
|
|
626
|
+
.sol-input:disabled {
|
|
627
|
+
background: var(--color-secondary, #f5f5f5);
|
|
628
|
+
color: var(--color-text-dark, #000);
|
|
629
|
+
opacity: 0.5;
|
|
630
|
+
cursor: not-allowed;
|
|
631
|
+
box-shadow: none;
|
|
632
|
+
}
|
|
633
|
+
.sol-input-error {
|
|
634
|
+
border-color: var(--color-danger, #dc3545) !important;
|
|
635
|
+
}
|
|
636
|
+
.sol-input-error:focus {
|
|
637
|
+
box-shadow: 0 0 0 4px var(--color-error-glow, rgba(220, 53, 69, 0.15)) !important;
|
|
638
|
+
}
|
|
639
|
+
:root.dark .sol-label {
|
|
640
|
+
color: var(--color-text-light, #fff);
|
|
641
|
+
opacity: 0.6;
|
|
642
|
+
}
|
|
643
|
+
:root.dark .sol-input {
|
|
644
|
+
background: rgba(28, 28, 30, 0.8);
|
|
645
|
+
color: var(--color-text-light, #fff);
|
|
646
|
+
border: 1px solid rgba(255, 255, 255, 0.15);
|
|
647
|
+
backdrop-filter: blur(12px);
|
|
648
|
+
-webkit-backdrop-filter: blur(12px);
|
|
649
|
+
box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.05), 0 4px 12px rgba(0, 0, 0, 0.4);
|
|
650
|
+
}
|
|
651
|
+
:root.dark .sol-input::placeholder {
|
|
652
|
+
color: var(--color-text-light, #fff);
|
|
653
|
+
opacity: 0.3;
|
|
654
|
+
}
|
|
655
|
+
:root.dark .sol-input:hover {
|
|
656
|
+
background: rgba(44, 44, 46, 0.9);
|
|
657
|
+
border-color: rgba(255, 255, 255, 0.25);
|
|
658
|
+
}
|
|
659
|
+
:root.dark .sol-input:focus {
|
|
660
|
+
background: rgba(44, 44, 46, 1);
|
|
661
|
+
border-color: var(--color-primary-dark, #0a84ff);
|
|
662
|
+
box-shadow: 0 0 0 4px var(--color-focus-glow-dark, rgba(10, 132, 255, 0.2)), 0 4px 12px rgba(0, 0, 0, 0.5);
|
|
663
|
+
}
|
|
664
|
+
:root.dark .sol-input-error {
|
|
665
|
+
border-color: var(--color-danger, #ff453a) !important;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
/* src/components/contextMenu.css */
|
|
669
|
+
.sol-context-menu {
|
|
670
|
+
position: fixed;
|
|
671
|
+
display: none;
|
|
672
|
+
z-index: 9999;
|
|
673
|
+
min-width: 180px;
|
|
674
|
+
background: transparent;
|
|
675
|
+
backdrop-filter: blur(12px) saturate(180%);
|
|
676
|
+
-webkit-backdrop-filter: blur(12px) saturate(180%);
|
|
677
|
+
border: 1px solid rgba(0, 0, 0, 0.1);
|
|
678
|
+
border-radius: 12px;
|
|
679
|
+
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15);
|
|
680
|
+
padding: 5px;
|
|
681
|
+
font-family:
|
|
682
|
+
-apple-system,
|
|
683
|
+
BlinkMacSystemFont,
|
|
684
|
+
"Segoe UI",
|
|
685
|
+
Roboto,
|
|
686
|
+
Helvetica,
|
|
687
|
+
Arial,
|
|
688
|
+
sans-serif;
|
|
689
|
+
user-select: none;
|
|
690
|
+
opacity: 0;
|
|
691
|
+
transform: translateY(-10px) scale(0.95);
|
|
692
|
+
transition: opacity 0.15s ease, transform 0.15s cubic-bezier(0.25, 0.8, 0.25, 1);
|
|
693
|
+
}
|
|
694
|
+
.sol-context-menu.visible {
|
|
695
|
+
display: block;
|
|
696
|
+
opacity: 1;
|
|
697
|
+
transform: translateY(0) scale(1);
|
|
698
|
+
}
|
|
699
|
+
.sol-menu-item {
|
|
700
|
+
display: flex;
|
|
701
|
+
align-items: center;
|
|
702
|
+
justify-content: space-between;
|
|
703
|
+
padding: 0.2rem 0.3rem;
|
|
704
|
+
font-size: 0.85rem;
|
|
705
|
+
color: var(--color-text-dark, #000);
|
|
706
|
+
border-radius: 8px;
|
|
707
|
+
cursor: pointer;
|
|
708
|
+
transition: background 0.1s, color 0.1s;
|
|
709
|
+
}
|
|
710
|
+
.sol-menu-item:hover {
|
|
711
|
+
background: var(--color-primary, #007aff);
|
|
712
|
+
color: #fff;
|
|
713
|
+
}
|
|
714
|
+
.sol-menu-shortcut {
|
|
715
|
+
font-size: 0.75rem;
|
|
716
|
+
opacity: 0.5;
|
|
717
|
+
margin-left: 20px;
|
|
718
|
+
}
|
|
719
|
+
.sol-menu-item:hover .sol-menu-shortcut {
|
|
720
|
+
color: #fff;
|
|
721
|
+
opacity: 0.8;
|
|
722
|
+
}
|
|
723
|
+
.sol-menu-divider {
|
|
724
|
+
height: 1px;
|
|
725
|
+
background: rgba(0, 0, 0, 0.08);
|
|
726
|
+
margin: 4px 0;
|
|
727
|
+
}
|
|
728
|
+
:root.dark .sol-context-menu {
|
|
729
|
+
background: rgba(28, 28, 30, 0.8);
|
|
730
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
731
|
+
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
|
|
732
|
+
}
|
|
733
|
+
:root.dark .sol-menu-item {
|
|
734
|
+
color: var(--color-text-light, #f0f0f0);
|
|
735
|
+
}
|
|
736
|
+
:root.dark .sol-menu-divider {
|
|
737
|
+
background: rgba(255, 255, 255, 0.1);
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
/* src/components/darkToggle.css */
|
|
741
|
+
|
|
579
742
|
/* src/index.css */
|
|
743
|
+
:root {
|
|
744
|
+
--font-body:
|
|
745
|
+
-apple-system,
|
|
746
|
+
BlinkMacSystemFont,
|
|
747
|
+
"SF Pro Text",
|
|
748
|
+
"Helvetica Neue",
|
|
749
|
+
Arial,
|
|
750
|
+
sans-serif;
|
|
751
|
+
--font-display:
|
|
752
|
+
"SF Pro Display",
|
|
753
|
+
-apple-system,
|
|
754
|
+
BlinkMacSystemFont,
|
|
755
|
+
"Helvetica Neue",
|
|
756
|
+
sans-serif;
|
|
757
|
+
--font-mono:
|
|
758
|
+
"SF Mono",
|
|
759
|
+
"Menlo",
|
|
760
|
+
"Consolas",
|
|
761
|
+
monospace;
|
|
762
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -1870,18 +1870,20 @@ function initDropdowns() {
|
|
|
1870
1870
|
};
|
|
1871
1871
|
const initialItem = content.querySelector(".dropdown-item.active") || content.querySelector('.dropdown-item:not([aria-disabled="true"])');
|
|
1872
1872
|
if (initialItem) setValue(initialItem);
|
|
1873
|
+
const openDropdown = () => drop.classList.add("open");
|
|
1874
|
+
const closeDropdown = () => drop.classList.remove("open");
|
|
1873
1875
|
btn.addEventListener("click", (e) => {
|
|
1874
1876
|
if (drop.getAttribute("aria-disabled") === "true") return;
|
|
1875
1877
|
e.stopPropagation();
|
|
1876
1878
|
drop.classList.toggle("open");
|
|
1877
1879
|
});
|
|
1878
1880
|
document.addEventListener("click", (e) => {
|
|
1879
|
-
if (!drop.contains(e.target))
|
|
1881
|
+
if (!drop.contains(e.target)) closeDropdown();
|
|
1880
1882
|
});
|
|
1881
1883
|
content.querySelectorAll(".dropdown-item").forEach((item) => {
|
|
1882
1884
|
item.addEventListener("click", () => {
|
|
1883
1885
|
setValue(item);
|
|
1884
|
-
|
|
1886
|
+
closeDropdown();
|
|
1885
1887
|
});
|
|
1886
1888
|
});
|
|
1887
1889
|
let items = Array.from(content.querySelectorAll('.dropdown-item:not([aria-disabled="true"])'));
|
|
@@ -1890,7 +1892,7 @@ function initDropdowns() {
|
|
|
1890
1892
|
if (drop.getAttribute("aria-disabled") === "true") return;
|
|
1891
1893
|
if (!["ArrowDown", "ArrowUp", "Enter", "Escape"].includes(e.key)) return;
|
|
1892
1894
|
e.preventDefault();
|
|
1893
|
-
|
|
1895
|
+
openDropdown();
|
|
1894
1896
|
if (e.key === "ArrowDown") {
|
|
1895
1897
|
index = (index + 1) % items.length;
|
|
1896
1898
|
items.forEach((i) => i.classList.remove("active"));
|
|
@@ -1905,26 +1907,372 @@ function initDropdowns() {
|
|
|
1905
1907
|
}
|
|
1906
1908
|
if (e.key === "Enter") {
|
|
1907
1909
|
setValue(items[index]);
|
|
1908
|
-
|
|
1910
|
+
closeDropdown();
|
|
1909
1911
|
}
|
|
1910
1912
|
if (e.key === "Escape") {
|
|
1911
|
-
|
|
1913
|
+
closeDropdown();
|
|
1912
1914
|
}
|
|
1913
1915
|
});
|
|
1914
1916
|
btn.setAttribute("tabindex", "0");
|
|
1915
1917
|
});
|
|
1916
1918
|
}
|
|
1917
1919
|
|
|
1920
|
+
// src/components/contextMenu.js
|
|
1921
|
+
function initContextMenu() {
|
|
1922
|
+
let menu = document.querySelector(".sol-context-menu");
|
|
1923
|
+
if (!menu) {
|
|
1924
|
+
menu = document.createElement("div");
|
|
1925
|
+
menu.className = "sol-context-menu";
|
|
1926
|
+
document.body.appendChild(menu);
|
|
1927
|
+
}
|
|
1928
|
+
let contextTarget = null;
|
|
1929
|
+
const showMenu = (e) => {
|
|
1930
|
+
e.preventDefault();
|
|
1931
|
+
contextTarget = e.target;
|
|
1932
|
+
const selection = window.getSelection().toString().trim();
|
|
1933
|
+
const link = e.target.closest("a");
|
|
1934
|
+
const img = e.target.closest("img");
|
|
1935
|
+
const input = e.target.closest("input, textarea, [contenteditable]");
|
|
1936
|
+
const isEditable = input || e.target.isContentEditable;
|
|
1937
|
+
const isTextInput = input && (input.type === "text" || input.type === "search" || input.type === "email" || input.type === "password" || input.tagName === "TEXTAREA" || input.isContentEditable);
|
|
1938
|
+
let menuHtml = "";
|
|
1939
|
+
if (selection.length > 0) {
|
|
1940
|
+
menuHtml += `
|
|
1941
|
+
<div class="sol-menu-label">Selectie</div>
|
|
1942
|
+
<div class="sol-menu-item" data-action="copy">
|
|
1943
|
+
Kopieer <span class="sol-menu-shortcut">\u2318C</span>
|
|
1944
|
+
</div>
|
|
1945
|
+
${isEditable ? `
|
|
1946
|
+
<div class="sol-menu-item" data-action="cut">
|
|
1947
|
+
Knippen <span class="sol-menu-shortcut">\u2318X</span>
|
|
1948
|
+
</div>` : ""}
|
|
1949
|
+
<div class="sol-menu-item" data-action="search-google">
|
|
1950
|
+
Zoek op Google: <em>"${selection.slice(0, 20)}${selection.length > 20 ? "\u2026" : ""}"</em>
|
|
1951
|
+
</div>
|
|
1952
|
+
<div class="sol-menu-item" data-action="search-wiki">
|
|
1953
|
+
Zoek op Wikipedia\u2026
|
|
1954
|
+
</div>
|
|
1955
|
+
<div class="sol-menu-item" data-action="translate">
|
|
1956
|
+
Vertaal selectie\u2026
|
|
1957
|
+
</div>
|
|
1958
|
+
<div class="sol-menu-divider"></div>
|
|
1959
|
+
`;
|
|
1960
|
+
}
|
|
1961
|
+
if (isTextInput) {
|
|
1962
|
+
menuHtml += `
|
|
1963
|
+
<div class="sol-menu-label">Tekstveld</div>
|
|
1964
|
+
${selection.length > 0 ? `
|
|
1965
|
+
<div class="sol-menu-item" data-action="cut">
|
|
1966
|
+
Knippen <span class="sol-menu-shortcut">\u2318X</span>
|
|
1967
|
+
</div>
|
|
1968
|
+
<div class="sol-menu-item" data-action="copy">
|
|
1969
|
+
Kopieer <span class="sol-menu-shortcut">\u2318C</span>
|
|
1970
|
+
</div>` : ""}
|
|
1971
|
+
<div class="sol-menu-item" data-action="paste">
|
|
1972
|
+
Plakken <span class="sol-menu-shortcut">\u2318V</span>
|
|
1973
|
+
</div>
|
|
1974
|
+
<div class="sol-menu-item" data-action="select-all">
|
|
1975
|
+
Alles selecteren <span class="sol-menu-shortcut">\u2318A</span>
|
|
1976
|
+
</div>
|
|
1977
|
+
<div class="sol-menu-item" data-action="clear-field">
|
|
1978
|
+
Veld wissen
|
|
1979
|
+
</div>
|
|
1980
|
+
<div class="sol-menu-divider"></div>
|
|
1981
|
+
`;
|
|
1982
|
+
}
|
|
1983
|
+
if (img) {
|
|
1984
|
+
menuHtml += `
|
|
1985
|
+
<div class="sol-menu-label">Afbeelding</div>
|
|
1986
|
+
<div class="sol-menu-item" data-action="open-img" data-url="${img.src}">
|
|
1987
|
+
Afbeelding openen in nieuw tabblad
|
|
1988
|
+
</div>
|
|
1989
|
+
<div class="sol-menu-item" data-action="copy-img-url" data-url="${img.src}">
|
|
1990
|
+
Kopieer afbeeldings-URL
|
|
1991
|
+
</div>
|
|
1992
|
+
<div class="sol-menu-item" data-action="download-img" data-url="${img.src}" data-filename="${img.alt || "afbeelding"}">
|
|
1993
|
+
Afbeelding opslaan\u2026
|
|
1994
|
+
</div>
|
|
1995
|
+
${img.alt ? `
|
|
1996
|
+
<div class="sol-menu-item" data-action="copy-alt" data-text="${img.alt}">
|
|
1997
|
+
Kopieer alt-tekst
|
|
1998
|
+
</div>` : ""}
|
|
1999
|
+
<div class="sol-menu-divider"></div>
|
|
2000
|
+
`;
|
|
2001
|
+
}
|
|
2002
|
+
if (link) {
|
|
2003
|
+
menuHtml += `
|
|
2004
|
+
<div class="sol-menu-label">Link</div>
|
|
2005
|
+
<div class="sol-menu-item" data-action="open-tab" data-url="${link.href}">
|
|
2006
|
+
Open in nieuw tabblad
|
|
2007
|
+
</div>
|
|
2008
|
+
<div class="sol-menu-item" data-action="open-window" data-url="${link.href}">
|
|
2009
|
+
Open in nieuw venster
|
|
2010
|
+
</div>
|
|
2011
|
+
<div class="sol-menu-item" data-action="copy-link" data-url="${link.href}">
|
|
2012
|
+
Kopieer link-adres
|
|
2013
|
+
</div>
|
|
2014
|
+
<div class="sol-menu-divider"></div>
|
|
2015
|
+
`;
|
|
2016
|
+
}
|
|
2017
|
+
menuHtml += `
|
|
2018
|
+
<div class="sol-menu-label">Navigatie</div>
|
|
2019
|
+
<div class="sol-menu-item${!history.length || history.state === null ? " disabled" : ""}" data-action="go-back">
|
|
2020
|
+
\u2190 Vorige pagina
|
|
2021
|
+
</div>
|
|
2022
|
+
<div class="sol-menu-item" data-action="go-forward">
|
|
2023
|
+
\u2192 Volgende pagina
|
|
2024
|
+
</div>
|
|
2025
|
+
<div class="sol-menu-item" data-action="reload">
|
|
2026
|
+
Vernieuwen <span class="sol-menu-shortcut">\u2318R</span>
|
|
2027
|
+
</div>
|
|
2028
|
+
<div class="sol-menu-item" data-action="hard-reload">
|
|
2029
|
+
Geforceerd vernieuwen <span class="sol-menu-shortcut">\u21E7\u2318R</span>
|
|
2030
|
+
</div>
|
|
2031
|
+
<div class="sol-menu-divider"></div>
|
|
2032
|
+
`;
|
|
2033
|
+
menuHtml += `
|
|
2034
|
+
<div class="sol-menu-label">Pagina</div>
|
|
2035
|
+
<div class="sol-menu-item" data-action="copy-page-url">
|
|
2036
|
+
Kopieer pagina-URL
|
|
2037
|
+
</div>
|
|
2038
|
+
<div class="sol-menu-item" data-action="view-source">
|
|
2039
|
+
Bekijk paginabron <span class="sol-menu-shortcut">\u2318U</span>
|
|
2040
|
+
</div>
|
|
2041
|
+
<div class="sol-menu-item" data-action="print">
|
|
2042
|
+
Printen <span class="sol-menu-shortcut">\u2318P</span>
|
|
2043
|
+
</div>
|
|
2044
|
+
<div class="sol-menu-item" data-action="save-page">
|
|
2045
|
+
Pagina opslaan <span class="sol-menu-shortcut">\u2318S</span>
|
|
2046
|
+
</div>
|
|
2047
|
+
<div class="sol-menu-item" data-action="scroll-top">
|
|
2048
|
+
Naar boven scrollen
|
|
2049
|
+
</div>
|
|
2050
|
+
<div class="sol-menu-divider"></div>
|
|
2051
|
+
`;
|
|
2052
|
+
menuHtml += `
|
|
2053
|
+
<div class="sol-menu-label">Ontwikkelaar</div>
|
|
2054
|
+
<div class="sol-menu-item" data-action="inspect">
|
|
2055
|
+
Inspecteer element <span class="sol-menu-shortcut">\u2325\u2318I</span>
|
|
2056
|
+
</div>
|
|
2057
|
+
<div class="sol-menu-item" data-action="copy-selector">
|
|
2058
|
+
Kopieer CSS-selector
|
|
2059
|
+
</div>
|
|
2060
|
+
<div class="sol-menu-item" data-action="log-element">
|
|
2061
|
+
Log element in console
|
|
2062
|
+
</div>
|
|
2063
|
+
`;
|
|
2064
|
+
menu.innerHTML = menuHtml;
|
|
2065
|
+
menu.style.display = "block";
|
|
2066
|
+
let posX = e.clientX;
|
|
2067
|
+
let posY = e.clientY;
|
|
2068
|
+
const menuWidth = menu.offsetWidth;
|
|
2069
|
+
const menuHeight = menu.offsetHeight;
|
|
2070
|
+
if (posX + menuWidth > window.innerWidth) posX -= menuWidth;
|
|
2071
|
+
if (posY + menuHeight > window.innerHeight) posY -= menuHeight;
|
|
2072
|
+
menu.style.left = `${posX}px`;
|
|
2073
|
+
menu.style.top = `${posY}px`;
|
|
2074
|
+
requestAnimationFrame(() => menu.classList.add("visible"));
|
|
2075
|
+
};
|
|
2076
|
+
const hideMenu = () => {
|
|
2077
|
+
menu.classList.remove("visible");
|
|
2078
|
+
setTimeout(() => {
|
|
2079
|
+
if (!menu.classList.contains("visible")) menu.style.display = "none";
|
|
2080
|
+
}, 150);
|
|
2081
|
+
};
|
|
2082
|
+
const getCssSelector = (el) => {
|
|
2083
|
+
if (!el) return "";
|
|
2084
|
+
const parts = [];
|
|
2085
|
+
while (el && el.nodeType === Node.ELEMENT_NODE) {
|
|
2086
|
+
let selector = el.nodeName.toLowerCase();
|
|
2087
|
+
if (el.id) {
|
|
2088
|
+
selector += `#${el.id}`;
|
|
2089
|
+
parts.unshift(selector);
|
|
2090
|
+
break;
|
|
2091
|
+
}
|
|
2092
|
+
if (el.className) {
|
|
2093
|
+
selector += "." + [...el.classList].join(".");
|
|
2094
|
+
}
|
|
2095
|
+
const siblings = el.parentNode ? [...el.parentNode.children].filter((s) => s.nodeName === el.nodeName) : [];
|
|
2096
|
+
if (siblings.length > 1) {
|
|
2097
|
+
selector += `:nth-of-type(${siblings.indexOf(el) + 1})`;
|
|
2098
|
+
}
|
|
2099
|
+
parts.unshift(selector);
|
|
2100
|
+
el = el.parentNode;
|
|
2101
|
+
}
|
|
2102
|
+
return parts.join(" > ");
|
|
2103
|
+
};
|
|
2104
|
+
document.addEventListener("contextmenu", showMenu);
|
|
2105
|
+
document.addEventListener("click", hideMenu);
|
|
2106
|
+
window.addEventListener("scroll", hideMenu);
|
|
2107
|
+
document.addEventListener("keydown", (e) => {
|
|
2108
|
+
if (e.key === "Escape") hideMenu();
|
|
2109
|
+
});
|
|
2110
|
+
menu.addEventListener("click", (e) => {
|
|
2111
|
+
const item = e.target.closest(".sol-menu-item");
|
|
2112
|
+
if (!item || item.classList.contains("disabled")) return;
|
|
2113
|
+
const action = item.dataset.action;
|
|
2114
|
+
const url = item.dataset.url;
|
|
2115
|
+
const text = item.dataset.text;
|
|
2116
|
+
const filename = item.dataset.filename;
|
|
2117
|
+
const sel = window.getSelection().toString().trim();
|
|
2118
|
+
switch (action) {
|
|
2119
|
+
// Tekst
|
|
2120
|
+
case "copy":
|
|
2121
|
+
document.execCommand("copy");
|
|
2122
|
+
break;
|
|
2123
|
+
case "cut":
|
|
2124
|
+
document.execCommand("cut");
|
|
2125
|
+
break;
|
|
2126
|
+
case "paste":
|
|
2127
|
+
navigator.clipboard.readText().then((t) => document.execCommand("insertText", false, t));
|
|
2128
|
+
break;
|
|
2129
|
+
case "select-all":
|
|
2130
|
+
document.execCommand("selectAll");
|
|
2131
|
+
break;
|
|
2132
|
+
case "clear-field":
|
|
2133
|
+
if (contextTarget?.closest("input, textarea")) contextTarget.closest("input, textarea").value = "";
|
|
2134
|
+
break;
|
|
2135
|
+
// Zoeken & vertalen
|
|
2136
|
+
case "search-google":
|
|
2137
|
+
window.open(`https://www.google.com/search?q=${encodeURIComponent(sel)}`, "_blank");
|
|
2138
|
+
break;
|
|
2139
|
+
case "search-wiki":
|
|
2140
|
+
window.open(`https://nl.wikipedia.org/wiki/Special:Search?search=${encodeURIComponent(sel)}`, "_blank");
|
|
2141
|
+
break;
|
|
2142
|
+
case "translate":
|
|
2143
|
+
window.open(`https://translate.google.com/?sl=auto&tl=nl&text=${encodeURIComponent(sel)}`, "_blank");
|
|
2144
|
+
break;
|
|
2145
|
+
// Afbeelding
|
|
2146
|
+
case "open-img":
|
|
2147
|
+
window.open(url, "_blank");
|
|
2148
|
+
break;
|
|
2149
|
+
case "copy-img-url":
|
|
2150
|
+
navigator.clipboard.writeText(url);
|
|
2151
|
+
break;
|
|
2152
|
+
case "copy-alt":
|
|
2153
|
+
navigator.clipboard.writeText(text);
|
|
2154
|
+
break;
|
|
2155
|
+
case "download-img": {
|
|
2156
|
+
const a = document.createElement("a");
|
|
2157
|
+
a.href = url;
|
|
2158
|
+
a.download = filename || "afbeelding";
|
|
2159
|
+
a.click();
|
|
2160
|
+
break;
|
|
2161
|
+
}
|
|
2162
|
+
// Link
|
|
2163
|
+
case "open-tab":
|
|
2164
|
+
window.open(url, "_blank");
|
|
2165
|
+
break;
|
|
2166
|
+
case "open-window":
|
|
2167
|
+
window.open(url, "_blank", "noopener,noreferrer");
|
|
2168
|
+
break;
|
|
2169
|
+
case "copy-link":
|
|
2170
|
+
navigator.clipboard.writeText(url);
|
|
2171
|
+
break;
|
|
2172
|
+
// Navigatie
|
|
2173
|
+
case "go-back":
|
|
2174
|
+
history.back();
|
|
2175
|
+
break;
|
|
2176
|
+
case "go-forward":
|
|
2177
|
+
history.forward();
|
|
2178
|
+
break;
|
|
2179
|
+
case "reload":
|
|
2180
|
+
location.reload();
|
|
2181
|
+
break;
|
|
2182
|
+
case "hard-reload":
|
|
2183
|
+
location.href = location.href;
|
|
2184
|
+
break;
|
|
2185
|
+
// Pagina
|
|
2186
|
+
case "copy-page-url":
|
|
2187
|
+
navigator.clipboard.writeText(location.href);
|
|
2188
|
+
break;
|
|
2189
|
+
case "view-source":
|
|
2190
|
+
window.open(`view-source:${location.href}`, "_blank");
|
|
2191
|
+
break;
|
|
2192
|
+
case "print":
|
|
2193
|
+
window.print();
|
|
2194
|
+
break;
|
|
2195
|
+
case "save-page":
|
|
2196
|
+
document.execCommand("SaveAs");
|
|
2197
|
+
break;
|
|
2198
|
+
case "scroll-top":
|
|
2199
|
+
window.scrollTo({ top: 0, behavior: "smooth" });
|
|
2200
|
+
break;
|
|
2201
|
+
// Ontwikkelaar
|
|
2202
|
+
case "inspect":
|
|
2203
|
+
console.log("%c[Inspecteer element]", "color:#6c63ff;font-weight:bold", contextTarget);
|
|
2204
|
+
break;
|
|
2205
|
+
case "copy-selector":
|
|
2206
|
+
navigator.clipboard.writeText(getCssSelector(contextTarget));
|
|
2207
|
+
break;
|
|
2208
|
+
case "log-element":
|
|
2209
|
+
console.log("%c[Sol Context Menu] Geselecteerd element:", "color:#6c63ff", contextTarget);
|
|
2210
|
+
console.table({
|
|
2211
|
+
tag: contextTarget?.tagName,
|
|
2212
|
+
id: contextTarget?.id,
|
|
2213
|
+
classes: contextTarget?.className,
|
|
2214
|
+
selector: getCssSelector(contextTarget),
|
|
2215
|
+
innerText: contextTarget?.innerText?.slice(0, 80)
|
|
2216
|
+
});
|
|
2217
|
+
break;
|
|
2218
|
+
}
|
|
2219
|
+
hideMenu();
|
|
2220
|
+
});
|
|
2221
|
+
}
|
|
2222
|
+
|
|
2223
|
+
// src/components/darkToggle.js
|
|
2224
|
+
function initThemeToggle(elementSelector = ".sol-theme-toggle") {
|
|
2225
|
+
const html = document.documentElement;
|
|
2226
|
+
const toggles = document.querySelectorAll(elementSelector);
|
|
2227
|
+
const STORAGE_KEY = "solora-theme";
|
|
2228
|
+
const applyTheme = (theme) => {
|
|
2229
|
+
if (theme === "dark") {
|
|
2230
|
+
html.classList.add("dark");
|
|
2231
|
+
html.classList.remove("light");
|
|
2232
|
+
} else {
|
|
2233
|
+
html.classList.add("light");
|
|
2234
|
+
html.classList.remove("dark");
|
|
2235
|
+
}
|
|
2236
|
+
toggles.forEach((btn) => {
|
|
2237
|
+
btn.innerHTML = `<span>${theme === "dark" ? "\u2600\uFE0F" : "\u{1F319}"}</span>`;
|
|
2238
|
+
btn.setAttribute("aria-label", `Switch to ${theme === "dark" ? "light" : "dark"} mode`);
|
|
2239
|
+
});
|
|
2240
|
+
localStorage.setItem(STORAGE_KEY, theme);
|
|
2241
|
+
};
|
|
2242
|
+
const getInitialTheme = () => {
|
|
2243
|
+
const saved = localStorage.getItem(STORAGE_KEY);
|
|
2244
|
+
if (saved) return saved;
|
|
2245
|
+
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
2246
|
+
return prefersDark ? "dark" : "light";
|
|
2247
|
+
};
|
|
2248
|
+
applyTheme(getInitialTheme());
|
|
2249
|
+
toggles.forEach((btn) => {
|
|
2250
|
+
btn.addEventListener("click", () => {
|
|
2251
|
+
const isDark = html.classList.contains("dark");
|
|
2252
|
+
applyTheme(isDark ? "light" : "dark");
|
|
2253
|
+
});
|
|
2254
|
+
});
|
|
2255
|
+
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", (e) => {
|
|
2256
|
+
if (!localStorage.getItem(STORAGE_KEY)) {
|
|
2257
|
+
applyTheme(e.matches ? "dark" : "light");
|
|
2258
|
+
}
|
|
2259
|
+
});
|
|
2260
|
+
}
|
|
2261
|
+
|
|
1918
2262
|
// src/index.js
|
|
1919
2263
|
if (typeof window !== "undefined") {
|
|
1920
2264
|
document.addEventListener("DOMContentLoaded", () => {
|
|
1921
2265
|
initCodeblocks();
|
|
1922
2266
|
initDropdowns();
|
|
2267
|
+
initContextMenu();
|
|
2268
|
+
initThemeToggle();
|
|
1923
2269
|
});
|
|
1924
2270
|
}
|
|
1925
2271
|
export {
|
|
1926
2272
|
initCodeblocks,
|
|
1927
|
-
|
|
2273
|
+
initContextMenu,
|
|
2274
|
+
initDropdowns,
|
|
2275
|
+
initThemeToggle
|
|
1928
2276
|
};
|
|
1929
2277
|
/*! Bundled license information:
|
|
1930
2278
|
|