diff --git a/nose/chris/pub/index.html b/nose/chris/pub/index.html index 578c6d7..08f70db 100644 --- a/nose/chris/pub/index.html +++ b/nose/chris/pub/index.html @@ -13,6 +13,9 @@

@defunkt

This is my website. I am Chris.

+

Other.html

+

corey

+

google

diff --git a/nose/chris/pub/other.html b/nose/chris/pub/other.html new file mode 100644 index 0000000..231a282 --- /dev/null +++ b/nose/chris/pub/other.html @@ -0,0 +1,4 @@ + +other +

other

+ \ No newline at end of file diff --git a/nose/ping/index.ts b/nose/ping/index.ts deleted file mode 100644 index 01816b7..0000000 --- a/nose/ping/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export default () => - "pong" \ No newline at end of file diff --git a/nose/ping/index.tsx b/nose/ping/index.tsx new file mode 100644 index 0000000..bec88b3 --- /dev/null +++ b/nose/ping/index.tsx @@ -0,0 +1,2 @@ +export default () => + pong pong - {Date.now()} \ No newline at end of file diff --git a/public/browser-nav.js b/public/browser-nav.js new file mode 100644 index 0000000..ee9afc4 --- /dev/null +++ b/public/browser-nav.js @@ -0,0 +1,96 @@ +// browser-nav.js - Injected into NOSE apps to get the UI browser working. +(function () { + const ALLOWED_DOMAINS = ['localhost', '.local', '.nose.space'] + + function isAllowedOrigin(url) { + try { + const urlObj = new URL(url, window.location.href) + return ALLOWED_DOMAINS.some(domain => + urlObj.hostname === domain || urlObj.hostname.endsWith(domain) + ) + } catch { + return false + } + } + + // Intercept navigation attempts + function interceptNavigation(e) { + const target = e.target.closest('a') + if (!target || !target.href) return + + // Allow relative URLs and hash links + if (target.getAttribute('href').startsWith('#')) return + if (target.getAttribute('href').startsWith('/')) return + + // Check if external + if (!isAllowedOrigin(target.href)) { + e.preventDefault() + + if (window.parent !== window) { + window.parent.postMessage({ + type: 'NAV_BLOCKED', + data: { url: target.href, reason: 'External domain not allowed' } + }, '*') + } else { + alert('Navigation to external sites is not allowed') + } + } + } + + // Listen for clicks on links + document.addEventListener('click', interceptNavigation, true) + + // Intercept programmatic navigation + const originalPushState = history.pushState + const originalReplaceState = history.replaceState + + history.pushState = function (state, title, url) { + if (url && !isAllowedOrigin(url)) { + if (window.parent !== window) { + window.parent.postMessage({ + type: 'NAV_BLOCKED', + data: { url, reason: 'External domain not allowed' } + }, '*') + } + return + } + return originalPushState.apply(this, arguments) + } + + history.replaceState = function (state, title, url) { + if (url && !isAllowedOrigin(url)) { + if (window.parent !== window) { + window.parent.postMessage({ + type: 'NAV_BLOCKED', + data: { url, reason: 'External domain not allowed' } + }, '*') + } + return + } + return originalReplaceState.apply(this, arguments) + } + + // Listen for navigation commands from parent + window.addEventListener('message', (event) => { + console.log(event) + if (event.data.type === 'NAV_COMMAND') { + switch (event.data.action) { + case 'back': history.back(); break + case 'forward': history.forward(); break + case 'reload': window.location.reload(); break + case 'stop': window.stop(); break + } + } + }) + + if (window.parent !== window) { + window.parent.postMessage({ type: 'NAV_READY' }, '*') + + window.addEventListener('popstate', () => { + window.parent.postMessage({ + type: 'URL_CHANGED', + data: { url: location.href } + }, '*') + }) + } +})() \ No newline at end of file diff --git a/src/css/browser.css b/src/css/browser.css new file mode 100644 index 0000000..353f149 --- /dev/null +++ b/src/css/browser.css @@ -0,0 +1,54 @@ +:root { + --browser-bar-height: 34px; +} + +iframe.browser { + display: block; + background-color: white; + z-index: 10; + border: none; + margin-top: var(--browser-bar-height); +} + +[data-mode="tall"] iframe.browser { + height: 100%; +} + +iframe:focus { + outline: none; +} + +.browser.active { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); +} + +#browser-controls { + position: absolute; + top: 0; + z-index: 15; + width: 100%; + height: var(--browser-bar-height); + background-color: var(--gray); +} + +#browser-controls span, +#browser-controls a { + display: inline-block; + margin-right: 10px; + padding: 5px; + background-color: var(--gray); + color: var(--c64-light-blue); + text-decoration: none; +} + +#forward-button { + transform: scaleX(-1); +} + +#close-button { + position: absolute; + right: -10; +} \ No newline at end of file diff --git a/src/css/main.css b/src/css/main.css index 3cca9cc..7d5fd89 100644 --- a/src/css/main.css +++ b/src/css/main.css @@ -16,6 +16,8 @@ --purple: #7C3AED; --blue: #1565C0; --magenta: #ff66cc; + --gray: #BEBEBE; + --grey: #BEBEBE; --c64-light-blue: #6C6FF6; --c64-dark-blue: #40318D; diff --git a/src/html/layout.tsx b/src/html/layout.tsx index 5401fbb..b7c5e83 100644 --- a/src/html/layout.tsx +++ b/src/html/layout.tsx @@ -11,6 +11,7 @@ export const Layout: FC = async ({ children, title }) => ( + diff --git a/src/html/terminal.tsx b/src/html/terminal.tsx index 9908d68..6216519 100644 --- a/src/html/terminal.tsx +++ b/src/html/terminal.tsx @@ -5,6 +5,15 @@ export const Terminal: FC = async () => ( + +
>