Create a responsive layout with a fixed main container using SiteOSController and SiteOSClient from the provided script.
by Rich Costello
HTML
<div id="shell">
<header id="header">
<h1>Caveon</h1>
</header>
<main id="main"></main>
</div>
CSS
*,
*::before,
*::after {
box-sizing: border-box;
}
html,
body {
height: 100%;
margin: 0;
padding: 0;
font-family: system-ui, sans-serif;
}
#shell {
position: fixed;
inset: 0;
display: flex;
flex-direction: column;
}
#header {
flex-shrink: 0;
padding: 0 1rem;
background: #1a1a2e;
color: #fff;
display: flex;
align-items: center;
height: 3rem;
}
#header h1 {
margin: 0;
font-size: 1.125rem;
font-weight: 600;
letter-spacing: 0.05em;
}
#main {
flex: 1;
min-height: 0;
position: relative;
}
/* SiteOS mounts an iframe into #main — make it fill the container */
#main iframe {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
border: none;
}
/* Tablet and up: add side gutters so the app doesn't stretch too wide */
@media (min-width: 768px) {
#shell {
max-width: 900px;
margin-inline: auto;
/* keep the fixed behaviour relative to the centred column */
left: 50%;
right: auto;
transform: translateX(-50%);
width: 100%;
box-shadow: 0 0 0 100vmax rgba(0, 0, 0, 0.08);
}
}
JavaScript
;(async () => {
const { SiteOSController, SiteOSClient } = await import('https://caveon-public.s3.amazonaws.com/sos/script.min.js') // https://github.com/Caveon-LLC/sos
// ---------------------------------------------------------------------------
// Controller — runs on the host page, mounts SiteOS into #main
// ---------------------------------------------------------------------------
const mainController = new SiteOSController('https://pub.caveon.com/interview_signup')
await mainController.launch('main')
const welcomeMessage = await mainController.request('welcome-message')
console.log(welcomeMessage)
// ---------------------------------------------------------------------------
// Client — runs inside the SiteOS iframe, handles requests from the controller
// ---------------------------------------------------------------------------
const client = new SiteOSClient()
client.on('welcome-message', async (promiseId) => {
const message = 'Welcome! Fork this fiddle and use it to get and decrypt the interview signup URL'
client.resolve(promiseId, message)
})
client.on('encrypted-url', async (x25519PublicKey, promiseId) => {
if (!promiseId) {
promiseId = x25519PublicKey
x25519PublicKey = null
}
if (!x25519PublicKey) {
console.log('No public key provided, generating random x25519 public key')
x25519PublicKey = await random25519PublicKeyB64()
}
const response = await fetch('/api/v1/interview_signup', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ x25519_public_key: x25519PublicKey })
})
const responseJson = await response.json()
client.resolve(promiseId, responseJson)
})
await client.propsReady()
//...