@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 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
- @media (prefers-color-scheme: dark) {
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
- @media (prefers-color-scheme: dark) {
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
- background: rgba(255, 255, 255, 0.8);
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.15);
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
- @media (prefers-color-scheme: dark) {
540
- .dropdown-btn {
541
- background: #1c1c1e;
542
- color: #f0f0f0;
543
- border: 1px solid rgba(255, 255, 255, 0.2);
544
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.5);
545
- }
546
- .dropdown-btn:hover {
547
- background: rgba(255, 255, 255, 0.05);
548
- }
549
- .dropdown-content {
550
- background: rgba(28, 28, 30, 0.8);
551
- backdrop-filter: blur(12px);
552
- -webkit-backdrop-filter: blur(12px);
553
- box-shadow: 0 12px 32px rgba(0, 0, 0, 0.6);
554
- }
555
- .dropdown-item {
556
- color: #f0f0f0;
557
- }
558
- .dropdown-item:hover {
559
- background: rgba(255, 255, 255, 0.08);
560
- }
561
- .dropdown-item.active {
562
- background: rgba(255, 255, 255, 0.12);
563
- }
564
- .dropdown-divider {
565
- background: rgba(255, 255, 255, 0.2);
566
- }
567
- .dropdown-item[aria-disabled=true],
568
- .dropdown-item.placeholder {
569
- color: rgba(255, 255, 255, 0.4);
570
- }
571
- .dropdown-label {
572
- color: rgba(255, 255, 255, 0.6);
573
- }
574
- .dropdown-content::-webkit-scrollbar-thumb {
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)) drop.classList.remove("open");
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
- drop.classList.remove("open");
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
- drop.classList.add("open");
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
- drop.classList.remove("open");
1910
+ closeDropdown();
1909
1911
  }
1910
1912
  if (e.key === "Escape") {
1911
- drop.classList.remove("open");
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
- initDropdowns
2273
+ initContextMenu,
2274
+ initDropdowns,
2275
+ initThemeToggle
1928
2276
  };
1929
2277
  /*! Bundled license information:
1930
2278
 
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@kerkhoff-ict/solora",
3
- "version": "2.0.8",
3
+ "version": "2.1.1",
4
4
  "description": "Simple CSS component library",
5
+ "type": "module",
5
6
  "main": "dist/index.js",
6
7
  "style": "dist/index.css",
7
8
  "files": [