pinokiod 7.5.18 → 7.5.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/kernel/bin/index.js +0 -5
  2. package/kernel/bin/setup.js +0 -1
  3. package/kernel/index.js +0 -3
  4. package/package.json +1 -1
  5. package/server/public/common.js +1 -1
  6. package/server/public/style.css +91 -0
  7. package/server/public/urldropdown.css +272 -0
  8. package/server/public/urldropdown.js +44 -12
  9. package/server/views/app.ejs +190 -146
  10. package/server/views/autolaunch.ejs +10 -1
  11. package/server/views/columns.ejs +13 -1
  12. package/server/views/d.ejs +40 -135
  13. package/server/views/index.ejs +14 -6
  14. package/server/views/logs.ejs +1 -1
  15. package/server/views/partials/app_autolaunch_modal_helpers.ejs +4 -0
  16. package/server/views/partials/d_column_subtitle.ejs +10 -0
  17. package/server/views/partials/d_menu_column.ejs +18 -0
  18. package/server/views/partials/d_terminal_column.ejs +2 -11
  19. package/server/views/partials/d_terminal_options.ejs +1 -18
  20. package/server/views/partials/d_tool_tab.ejs +32 -0
  21. package/server/views/partials/main_sidebar.ejs +3 -0
  22. package/server/views/rows.ejs +13 -1
  23. package/system/plugin/antigravity-cli/common.js +1 -2
  24. package/test/antigravity-cli-plugin.test.js +3 -2
  25. package/test/home-autolaunch-live-ui.test.js +70 -0
  26. package/test/launch-requirements-browser.test.js +259 -3
  27. package/test/plugin-dev-iframe.test.js +67 -1
  28. package/test/plugin-sources.test.js +1 -1
  29. package/test/url-split-modal.test.js +107 -0
  30. package/system/plugin/crush/crush.png +0 -0
  31. package/system/plugin/crush/pinokio.js +0 -15
  32. package/system/plugin/qwen/pinokio.js +0 -34
  33. package/system/plugin/qwen/qwen.png +0 -0
  34. package/system/plugin/windsurf/pinokio.js +0 -23
  35. package/system/plugin/windsurf/windsurf.png +0 -0
@@ -238,11 +238,6 @@ class Bin {
238
238
  if (this.kernel.homedir) {
239
239
  const bin_folder = this.path()
240
240
  await fs.promises.mkdir(bin_folder, { recursive: true }).catch((e) => { })
241
- if (this.platform !== "linux") {
242
- const playwright_folder = path.resolve(bin_folder, "playwright/browsers")
243
- process.env.PLAYWRIGHT_BROWSERS_PATH = playwright_folder
244
- }
245
- // await fs.promises.mkdir(playwright_folder, { recursive: true }).catch((e) => { })
246
241
  let system_env = await Environment.get(this.kernel.homedir, this.kernel)
247
242
 
248
243
  if (system_env.HTTP_PROXY) {
@@ -49,7 +49,6 @@ module.exports = {
49
49
  }
50
50
  requirements = requirements.concat([
51
51
  // { name: "cloudflared" },
52
- // { name: "playwright" },
53
52
  { name: "huggingface" },
54
53
  { name: "uv" },
55
54
  { name: "py" },
package/kernel/index.js CHANGED
@@ -1272,9 +1272,6 @@ class Kernel {
1272
1272
 
1273
1273
  await fs.promises.mkdir(this.path("logs"), { recursive: true }).catch((e) => { })
1274
1274
  await fs.promises.writeFile(this.path("logs/system.json"), JSON.stringify(this.i, null, 2))
1275
- let pwpath = this.bin.path("playwright/node_modules/playwright")
1276
- this.playwright = (await this.loader.load(pwpath)).resolved
1277
-
1278
1275
  //await this.fileserver()
1279
1276
 
1280
1277
  // get env
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pinokiod",
3
- "version": "7.5.18",
3
+ "version": "7.5.20",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -3301,7 +3301,7 @@ document.addEventListener("DOMContentLoaded", () => {
3301
3301
  selectedUrl = await api.openSplitModal({
3302
3302
  title: modalTitle,
3303
3303
  description: 'Choose a running process or use the current tab URL for the new pane.',
3304
- confirmLabel: 'Split',
3304
+ confirmLabel: 'Open in pane',
3305
3305
  includeCurrent: true
3306
3306
  });
3307
3307
  } catch (error) {
@@ -1284,6 +1284,7 @@ body.main-sidebar-page .navheader .sidebar-toggle {
1284
1284
  padding: 0;
1285
1285
  border-radius: 9px;
1286
1286
  box-sizing: border-box;
1287
+ transition: background-color 140ms cubic-bezier(0.25, 1, 0.5, 1), box-shadow 140ms cubic-bezier(0.25, 1, 0.5, 1), color 140ms cubic-bezier(0.25, 1, 0.5, 1);
1287
1288
  }
1288
1289
  body.dark.main-sidebar-page .navheader .sidebar-toggle {
1289
1290
  color: rgba(248, 250, 252, 0.92);
@@ -1319,6 +1320,8 @@ body.main-sidebar-page .sidebar-toggle-panel {
1319
1320
  width: 4px;
1320
1321
  border-radius: 1px;
1321
1322
  background: currentColor;
1323
+ transform-origin: left center;
1324
+ transition: opacity 150ms cubic-bezier(0.25, 1, 0.5, 1), transform 150ms cubic-bezier(0.25, 1, 0.5, 1), background-color 150ms cubic-bezier(0.25, 1, 0.5, 1), border-color 150ms cubic-bezier(0.25, 1, 0.5, 1);
1322
1325
  }
1323
1326
  body.main-sidebar-page .sidebar-toggle-content {
1324
1327
  position: absolute;
@@ -1330,12 +1333,18 @@ body.main-sidebar-page .sidebar-toggle-content {
1330
1333
  background: currentColor;
1331
1334
  opacity: 0.32;
1332
1335
  box-shadow: 0 3.8px 0 currentColor, 0 7.6px 0 currentColor;
1336
+ transition: opacity 150ms cubic-bezier(0.25, 1, 0.5, 1), transform 150ms cubic-bezier(0.25, 1, 0.5, 1);
1333
1337
  }
1334
1338
  body.main-sidebar-page .navheader .sidebar-toggle[aria-expanded="false"] .sidebar-toggle-panel {
1335
1339
  background: transparent;
1336
1340
  outline: 1.5px solid currentColor;
1337
1341
  outline-offset: -1px;
1338
1342
  opacity: 0.35;
1343
+ transform: translateX(-1px) scaleX(0.8);
1344
+ }
1345
+ body.main-sidebar-page .navheader .sidebar-toggle[aria-expanded="false"] .sidebar-toggle-content {
1346
+ opacity: 0.42;
1347
+ transform: translateX(-2px);
1339
1348
  }
1340
1349
  body.main-sidebar-page main {
1341
1350
  display: flex;
@@ -1810,6 +1819,10 @@ body.dark .main-sidebar-peer-dialog-surface {
1810
1819
 
1811
1820
  body.main-sidebar-page .main-sidebar {
1812
1821
  align-self: stretch;
1822
+ flex: 0 0 180px;
1823
+ width: 180px;
1824
+ min-width: 180px;
1825
+ max-width: 180px;
1813
1826
  height: auto;
1814
1827
  max-height: none;
1815
1828
  overflow-x: hidden;
@@ -1817,6 +1830,14 @@ body.dark .main-sidebar-peer-dialog-surface {
1817
1830
  overscroll-behavior: contain;
1818
1831
  scrollbar-width: thin;
1819
1832
  scrollbar-color: rgba(148, 163, 184, 0.45) transparent;
1833
+ opacity: 1;
1834
+ transform: translateX(0);
1835
+ }
1836
+
1837
+ body.main-sidebar-page.main-sidebar-motion-ready .main-sidebar,
1838
+ body.main-sidebar-page.main-sidebar-motion-ready main > .container,
1839
+ body.main-sidebar-page.main-sidebar-motion-ready main > .task-container {
1840
+ transition: flex-basis 190ms cubic-bezier(0.25, 1, 0.5, 1), width 190ms cubic-bezier(0.25, 1, 0.5, 1), min-width 190ms cubic-bezier(0.25, 1, 0.5, 1), max-width 190ms cubic-bezier(0.25, 1, 0.5, 1), padding 190ms cubic-bezier(0.25, 1, 0.5, 1), border-color 190ms cubic-bezier(0.25, 1, 0.5, 1), opacity 140ms cubic-bezier(0.25, 1, 0.5, 1), transform 190ms cubic-bezier(0.25, 1, 0.5, 1);
1820
1841
  }
1821
1842
 
1822
1843
  body.dark.main-sidebar-page .main-sidebar {
@@ -1842,6 +1863,7 @@ body.dark .main-sidebar-peer-dialog-surface {
1842
1863
  }
1843
1864
 
1844
1865
  body.main-sidebar-page.main-sidebar-collapsed .main-sidebar {
1866
+ flex-basis: 0;
1845
1867
  width: 0;
1846
1868
  min-width: 0;
1847
1869
  max-width: 0;
@@ -1852,12 +1874,24 @@ body.dark .main-sidebar-peer-dialog-surface {
1852
1874
  opacity: 0;
1853
1875
  pointer-events: none;
1854
1876
  overflow: hidden;
1877
+ transform: translateX(-10px);
1855
1878
  }
1856
1879
 
1857
1880
  body.main-sidebar-page.main-sidebar-collapsed main > .container,
1858
1881
  body.main-sidebar-page.main-sidebar-collapsed main > .task-container {
1859
1882
  padding-left: 0;
1860
1883
  }
1884
+
1885
+ @media (prefers-reduced-motion: reduce) {
1886
+ body.main-sidebar-page .navheader .sidebar-toggle,
1887
+ body.main-sidebar-page .sidebar-toggle-panel,
1888
+ body.main-sidebar-page .sidebar-toggle-content,
1889
+ body.main-sidebar-page.main-sidebar-motion-ready .main-sidebar,
1890
+ body.main-sidebar-page.main-sidebar-motion-ready main > .container,
1891
+ body.main-sidebar-page.main-sidebar-motion-ready main > .task-container {
1892
+ transition-duration: 0.01ms !important;
1893
+ }
1894
+ }
1861
1895
  }
1862
1896
  form.search input[type=search] {
1863
1897
  flex-grow: 1;
@@ -6472,6 +6506,63 @@ body.dark .logs-resizer:hover .logs-resizer-toggle {
6472
6506
  }
6473
6507
  }
6474
6508
 
6509
+ body.main-sidebar-page main > .logs-container {
6510
+ overflow: hidden;
6511
+ }
6512
+
6513
+ .logs-page[data-view="latest"] {
6514
+ overflow-x: hidden;
6515
+ overflow-y: auto;
6516
+ overscroll-behavior: contain;
6517
+ scroll-padding-bottom: 96px;
6518
+ }
6519
+
6520
+ .logs-page[data-view="latest"] .logs-latest-view {
6521
+ flex: 1 0 auto;
6522
+ overflow: visible;
6523
+ }
6524
+
6525
+ .logs-page[data-view="latest"] .logs-latest-workspace {
6526
+ flex: 1 0 auto;
6527
+ align-items: start;
6528
+ grid-template-rows: auto;
6529
+ overflow: visible;
6530
+ }
6531
+
6532
+ .logs-page[data-view="latest"] .logs-report-pane,
6533
+ .logs-page[data-view="latest"] .logs-redaction-pane {
6534
+ align-self: start;
6535
+ width: 100%;
6536
+ overflow: visible;
6537
+ }
6538
+
6539
+ .logs-page[data-view="latest"] .logs-review-content,
6540
+ .logs-page[data-view="latest"] .logs-review-section--redactions {
6541
+ flex: 0 0 auto;
6542
+ overflow: visible;
6543
+ }
6544
+
6545
+ .logs-page[data-view="latest"] .logs-review-file-list {
6546
+ max-height: none;
6547
+ overflow: visible;
6548
+ }
6549
+
6550
+ .logs-page[data-view="latest"] .logs-report-output,
6551
+ .logs-page[data-view="latest"] .logs-redaction-list {
6552
+ flex: 0 0 auto;
6553
+ overflow: visible;
6554
+ }
6555
+
6556
+ .logs-page[data-view="latest"] .logs-redaction-pane {
6557
+ max-height: none;
6558
+ }
6559
+
6560
+ .logs-page[data-view="latest"] .logs-community-footer {
6561
+ position: sticky;
6562
+ bottom: 0;
6563
+ z-index: 3;
6564
+ }
6565
+
6475
6566
  /* Minimal SweetAlert normalization for generic QR/form modals. */
6476
6567
  .swal2-popup.min-popup,
6477
6568
  .swal2-popup.min-popup2 {
@@ -1620,6 +1620,12 @@ body.dark .url-modal-close:hover {
1620
1620
  outline: 2px solid royalblue;
1621
1621
  outline-offset: 2px;
1622
1622
  }
1623
+ .url-modal-input-row {
1624
+ width: 100%;
1625
+ }
1626
+ .url-modal-inline-submit {
1627
+ display: none;
1628
+ }
1623
1629
  .url-modal-input {
1624
1630
  width: 100%;
1625
1631
  padding: 14px 16px;
@@ -1736,6 +1742,272 @@ body.dark .url-modal-button.cancel {
1736
1742
  box-shadow: none;
1737
1743
  }
1738
1744
 
1745
+ .url-modal-overlay.split-mode {
1746
+ background: rgba(15, 23, 42, 0.32);
1747
+ -webkit-backdrop-filter: none;
1748
+ backdrop-filter: none;
1749
+ }
1750
+ .url-modal-content.split-mode {
1751
+ width: min(860px, calc(100% - 48px));
1752
+ padding: 22px 24px 20px;
1753
+ gap: 10px;
1754
+ border-radius: 10px;
1755
+ background: rgba(252, 252, 253, 0.98);
1756
+ box-shadow: 0 18px 48px rgba(15, 23, 42, 0.18);
1757
+ }
1758
+ body.dark .url-modal-content.split-mode {
1759
+ background: rgba(24, 25, 27, 0.98);
1760
+ border-color: rgba(148, 163, 184, 0.18);
1761
+ box-shadow: 0 22px 56px rgba(0, 0, 0, 0.45);
1762
+ }
1763
+ .url-modal-content.split-mode h3 {
1764
+ padding-right: 36px;
1765
+ font-size: 20px;
1766
+ letter-spacing: 0;
1767
+ }
1768
+ .url-modal-content.split-mode .url-modal-description {
1769
+ font-size: 13px;
1770
+ line-height: 1.4;
1771
+ }
1772
+ .url-modal-content.split-mode .url-modal-input-row {
1773
+ display: grid;
1774
+ grid-template-columns: minmax(0, 1fr) auto;
1775
+ align-items: stretch;
1776
+ }
1777
+ .url-modal-content.split-mode .url-modal-input {
1778
+ height: 38px;
1779
+ min-width: 0;
1780
+ padding: 8px 12px;
1781
+ border-radius: 7px 0 0 7px;
1782
+ border-color: rgba(15, 23, 42, 0.14);
1783
+ background: rgba(255, 255, 255, 0.95);
1784
+ font-size: 13px;
1785
+ box-shadow: none;
1786
+ }
1787
+ .url-modal-content.split-mode .url-modal-input:focus {
1788
+ border-color: rgba(15, 23, 42, 0.28);
1789
+ box-shadow: inset 0 0 0 1px rgba(15, 23, 42, 0.08);
1790
+ }
1791
+ body.dark .url-modal-content.split-mode .url-modal-input {
1792
+ border-color: rgba(148, 163, 184, 0.28);
1793
+ background: rgba(255, 255, 255, 0.06);
1794
+ }
1795
+ body.dark .url-modal-content.split-mode .url-modal-input:focus {
1796
+ border-color: rgba(226, 232, 240, 0.42);
1797
+ box-shadow: inset 0 0 0 1px rgba(226, 232, 240, 0.12);
1798
+ }
1799
+ .url-modal-content.split-mode .url-modal-inline-submit {
1800
+ display: inline-flex;
1801
+ align-items: center;
1802
+ justify-content: center;
1803
+ height: 38px;
1804
+ padding: 0 14px;
1805
+ border: 1px solid rgba(15, 23, 42, 0.9);
1806
+ border-left: none;
1807
+ border-radius: 0 7px 7px 0;
1808
+ background: rgba(15, 23, 42, 0.92);
1809
+ color: #fff;
1810
+ font-size: 12px;
1811
+ font-weight: 600;
1812
+ white-space: nowrap;
1813
+ cursor: pointer;
1814
+ }
1815
+ .url-modal-content.split-mode .url-modal-inline-submit:hover {
1816
+ background: rgba(15, 23, 42, 1);
1817
+ }
1818
+ .url-modal-content.split-mode .url-modal-inline-submit:focus-visible {
1819
+ outline: 2px solid rgba(15, 23, 42, 0.35);
1820
+ outline-offset: 2px;
1821
+ }
1822
+ .url-modal-content.split-mode .url-modal-inline-submit:disabled {
1823
+ cursor: not-allowed;
1824
+ opacity: 0.45;
1825
+ }
1826
+ body.dark .url-modal-content.split-mode .url-modal-inline-submit {
1827
+ border-color: rgba(226, 232, 240, 0.84);
1828
+ background: rgba(226, 232, 240, 0.92);
1829
+ color: rgba(15, 23, 42, 0.96);
1830
+ }
1831
+ body.dark .url-modal-content.split-mode .url-modal-inline-submit:hover {
1832
+ background: rgba(255, 255, 255, 0.98);
1833
+ }
1834
+ .url-modal-content.split-mode .url-modal-actions {
1835
+ display: none;
1836
+ }
1837
+ .url-modal-content.split-mode .url-dropdown {
1838
+ max-height: 58vh;
1839
+ margin-top: 2px;
1840
+ border-radius: 8px;
1841
+ border-color: rgba(15, 23, 42, 0.1);
1842
+ background: rgba(255, 255, 255, 0.96);
1843
+ box-shadow: none;
1844
+ }
1845
+ body.dark .url-modal-content.split-mode .url-dropdown {
1846
+ background: rgba(255, 255, 255, 0.04);
1847
+ border-color: rgba(148, 163, 184, 0.16);
1848
+ box-shadow: none;
1849
+ }
1850
+ .url-modal-content.split-mode .url-dropdown-host-header {
1851
+ min-height: 28px;
1852
+ padding: 0 10px;
1853
+ background: rgba(15, 23, 42, 0.035);
1854
+ color: rgba(71, 85, 105, 0.9);
1855
+ border-bottom: 1px solid rgba(15, 23, 42, 0.08);
1856
+ font-size: 11px;
1857
+ font-weight: 600;
1858
+ letter-spacing: 0.02em;
1859
+ }
1860
+ body.dark .url-modal-content.split-mode .url-dropdown-host-header {
1861
+ background: rgba(255, 255, 255, 0.04);
1862
+ color: rgba(203, 213, 225, 0.86);
1863
+ border-bottom-color: rgba(148, 163, 184, 0.14);
1864
+ }
1865
+ .url-modal-content.split-mode .url-dropdown-host-header .host-name,
1866
+ .url-modal-content.split-mode .url-dropdown-host-header .host-meta,
1867
+ .url-modal-content.split-mode .url-dropdown-host-header .host-arch {
1868
+ padding: 0;
1869
+ color: inherit;
1870
+ font-size: inherit;
1871
+ font-weight: inherit;
1872
+ text-align: left;
1873
+ }
1874
+ .url-modal-content.split-mode .url-dropdown-host-header .host-name {
1875
+ flex-grow: 0;
1876
+ }
1877
+ .url-modal-content.split-mode .url-dropdown-item {
1878
+ min-height: 34px;
1879
+ padding: 4px 8px;
1880
+ border-bottom-color: rgba(15, 23, 42, 0.07);
1881
+ gap: 10px;
1882
+ }
1883
+ body.dark .url-modal-content.split-mode .url-dropdown-item {
1884
+ border-bottom-color: rgba(148, 163, 184, 0.12);
1885
+ }
1886
+ .url-modal-content.split-mode .url-dropdown-item:hover {
1887
+ background: rgba(15, 23, 42, 0.035);
1888
+ }
1889
+ body.dark .url-modal-content.split-mode .url-dropdown-item:hover {
1890
+ background: rgba(255, 255, 255, 0.05);
1891
+ }
1892
+ .url-modal-content.split-mode .url-dropdown-item.current-project {
1893
+ display: grid;
1894
+ grid-template-columns: minmax(150px, 0.9fr) minmax(120px, 1.1fr) auto;
1895
+ align-items: center;
1896
+ }
1897
+ .url-modal-content.split-mode .url-dropdown-item:not(.current-project) {
1898
+ display: grid;
1899
+ grid-template-columns: minmax(150px, 0.9fr) minmax(120px, 1.1fr);
1900
+ align-items: center;
1901
+ }
1902
+ .url-modal-content.split-mode .url-dropdown-name,
1903
+ .url-modal-content.split-mode .url-dropdown-url,
1904
+ .url-modal-content.split-mode .url-mode-buttons {
1905
+ min-width: 0;
1906
+ }
1907
+ .url-modal-content.split-mode .url-dropdown-name {
1908
+ font-size: 13px;
1909
+ font-weight: 600;
1910
+ }
1911
+ .url-modal-content.split-mode .url-dropdown-name span,
1912
+ .url-modal-content.split-mode .url-dropdown-name {
1913
+ overflow: hidden;
1914
+ text-overflow: ellipsis;
1915
+ white-space: nowrap;
1916
+ }
1917
+ .url-modal-content.split-mode .url-dropdown-name span {
1918
+ display: inline-flex;
1919
+ align-items: center;
1920
+ max-width: 100%;
1921
+ gap: 7px;
1922
+ }
1923
+ .url-modal-content.split-mode .url-dropdown-name i {
1924
+ margin-right: 0;
1925
+ color: rgba(71, 85, 105, 0.9);
1926
+ }
1927
+ body.dark .url-modal-content.split-mode .url-dropdown-name i {
1928
+ color: rgba(203, 213, 225, 0.82);
1929
+ }
1930
+ .url-modal-content.split-mode .url-dropdown-url {
1931
+ gap: 6px;
1932
+ margin-bottom: 0;
1933
+ overflow: hidden;
1934
+ white-space: nowrap;
1935
+ }
1936
+ .url-modal-content.split-mode .url-address {
1937
+ overflow: hidden;
1938
+ text-overflow: ellipsis;
1939
+ white-space: nowrap;
1940
+ }
1941
+ .url-modal-content.split-mode .url-scheme,
1942
+ .url-modal-content.split-mode .url-scheme.https {
1943
+ flex: 0 0 auto;
1944
+ padding: 1px 5px;
1945
+ border-radius: 4px;
1946
+ background: rgba(15, 23, 42, 0.055);
1947
+ color: rgba(71, 85, 105, 0.82);
1948
+ font-size: 9px;
1949
+ letter-spacing: 0;
1950
+ }
1951
+ body.dark .url-modal-content.split-mode .url-scheme,
1952
+ body.dark .url-modal-content.split-mode .url-scheme.https {
1953
+ background: rgba(255, 255, 255, 0.07);
1954
+ color: rgba(203, 213, 225, 0.78);
1955
+ }
1956
+ .url-modal-content.split-mode .url-mode-buttons {
1957
+ justify-content: flex-end;
1958
+ flex-wrap: nowrap;
1959
+ gap: 4px;
1960
+ }
1961
+ .url-modal-content.split-mode .url-mode-button {
1962
+ height: 26px;
1963
+ padding: 0 9px;
1964
+ border-radius: 6px;
1965
+ border-color: rgba(15, 23, 42, 0.12);
1966
+ background: rgba(255, 255, 255, 0.88);
1967
+ color: rgba(15, 23, 42, 0.78);
1968
+ font-size: 11px;
1969
+ line-height: 1;
1970
+ }
1971
+ .url-modal-content.split-mode .url-mode-button:hover {
1972
+ background: rgba(15, 23, 42, 0.055);
1973
+ color: rgba(15, 23, 42, 0.9);
1974
+ }
1975
+ .url-modal-content.split-mode .url-mode-button.active {
1976
+ border-color: rgba(15, 23, 42, 0.92);
1977
+ background: rgba(15, 23, 42, 0.92);
1978
+ color: #fff;
1979
+ }
1980
+ body.dark .url-modal-content.split-mode .url-mode-button {
1981
+ border-color: rgba(148, 163, 184, 0.18);
1982
+ background: rgba(255, 255, 255, 0.05);
1983
+ color: rgba(226, 232, 240, 0.82);
1984
+ }
1985
+ body.dark .url-modal-content.split-mode .url-mode-button:hover {
1986
+ background: rgba(255, 255, 255, 0.09);
1987
+ color: rgba(255, 255, 255, 0.92);
1988
+ }
1989
+ body.dark .url-modal-content.split-mode .url-mode-button.active {
1990
+ border-color: rgba(226, 232, 240, 0.86);
1991
+ background: rgba(226, 232, 240, 0.92);
1992
+ color: rgba(15, 23, 42, 0.96);
1993
+ }
1994
+
1995
+ @media (max-width: 640px) {
1996
+ .url-modal-content.split-mode {
1997
+ width: min(540px, calc(100% - 20px));
1998
+ padding: 18px;
1999
+ }
2000
+ .url-modal-content.split-mode .url-dropdown-item.current-project {
2001
+ grid-template-columns: minmax(0, 1fr) auto;
2002
+ }
2003
+ .url-modal-content.split-mode .url-dropdown-item:not(.current-project) {
2004
+ grid-template-columns: minmax(0, 1fr);
2005
+ }
2006
+ .url-modal-content.split-mode .url-dropdown-url {
2007
+ display: none;
2008
+ }
2009
+ }
2010
+
1739
2011
  /* Host categorization styles */
1740
2012
  .url-dropdown-host-header {
1741
2013
  background: royalblue;
@@ -191,13 +191,13 @@ function initUrlDropdown(config = {}) {
191
191
  };
192
192
  };
193
193
 
194
- const buildProjectModeButtons = (projectCtx) => {
194
+ const buildProjectModeButtons = (projectCtx, { includeFiles = true } = {}) => {
195
195
  if (!projectCtx) return '';
196
196
  const modes = [
197
197
  { key: 'run', label: 'Run', icon: 'fa-solid fa-circle-play', suffix: '' },
198
198
  { key: 'dev', label: 'Dev', icon: 'fa-solid fa-code', suffix: '/dev' },
199
199
  { key: 'files', label: 'Files', icon: 'fa-solid fa-file-lines', suffix: '/files' },
200
- ];
200
+ ].filter((mode) => includeFiles || mode.key !== 'files');
201
201
 
202
202
  const buildTarget = (suffix) => {
203
203
  const targetPath = `${projectCtx.basePath}${suffix}`;
@@ -244,14 +244,15 @@ function initUrlDropdown(config = {}) {
244
244
  currentUrl = '',
245
245
  currentTitle = 'Current tab',
246
246
  currentProject = null,
247
- origin = ''
247
+ origin = '',
248
+ includeFiles = true
248
249
  } = {}) => {
249
250
  const entries = [];
250
251
 
251
252
  if (includeCurrentTab && currentUrl) {
252
253
  const schemeLabel = currentUrl.startsWith('https://') ? 'HTTPS' : 'HTTP';
253
254
  const currentPathLabel = currentProject ? currentProject.basePath : formatUrlLabel(currentUrl) || currentUrl;
254
- const projectButtons = currentProject ? buildProjectModeButtons(currentProject) : '';
255
+ const projectButtons = currentProject ? buildProjectModeButtons(currentProject, { includeFiles }) : '';
255
256
  entries.push(`
256
257
  <div class="url-dropdown-item${currentProject ? ' non-selectable current-project' : ''}" data-url="${escapeAttribute(currentUrl)}" data-host-type="current">
257
258
  <div class="url-dropdown-name">
@@ -285,7 +286,7 @@ function initUrlDropdown(config = {}) {
285
286
  if (!projectCtx) return;
286
287
  const displayUrl = projectCtx.origin ? `${projectCtx.origin}${projectCtx.basePath}` : projectCtx.basePath;
287
288
  const schemeLabel = displayUrl.startsWith('https://') ? 'HTTPS' : 'HTTP';
288
- const projectButtons = buildProjectModeButtons(projectCtx);
289
+ const projectButtons = buildProjectModeButtons(projectCtx, { includeFiles });
289
290
  const displayTitle = getAppDisplayTitle(app);
290
291
  entries.push(`
291
292
  <div class="url-dropdown-item non-selectable current-project" data-url="${escapeAttribute(displayUrl)}" data-host-type="current">
@@ -707,7 +708,7 @@ function initUrlDropdown(config = {}) {
707
708
  return html;
708
709
  };
709
710
 
710
- const buildDropdownHtml = (processes, { includeCurrentTab = true, apps = [], inputElement } = {}) => {
711
+ const buildDropdownHtml = (processes, { includeCurrentTab = true, apps = [], inputElement, includeFiles = true } = {}) => {
711
712
  const currentUrl = typeof window !== 'undefined' ? window.location.href : '';
712
713
  const currentTitle = typeof document !== 'undefined' ? (document.title || 'Current tab') : 'Current tab';
713
714
  const currentProject = parseProjectContext(currentUrl);
@@ -719,7 +720,8 @@ function initUrlDropdown(config = {}) {
719
720
  currentUrl,
720
721
  currentTitle,
721
722
  currentProject,
722
- origin
723
+ origin,
724
+ includeFiles
723
725
  });
724
726
  if (appsHtml) {
725
727
  html += appsHtml;
@@ -932,6 +934,17 @@ function initUrlDropdown(config = {}) {
932
934
  modalInput.className = 'url-modal-input';
933
935
  modalInput.placeholder = 'Example: http://localhost:7860';
934
936
 
937
+ const inputRow = document.createElement('div');
938
+ inputRow.className = 'url-modal-input-row';
939
+
940
+ const inlineConfirmButton = document.createElement('button');
941
+ inlineConfirmButton.type = 'button';
942
+ inlineConfirmButton.className = 'url-modal-inline-submit';
943
+ inlineConfirmButton.textContent = 'Open';
944
+ inlineConfirmButton.disabled = true;
945
+
946
+ inputRow.append(modalInput, inlineConfirmButton);
947
+
935
948
  const modalDropdown = document.createElement('div');
936
949
  modalDropdown.className = 'url-dropdown';
937
950
  modalDropdown.id = 'url-modal-dropdown';
@@ -952,11 +965,13 @@ function initUrlDropdown(config = {}) {
952
965
 
953
966
  actions.append(cancelButton, confirmButton);
954
967
 
955
- content.append(closeButton, heading, description, modalInput, modalDropdown, actions);
968
+ content.append(closeButton, heading, description, inputRow, modalDropdown, actions);
956
969
  overlay.append(content);
957
970
 
958
971
  const updateConfirmState = () => {
959
- confirmButton.disabled = !modalInput.value.trim();
972
+ const disabled = !modalInput.value.trim();
973
+ confirmButton.disabled = disabled;
974
+ inlineConfirmButton.disabled = disabled;
960
975
  };
961
976
 
962
977
  modalInput.addEventListener('focus', () => {
@@ -981,6 +996,7 @@ function initUrlDropdown(config = {}) {
981
996
 
982
997
  cancelButton.addEventListener('click', closeMobileModal);
983
998
  confirmButton.addEventListener('click', submitMobileModal);
999
+ inlineConfirmButton.addEventListener('click', submitMobileModal);
984
1000
  closeButton.addEventListener('click', closeMobileModal);
985
1001
 
986
1002
  overlay.addEventListener('click', (event) => {
@@ -991,9 +1007,12 @@ function initUrlDropdown(config = {}) {
991
1007
 
992
1008
  overlay._modalRefs = {
993
1009
  input: modalInput,
1010
+ inputRow,
994
1011
  dropdown: modalDropdown,
995
1012
  confirmButton,
1013
+ inlineConfirmButton,
996
1014
  cancelButton,
1015
+ content,
997
1016
  closeButton,
998
1017
  heading,
999
1018
  description,
@@ -1038,12 +1057,18 @@ function initUrlDropdown(config = {}) {
1038
1057
  refs.heading.textContent = title;
1039
1058
  refs.description.textContent = descriptionText;
1040
1059
  refs.confirmButton.textContent = confirmLabel;
1060
+ if (refs.inlineConfirmButton) {
1061
+ refs.inlineConfirmButton.textContent = confirmLabel;
1062
+ }
1041
1063
  refs.includeCurrent = includeCurrent;
1042
1064
  refs.context = customOptions.context || 'default';
1043
1065
  refs.returnSelection = Boolean(customOptions.awaitSelection);
1044
1066
  refs.resolve = null;
1067
+ overlay.classList.toggle('split-mode', refs.context === 'split');
1068
+ refs.content?.classList.toggle('split-mode', refs.context === 'split');
1045
1069
  if (refs.dropdown) {
1046
1070
  refs.dropdown._includeCurrent = includeCurrent;
1071
+ refs.dropdown._context = refs.context;
1047
1072
  }
1048
1073
 
1049
1074
  modalInput.value = initialValue;
@@ -1086,6 +1111,9 @@ function initUrlDropdown(config = {}) {
1086
1111
  if (refs?.confirmButton) {
1087
1112
  refs.confirmButton.disabled = true;
1088
1113
  }
1114
+ if (refs?.inlineConfirmButton) {
1115
+ refs.inlineConfirmButton.disabled = true;
1116
+ }
1089
1117
 
1090
1118
  if (refs) {
1091
1119
  if (options.resolveValue !== undefined) {
@@ -1102,6 +1130,8 @@ function initUrlDropdown(config = {}) {
1102
1130
  if (!options.keepMode) {
1103
1131
  refs.context = 'default';
1104
1132
  refs.includeCurrent = true;
1133
+ overlay.classList.remove('split-mode');
1134
+ refs.content?.classList.remove('split-mode');
1105
1135
  }
1106
1136
  }
1107
1137
 
@@ -1151,7 +1181,8 @@ function initUrlDropdown(config = {}) {
1151
1181
  modalDropdown.innerHTML = buildDropdownHtml(processes, {
1152
1182
  includeCurrentTab: includeCurrent,
1153
1183
  apps,
1154
- inputElement: modalDropdown.parentElement.querySelector('.url-modal-input')
1184
+ inputElement: modalDropdown.parentElement.querySelector('.url-modal-input'),
1185
+ includeFiles: modalDropdown._context !== 'split'
1155
1186
  });
1156
1187
  attachCreateButtonHandler(modalDropdown, modalDropdown.parentElement.querySelector('.url-modal-input'));
1157
1188
  attachUrlItemHandlers(modalDropdown, { onSelect: handleModalSelection });
@@ -1216,7 +1247,8 @@ function initUrlDropdown(config = {}) {
1216
1247
  modalDropdown.innerHTML = buildDropdownHtml(processes, {
1217
1248
  includeCurrentTab: includeCurrent,
1218
1249
  apps,
1219
- inputElement: modalInput
1250
+ inputElement: modalInput,
1251
+ includeFiles: modalDropdown._context !== 'split'
1220
1252
  });
1221
1253
 
1222
1254
  attachCreateButtonHandler(modalDropdown, modalInput);
@@ -1251,7 +1283,7 @@ function initUrlDropdown(config = {}) {
1251
1283
  return showMobileModal({
1252
1284
  title: modalOptions.title || 'Split View',
1253
1285
  description: modalOptions.description || 'Choose an app, a running process, or use the current tab URL for the new pane.',
1254
- confirmLabel: modalOptions.confirmLabel || 'Split',
1286
+ confirmLabel: modalOptions.confirmLabel || 'Open in pane',
1255
1287
  includeCurrent: modalOptions.includeCurrent !== false,
1256
1288
  awaitSelection: true,
1257
1289
  context: 'split'