Captain Bob, 2026-11-07: build the .com from the StarshipOS.com canvas.
canvas/ holds the artboards as drawn; build.py makes Main, Inquiries and
TryIt as {{html}} pages (the wiki's links and domains, the images as
attachments, the real console in Try it, the forms by e-mail); install.sh
puts them on the wiki and checks a guest's view. Installed on
starshipos-f18.com: every page and image reads 200 as a guest, and renders
without a macro error.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
93 lines
5.6 KiB
Python
Executable File
93 lines
5.6 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""build.py -- the starshipos-f18.com XWiki pages, made from the "StarshipOS.com" design canvas.
|
|
|
|
site/com/build.py canvas/{Main,Inquiries,TryIt}.dc.html -> {Main,Inquiries,TryIt}.WebHome.xwiki
|
|
|
|
The canvas is the source: its artboards are copied into canvas/ as they are, and this turns each into
|
|
one {{html}} block (which needs a page author with script rights). What changes on the way:
|
|
|
|
- the accent hole becomes its default colour, and the canvas's links become the wiki's pages
|
|
(Main.dc.html -> /bin/view/Main/, ...) and the real domains (starshipos.org -> starshipos-f18.org);
|
|
- the two images become attachments of Main.WebHome (badge.jpg, captain-bob.jpg -- web-size copies
|
|
of the canvas's uploads);
|
|
- Try it: the drawn console becomes the real one, an iframe of try.starshipos-f18.com;
|
|
- the forms, which have no server behind them, send by e-mail (mailto:);
|
|
- a link the canvas left as a placeholder ([SSRN PAPER URL]) points at the .org until it is given.
|
|
|
|
install.sh puts the pages and the images on the wiki.
|
|
"""
|
|
import os
|
|
import re
|
|
|
|
ACCENT = "#F5891F"
|
|
FONTS = ('<link rel="preconnect" href="https://fonts.googleapis.com">\n'
|
|
'<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700'
|
|
'&family=Exo+2:wght@600;700&display=swap" rel="stylesheet">')
|
|
ORG = "https://starshipos-f18.org/"
|
|
PAGES = ["Main", "Inquiries", "TryIt"]
|
|
IMAGES = {"/_blob/5b564d54d98e02ad600c913a9a1888f2": "badge.jpg",
|
|
"/_blob/5483451f292782a8b366e437181c4bcf": "captain-bob.jpg"}
|
|
|
|
CONSOLE = '''<div style="background: #050A14; border: 1px solid #34486A; border-radius: 8px; overflow: hidden">
|
|
<div style="display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px; padding: 12px 20px; border-bottom: 1px solid #22324D; background: #0E182B; font-size: 13px; color: #A3AEC2">
|
|
<span style="display: flex; align-items: center; gap: 10px"><span aria-hidden="true" style="display: inline-block; width: 10px; height: 10px; border-radius: 50%; background: #4FD1B0"></span>StarshipOS · amd64 · your session</span>
|
|
<span>try.starshipos-f18.com</span>
|
|
</div>
|
|
<iframe src="https://try.starshipos-f18.com/" title="StarshipOS console" style="display: block; width: 100%; height: 30em; border: 0; background: #050A14"></iframe>
|
|
</div>
|
|
<p style="margin: 12px 0 0; font-size: 13px; color: #A3AEC2">If the console does not connect, every machine is in use: try again in a few minutes.</p>'''
|
|
|
|
|
|
def body(src):
|
|
m = re.search(r"<x-dc>(.*)</x-dc>", src, re.S)
|
|
html = re.sub(r"<helmet>.*?</helmet>", "", m.group(1), flags=re.S).strip()
|
|
html = html.replace("{{accent}}", ACCENT)
|
|
for p in PAGES:
|
|
html = html.replace('href="%s.dc.html"' % p, 'href="/bin/view/%s/"' % p)
|
|
html = html.replace('href="https://starshipos.org"', 'href="%s"' % ORG)
|
|
html = html.replace(">starshipos.org</a>", ">starshipos-f18.org</a>")
|
|
html = html.replace("on starshipos.org.", "on starshipos-f18.org.")
|
|
html = html.replace('href="[SSRN PAPER URL]"', 'href="%s"' % ORG)
|
|
for blob, name in IMAGES.items():
|
|
html = html.replace('src="%s"' % blob, 'src="/bin/download/Main/WebHome/%s"' % name)
|
|
html = html.replace("min-height: 100vh", "min-height: 0") # inside the wiki's page, not a screen
|
|
return html
|
|
|
|
|
|
def try_it(html):
|
|
start = html.index('<div style="background: #050A14')
|
|
end = html.index("</p>", html.index("[LIVE CONSOLE]")) + len("</p>")
|
|
return html[:start] + CONSOLE + html[end:]
|
|
|
|
|
|
def forms(html, page):
|
|
if page == "Main":
|
|
html = html.replace('<form style="flex: 1 1 420px; display: flex; flex-wrap: wrap; gap: 12px" aria-label="Subscribe to announcements">',
|
|
'<form action="mailto:info@starshipos.com?subject=Subscribe%20to%20launch%20announcements" method="post" enctype="text/plain" style="flex: 1 1 420px; display: flex; flex-wrap: wrap; gap: 12px" aria-label="Subscribe to announcements">')
|
|
html = html.replace('<input id="sub-email" type="email"', '<input id="sub-email" name="email" type="email" required')
|
|
html = html.replace('<button type="button" style="min-height: 48px; padding: 0 24px',
|
|
'<button type="submit" style="min-height: 48px; padding: 0 24px')
|
|
if page == "Inquiries":
|
|
html = html.replace('<form aria-label="Inquiry form"',
|
|
'<form action="mailto:info@starshipos.com?subject=StarshipOS%20inquiry" method="post" enctype="text/plain" aria-label="Inquiry form"')
|
|
for i, n in (("q-name", "name"), ("q-email", "email"), ("q-org", "organization"), ("q-topic", "topic"),
|
|
("q-msg", "message"), ("q-list", "announcements")):
|
|
html = html.replace('id="%s"' % i, 'id="%s" name="%s"' % (i, n), 1)
|
|
html = html.replace('<button type="button" style="min-height: 48px; padding: 0 28px',
|
|
'<button type="submit" style="min-height: 48px; padding: 0 28px')
|
|
html = html.replace("Replies usually within a few days.",
|
|
"Opens your e-mail program. Replies usually within a few days.")
|
|
return html
|
|
|
|
|
|
if __name__ == "__main__":
|
|
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
|
for p in PAGES:
|
|
html = forms(body(open("canvas/%s.dc.html" % p).read()), p)
|
|
if p == "TryIt":
|
|
html = try_it(html)
|
|
assert "{{" not in html and "[SSRN" not in html and ".dc.html" not in html and "_blob" not in html, p
|
|
with open("%s.WebHome.xwiki" % p, "w") as f:
|
|
f.write('{{html clean="false"}}\n%s\n%s\n{{/html}}\n' % (FONTS, html))
|
|
print("wrote", ", ".join("%s.WebHome.xwiki" % p for p in PAGES))
|