pinokiod 7.0.10 → 7.0.11

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pinokiod",
3
- "version": "7.0.10",
3
+ "version": "7.0.11",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/server/index.js CHANGED
@@ -3815,14 +3815,10 @@ class Server {
3815
3815
  }
3816
3816
  }
3817
3817
  }
3818
- if (config.menu[i].popout) {
3819
- config.menu[i].target = "_blank"
3820
- } else {
3821
- const targetBase = config.menu[i].id || config.menu[i].src || config.menu[i].href
3822
- config.menu[i].target = targetBase ? "@" + targetBase : undefined
3823
- if (config.menu[i].href) {
3824
- config.menu[i].target_full = config.menu[i].href
3825
- }
3818
+ const targetBase = config.menu[i].id || config.menu[i].src || config.menu[i].href
3819
+ config.menu[i].target = targetBase ? "@" + targetBase : undefined
3820
+ if (config.menu[i].href) {
3821
+ config.menu[i].target_full = config.menu[i].href
3826
3822
  }
3827
3823
 
3828
3824
  //if (config.menu[i].href && config.menu[i].href.startsWith("http")) {
@@ -0,0 +1,60 @@
1
+ .browserview-external-surface {
2
+ display: flex;
3
+ align-items: center;
4
+ justify-content: center;
5
+ width: 100%;
6
+ height: 100%;
7
+ min-height: 0;
8
+ padding: 40px 32px;
9
+ box-sizing: border-box;
10
+ cursor: pointer;
11
+ transition: background-color 120ms ease;
12
+ }
13
+ .browserview-external-surface:hover,
14
+ .browserview-external-surface:focus-visible {
15
+ background: rgba(15, 23, 42, 0.03);
16
+ }
17
+ .browserview-external-panel {
18
+ width: min(420px, 100%);
19
+ display: grid;
20
+ justify-items: center;
21
+ gap: 12px;
22
+ text-align: center;
23
+ }
24
+ .browserview-external-icon {
25
+ width: 44px;
26
+ height: 44px;
27
+ display: grid;
28
+ place-items: center;
29
+ border-radius: 999px;
30
+ border: 1px solid rgba(15, 23, 42, 0.12);
31
+ color: #1f2937;
32
+ font-size: 16px;
33
+ }
34
+ .browserview-external-title {
35
+ font-size: 16px;
36
+ font-weight: 600;
37
+ line-height: 1.4;
38
+ color: #111827;
39
+ }
40
+ .browserview-external-url {
41
+ max-width: 100%;
42
+ font-size: 13px;
43
+ line-height: 1.5;
44
+ color: #6b7280;
45
+ word-break: break-word;
46
+ }
47
+ body.dark .browserview-external-surface:hover,
48
+ body.dark .browserview-external-surface:focus-visible {
49
+ background: rgba(148, 163, 184, 0.06);
50
+ }
51
+ body.dark .browserview-external-icon {
52
+ border-color: rgba(148, 163, 184, 0.24);
53
+ color: #e5e7eb;
54
+ }
55
+ body.dark .browserview-external-title {
56
+ color: #f3f4f6;
57
+ }
58
+ body.dark .browserview-external-url {
59
+ color: #94a3b8;
60
+ }
@@ -0,0 +1,92 @@
1
+ (function() {
2
+ const DEFAULT_TITLE = "Click to open in browser"
3
+ const normalizeHref = (value) => {
4
+ if (typeof value !== "string") {
5
+ return ""
6
+ }
7
+ const trimmed = value.trim()
8
+ if (
9
+ trimmed.length >= 2 &&
10
+ ((trimmed.startsWith('"') && trimmed.endsWith('"')) || (trimmed.startsWith("'") && trimmed.endsWith("'")))
11
+ ) {
12
+ return trimmed.slice(1, -1)
13
+ }
14
+ return trimmed
15
+ }
16
+
17
+ const resolveHref = (target) => {
18
+ if (!target) {
19
+ return ""
20
+ }
21
+ return normalizeHref(target.getAttribute("data-target-full") || target.href || target.getAttribute("href") || "")
22
+ }
23
+
24
+ const openBrowserPopoutUrl = (href) => {
25
+ if (!href) {
26
+ return
27
+ }
28
+ const agent = document.body ? document.body.getAttribute("data-agent") : null
29
+ if (agent === "electron") {
30
+ window.open(href, "_blank", "browser")
31
+ } else {
32
+ window.open(href, "_blank", "noopener")
33
+ }
34
+ }
35
+
36
+ window.createBrowserPopoutSurface = function(options = {}) {
37
+ const surface = document.getElementById(options.id || "browserview-external-surface")
38
+ const title = surface ? surface.querySelector("[data-browserview-external-title]") : null
39
+ const url = surface ? surface.querySelector("[data-browserview-external-url]") : null
40
+ const titleText = options.title || DEFAULT_TITLE
41
+ const onShow = typeof options.onShow === "function" ? options.onShow : null
42
+
43
+ const hide = () => {
44
+ if (!surface) {
45
+ return
46
+ }
47
+ surface.classList.add("hidden")
48
+ surface.setAttribute("hidden", "")
49
+ delete surface.dataset.href
50
+ }
51
+
52
+ const show = (target) => {
53
+ if (!surface || !target) {
54
+ return
55
+ }
56
+ const href = resolveHref(target)
57
+ surface.dataset.href = href
58
+ surface.classList.remove("hidden")
59
+ surface.removeAttribute("hidden")
60
+ if (title) {
61
+ title.textContent = titleText
62
+ }
63
+ if (url) {
64
+ url.textContent = href
65
+ }
66
+ if (onShow) {
67
+ onShow({ target, href })
68
+ }
69
+ }
70
+
71
+ if (surface && !surface.dataset.browserPopoutBound) {
72
+ surface.dataset.browserPopoutBound = "true"
73
+ surface.addEventListener("click", () => {
74
+ openBrowserPopoutUrl(surface.dataset.href || "")
75
+ })
76
+ surface.addEventListener("keydown", (event) => {
77
+ if (event.key === "Enter" || event.key === " ") {
78
+ event.preventDefault()
79
+ openBrowserPopoutUrl(surface.dataset.href || "")
80
+ }
81
+ })
82
+ }
83
+
84
+ return {
85
+ hide,
86
+ isPopoutTab: (node) => Boolean(node && node.getAttribute("data-popout-browser") === "true"),
87
+ open: openBrowserPopoutUrl,
88
+ show,
89
+ surface,
90
+ }
91
+ }
92
+ })()
@@ -108,7 +108,11 @@ document.addEventListener("click", async (e) => {
108
108
  if (href) {
109
109
  let agent = document.body.getAttribute("data-agent")
110
110
  if (agent === "electron") {
111
- window.open(href, "_blank", "pinokio")
111
+ if (features && features.includes("browser")) {
112
+ window.open(href, "_blank", "browser")
113
+ } else {
114
+ window.open(href, "_blank", "pinokio")
115
+ }
112
116
  } else {
113
117
  window.open(href, "_blank", features)
114
118
  }
@@ -144,13 +148,17 @@ document.addEventListener("click", async (e) => {
144
148
  if (el) {
145
149
  e.preventDefault()
146
150
  e.stopPropagation()
151
+ let features = el.getAttribute("features")
152
+ let href = el.href || el.getAttribute("data-href")
147
153
  let agent = document.body.getAttribute("data-agent")
148
- if (agent === "electron") {
149
- window.open(href, "_blank", "pinokio")
150
- } else {
151
- // window.open(href, "_blank", features)
152
- let features = el.getAttribute("features")
153
- window.open(el.href, "_blank", features)
154
+ if (agent === "electron" && href) {
155
+ if (features && features.includes("browser")) {
156
+ window.open(href, "_blank", "browser")
157
+ } else {
158
+ window.open(href, "_blank", "pinokio")
159
+ }
160
+ } else if (href) {
161
+ window.open(href, "_blank", features)
154
162
  }
155
163
  }
156
164
  }
@@ -1376,6 +1376,15 @@ header .runner.terminal-runner-minimal .btn span {
1376
1376
  .terminal-config .btn {
1377
1377
  margin-right: 0;
1378
1378
  }
1379
+ @media (max-width: 640px) {
1380
+ .navheader2 .runner,
1381
+ .navheader2 .runner .terminal-runner-utilities {
1382
+ gap: 5px;
1383
+ }
1384
+ .navheader2 .runner .btn {
1385
+ padding: 5px 5px;
1386
+ }
1387
+ }
1379
1388
  .terminal-config-menu {
1380
1389
  position: absolute;
1381
1390
  top: calc(100% + 8px);
@@ -4737,6 +4737,7 @@ header.navheader .mode-selector .community-mode-toggle {
4737
4737
  }
4738
4738
  </style>
4739
4739
  <link href="/app.css" rel="stylesheet"/>
4740
+ <link href="/browser-popout-surface.css" rel="stylesheet"/>
4740
4741
  <link href="/tab-link-popover.css" rel="stylesheet"/>
4741
4742
  <script src="/window_storage.js"></script>
4742
4743
  <script src="/timeago.min.js"></script>
@@ -4762,6 +4763,7 @@ header.navheader .mode-selector .community-mode-toggle {
4762
4763
  <script src="/popper.min.js"></script>
4763
4764
  <script src="/tippy-bundle.umd.min.js"></script>
4764
4765
  <script src="/tab-link-popover.js"></script>
4766
+ <script src="/browser-popout-surface.js"></script>
4765
4767
  <script>
4766
4768
  (function() {
4767
4769
  try {
@@ -5064,6 +5066,7 @@ header.navheader .mode-selector .community-mode-toggle {
5064
5066
  <% if (type === 'files') { %>
5065
5067
  <iframe class='selected' src="<%=editor_tab%>" allow="fullscreen *;" allowfullscreen></iframe>
5066
5068
  <% } %>
5069
+ <%- include('./partials/browser_popout_surface') %>
5067
5070
  </main>
5068
5071
  <% if (type === 'run') { %>
5069
5072
  <div class='ask-ai-resizer' id='ask-ai-resizer' role="separator" aria-orientation="vertical" aria-valuemin="240" aria-valuemax="9999" aria-valuenow="560" tabindex="0" aria-label="Resize panel"></div>
@@ -5281,6 +5284,11 @@ header.navheader .mode-selector .community-mode-toggle {
5281
5284
  })()
5282
5285
  let ignorePersistedSelection = pluginLaunchActive
5283
5286
  let lastForegroundSignature = null
5287
+ const browserPopoutSurface = window.createBrowserPopoutSurface({
5288
+ onShow: () => {
5289
+ lastForegroundSignature = null
5290
+ },
5291
+ })
5284
5292
  const iframe_onerror = (iframe) => {
5285
5293
  if (iframe && iframe.dataset && iframe.dataset.forceVisible === 'true') {
5286
5294
  return
@@ -6334,7 +6342,10 @@ const rerenderMenuSection = (container, html) => {
6334
6342
  target.classList.add("cursor")
6335
6343
  }
6336
6344
  const nav = (type) => {
6337
- let targetFrame = document.querySelector("iframe:not(.hidden)")
6345
+ let targetFrame = document.querySelector("main.browserview iframe:not(.hidden)")
6346
+ if (!targetFrame || !targetFrame.contentWindow) {
6347
+ return
6348
+ }
6338
6349
  if (type === "back") {
6339
6350
  // targetFrame.contentWindow.history.back()
6340
6351
  targetFrame.contentWindow.postMessage({
@@ -6520,6 +6531,7 @@ const rerenderMenuSection = (container, html) => {
6520
6531
  }
6521
6532
 
6522
6533
  if (!target) {
6534
+ browserPopoutSurface.hide()
6523
6535
  document.querySelector(".container").classList.remove("active")
6524
6536
  document.querySelector("aside").classList.add("active")
6525
6537
  return
@@ -6570,7 +6582,8 @@ const rerenderMenuSection = (container, html) => {
6570
6582
  let _url = new URL(target.href)
6571
6583
  const urlKey = selectionUrlStorageKey()
6572
6584
  if (urlKey) {
6573
- windowStorage.setItem(urlKey, _url.pathname + _url.search + _url.hash)
6585
+ const selectionValue = browserPopoutSurface.isPopoutTab(target) ? target.href : (_url.pathname + _url.search + _url.hash)
6586
+ windowStorage.setItem(urlKey, selectionValue)
6574
6587
  }
6575
6588
  <% } %>
6576
6589
 
@@ -6578,6 +6591,15 @@ const rerenderMenuSection = (container, html) => {
6578
6591
  document.querySelectorAll("main.browserview iframe").forEach((el) => {
6579
6592
  el.classList.add("hidden")
6580
6593
  })
6594
+ browserPopoutSurface.hide()
6595
+ if (browserPopoutSurface.isPopoutTab(target)) {
6596
+ if (eventParam) {
6597
+ eventParam.preventDefault()
6598
+ eventParam.stopPropagation()
6599
+ }
6600
+ browserPopoutSurface.show(target)
6601
+ return
6602
+ }
6581
6603
 
6582
6604
 
6583
6605
 
@@ -730,6 +730,7 @@ body.dark .appcanvas {
730
730
  }
731
731
  </style>
732
732
  <link href="/app.css" rel="stylesheet"/>
733
+ <link href="/browser-popout-surface.css" rel="stylesheet"/>
733
734
  <script src="/popper.min.js"></script>
734
735
  <script src="/tippy-bundle.umd.min.js"></script>
735
736
  <script src="/hotkeys.min.js"></script>
@@ -751,6 +752,7 @@ body.dark .appcanvas {
751
752
  <script src="/filepond-plugin-image-transform.min.js"></script>
752
753
  <script src="/filepond.min.js"></script>
753
754
  <script src="/fseditor.js"></script>
755
+ <script src="/browser-popout-surface.js"></script>
754
756
  </head>
755
757
  <body class='<%=theme%>' data-platform="<%=platform%>" data-agent="<%=agent%>">
756
758
  <header class='navheader grabbable'>
@@ -791,6 +793,7 @@ body.dark .appcanvas {
791
793
  </aside>
792
794
  <div class='container'>
793
795
  <main class='browserview'>
796
+ <%- include('./partials/browser_popout_surface') %>
794
797
  </main>
795
798
  </div>
796
799
  </div>
@@ -803,6 +806,7 @@ body.dark .appcanvas {
803
806
  interacted = true
804
807
  })
805
808
  const n = new N()
809
+ const browserPopoutSurface = window.createBrowserPopoutSurface()
806
810
  const getTarget = (href) => {
807
811
  let u
808
812
  if (href.startsWith("http")) {
@@ -851,6 +855,9 @@ body.dark .appcanvas {
851
855
  }
852
856
  const nav = (type) => {
853
857
  let targetFrame = document.querySelector("iframe:not(.hidden)")
858
+ if (!targetFrame || !targetFrame.contentWindow) {
859
+ return
860
+ }
854
861
  if (type === "back") {
855
862
  // targetFrame.contentWindow.history.back()
856
863
  targetFrame.contentWindow.postMessage({
@@ -948,6 +955,7 @@ body.dark .appcanvas {
948
955
  document.querySelector(".container").classList.add("active")
949
956
  document.querySelector("aside").classList.remove("active")
950
957
  } else {
958
+ browserPopoutSurface.hide()
951
959
  document.querySelector(".container").classList.remove("active")
952
960
  document.querySelector("aside").classList.add("active")
953
961
  }
@@ -986,6 +994,15 @@ body.dark .appcanvas {
986
994
  document.querySelectorAll("iframe").forEach((el) => {
987
995
  el.classList.add("hidden")
988
996
  })
997
+ browserPopoutSurface.hide()
998
+ if (browserPopoutSurface.isPopoutTab(target)) {
999
+ if (e) {
1000
+ e.preventDefault()
1001
+ e.stopPropagation()
1002
+ }
1003
+ browserPopoutSurface.show(target)
1004
+ return
1005
+ }
989
1006
 
990
1007
 
991
1008
 
@@ -0,0 +1,7 @@
1
+ <div class='browserview-external-surface hidden' id='browserview-external-surface' hidden role='button' tabindex='0' aria-label='Open selected page in browser'>
2
+ <div class='browserview-external-panel'>
3
+ <div class='browserview-external-icon'><i class="fa-solid fa-up-right-from-square" aria-hidden="true"></i></div>
4
+ <div class='browserview-external-title' data-browserview-external-title>Click to open in browser</div>
5
+ <div class='browserview-external-url' data-browserview-external-url></div>
6
+ </div>
7
+ </div>
@@ -27,15 +27,17 @@
27
27
  <div data-filepath="<%=item.href%>" class='btn header-item frame-link <%=item.display || ""%>'>
28
28
  <div class='tab'><%-item.btn%></div>
29
29
  </div>
30
- <% } else if (item.target === "_blank") { %>
31
- <a <%=item.default ? 'data-default' : ''%> data-confirm="<%=item.confirm%>" data-index="<%=index+4%>" target="<%=item.target%>" data-mode="<%=item.mode%>" href="<%=item.href%>" class='btn header-item frame-link <%=item.display || ""%>'<%= item.target_full ? ` data-target-full="${item.target_full}"` : '' %><%= item.project_slug ? ` data-project-slug="${item.project_slug}"` : '' %>>
30
+ <% } else if (item.target === "_blank" || item.popout) { %>
31
+ <a <%=item.default ? 'data-default' : ''%> data-confirm="<%=item.confirm%>" data-index="<%=index+4%>" target="<%=item.target%>" data-mode="<%=item.mode%>" href="<%=item.href%>" class='btn header-item frame-link <%=item.display || ""%>'<% if (item.popout) { %> data-popout-browser="true"<% } %><%- item.target_full ? ` data-target-full=${JSON.stringify(item.target_full)}` : '' %><%- item.project_slug ? ` data-project-slug=${JSON.stringify(item.project_slug)}` : '' %>>
32
32
  <div class='tab'><%-item.btn%></div>
33
- <div class='loader'>
34
- <i class="fa-solid fa-up-right-from-square"></i>
35
- </div>
33
+ <% if (!item.popout) { %>
34
+ <div class='loader'>
35
+ <i class="fa-solid fa-up-right-from-square"></i>
36
+ </div>
37
+ <% } %>
36
38
  </a>
37
39
  <% } else { %>
38
- <a <%=item.default ? 'data-default' : ''%> data-confirm="<%=item.confirm%>" data-index="<%=index+4%>" target="<%=item.target%>" data-mode="<%=item.mode%>" href="<%=item.href%>" class='btn header-item frame-link <%=item.display || ""%>'<%= item.target_full ? ` data-target-full="${item.target_full}"` : '' %> <%=item.shell_id ? `data-shell=${item.shell_id}` : ""%> <%=item.script_id ? `data-script=${item.script_id}` : ''%><%= item.project_slug ? ` data-project-slug="${item.project_slug}"` : '' %>>
40
+ <a <%=item.default ? 'data-default' : ''%> data-confirm="<%=item.confirm%>" data-index="<%=index+4%>" target="<%=item.target%>" data-mode="<%=item.mode%>" href="<%=item.href%>" class='btn header-item frame-link <%=item.display || ""%>'<%- item.target_full ? ` data-target-full=${JSON.stringify(item.target_full)}` : '' %> <%=item.shell_id ? `data-shell=${item.shell_id}` : ""%> <%=item.script_id ? `data-script=${item.script_id}` : ''%><%- item.project_slug ? ` data-project-slug=${JSON.stringify(item.project_slug)}` : '' %>>
39
41
  <% if (item.running) { %>
40
42
  <i class="fa-solid fa-circle"></i>
41
43
  <% } %>
@@ -39,18 +39,20 @@
39
39
  <i class="fa-solid fa-angle-right"></i>
40
40
  <% } %>
41
41
  </div>
42
- <% } else if (item.target === "_blank") { %>
43
- <a <%=item.default ? 'data-default' : ''%> data-confirm="<%=item.confirm%>" data-index="<%=index%>" target="<%=item.target%>" data-mode="<%=item.mode%>" href="<%=item.href%>" class='btn header-item frame-link <%=item.display || ""%>'<%= item.target_full ? ` data-target-full="${item.target_full}"` : '' %><%= item.project_slug ? ` data-project-slug="${item.project_slug}"` : '' %><%- item.inject ? ` data-pinokio-inject="${encodeURIComponent(JSON.stringify(item.inject))}"` : '' %>>
42
+ <% } else if (item.target === "_blank" || item.popout) { %>
43
+ <a <%=item.default ? 'data-default' : ''%> data-confirm="<%=item.confirm%>" data-index="<%=index%>" target="<%=item.target%>" data-mode="<%=item.mode%>" href="<%=item.href%>" class='btn header-item frame-link <%=item.display || ""%>'<% if (item.popout) { %> data-popout-browser="true"<% } %><%- item.target_full ? ` data-target-full=${JSON.stringify(item.target_full)}` : '' %><%- item.project_slug ? ` data-project-slug=${JSON.stringify(item.project_slug)}` : '' %><%- item.inject ? ` data-pinokio-inject="${encodeURIComponent(JSON.stringify(item.inject))}"` : '' %>>
44
44
  <div class='tab'><%-item.btn%></div>
45
45
  <% if (item.arrow) { %>
46
46
  <i class="fa-solid fa-angle-right"></i>
47
47
  <% } %>
48
- <div class='loader'>
49
- <i class="fa-solid fa-up-right-from-square"></i>
50
- </div>
48
+ <% if (!item.popout) { %>
49
+ <div class='loader'>
50
+ <i class="fa-solid fa-up-right-from-square"></i>
51
+ </div>
52
+ <% } %>
51
53
  </a>
52
54
  <% } else { %>
53
- <a <%=item.default ? 'data-default' : ''%> data-confirm="<%=item.confirm%>" data-index="<%=index%>" target="<%=item.target%>" data-mode="<%=item.mode%>" href="<%=item.href%>" class='btn header-item frame-link <%=item.display || ""%>'<%= item.target_full ? ` data-target-full="${item.target_full}"` : '' %> <%=item.shell_id ? `data-shell=${item.shell_id}` : ""%> <%=item.script_id ? `data-script=${item.script_id}` : ''%><%= item.project_slug ? ` data-project-slug="${item.project_slug}"` : '' %><%- item.inject ? ` data-pinokio-inject="${encodeURIComponent(JSON.stringify(item.inject))}"` : '' %>>
55
+ <a <%=item.default ? 'data-default' : ''%> data-confirm="<%=item.confirm%>" data-index="<%=index%>" target="<%=item.target%>" data-mode="<%=item.mode%>" href="<%=item.href%>" class='btn header-item frame-link <%=item.display || ""%>'<%- item.target_full ? ` data-target-full=${JSON.stringify(item.target_full)}` : '' %> <%=item.shell_id ? `data-shell=${item.shell_id}` : ""%> <%=item.script_id ? `data-script=${item.script_id}` : ''%><%- item.project_slug ? ` data-project-slug=${JSON.stringify(item.project_slug)}` : '' %><%- item.inject ? ` data-pinokio-inject="${encodeURIComponent(JSON.stringify(item.inject))}"` : '' %>>
54
56
  <% if (item.running) { %>
55
57
  <i class="fa-solid fa-circle"></i>
56
58
  <% } %>