Nucleic-Session: 70972BA4-18A4-4077-AFC2-9CD7F5873D2F Co-authored-by: Nucleic <[email protected]>
461 lines
25 KiB
HTML
461 lines
25 KiB
HTML
<!doctype html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
<title>Nucleic — iPhone cockpit mock (faithful web port of the iOS app)</title>
|
||
<!-- Self-hosted fonts (latin subset). The woff2 binaries live in fonts/ and are
|
||
preloaded so they download in parallel with the HTML; @font-face is inlined
|
||
(no render-blocking stylesheet) and the page never contacts Google. -->
|
||
<link rel="preload" href="fonts/space-grotesk.woff2" as="font" type="font/woff2" crossorigin />
|
||
<link rel="preload" href="fonts/jetbrains-mono.woff2" as="font" type="font/woff2" crossorigin />
|
||
<style>
|
||
@font-face{font-family:'Space Grotesk';font-style:normal;font-weight:400 700;font-display:swap;src:url(fonts/space-grotesk.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||
@font-face{font-family:'JetBrains Mono';font-style:normal;font-weight:400 500;font-display:swap;src:url(fonts/jetbrains-mono.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||
</style>
|
||
|
||
<!--
|
||
============================================================================
|
||
NUCLEIC iPHONE COCKPIT — web-compatible port of the iOS app (NucleicRemote)
|
||
============================================================================
|
||
|
||
FOR THE WEBSITE AGENT
|
||
Self-contained, previewable port of Nucleic's *phone* interface — the iOS
|
||
app's Home tab. It is the mobile counterpart to website/cockpit.html (the Mac
|
||
cockpit): where that shows the desktop home + Control sidebar, this shows the
|
||
phone the app actually ships, so the site can swap the wide Mac window for the
|
||
app surface on small screens.
|
||
|
||
NO DEVICE FRAME. Because this renders ON a phone, drawing a phone around it
|
||
would be a phone-in-a-phone. So there is no bezel, no status bar (clock /
|
||
signal / wifi / battery), no Dynamic Island, no home indicator — only the app's
|
||
own chrome (the tab bar and the connection chip). The app content sits in a
|
||
clean, borderless surface framed like the desktop cockpit: a rounded card with a
|
||
hairline border and soft shadow. Internal scrolling is locked — the card sizes to
|
||
its content and the page scrolls.
|
||
|
||
GROUNDED IN THE iOS SOURCE (ios/NucleicRemote/NucleicRemote):
|
||
• RootView (NucleicRemoteApp.swift) — the 5-tab bar: Home · Sessions ·
|
||
Projects · To-dos · Settings, tinted with Palette.accent (teal). Sessions
|
||
carries .badge(needsYouCount).
|
||
• HomeView.swift — greeting (time-of-day) + StreakBadge, the five StatCards
|
||
(Projects / In progress / Active / Messages / Tokens), the GitHub-style
|
||
ActivityGrid in a card, the InProgressSessions card, then QuickTodos and
|
||
StartChatComposer. navigationTitle("Home"), inline.
|
||
• SessionRow (SessionsView.swift) — status symbol+color, title + project,
|
||
trailing pending-approval pill / diffstat.
|
||
• Composer.swift — QuickTodos (capture field + idea rows) and
|
||
StartChatComposer (project + Auto, model + effort, prompt + send).
|
||
• ConnectionChip.swift — the floating "Connected · LAN" capsule pinned to the
|
||
bottom safe area above the tab bar.
|
||
• Theme.swift — Palette (teal accent, blue/amber/green/purple status,
|
||
frozen blue, orchestra gold) and StatusStyle (symbol/label per status).
|
||
|
||
CONTENT mirrors the app's offline preview seed (RemoteStore.seedDemo, used for
|
||
NUCLEIC_DEMO UI previews) so every number, title, and status is real app data:
|
||
host "Andrew's Mac"; 2 projects (nucleic, website); 5 chats, 2 active, 142
|
||
messages, 1.28M tokens; the running "flaky-tests" chat; three captured ideas.
|
||
|
||
THEME: the app adapts to the system; this port is pinned to iOS LIGHT mode —
|
||
systemBackground white, secondarySystemBackground (#f2f2f7) cards with a
|
||
primary-6% hairline, the iOS semantic label tiers, and the exact Palette sRGB
|
||
values from Theme.swift. It uses the phone's TEAL accent (Palette.accent),
|
||
not the Mac cockpit's violet Control accent — this is the product on a phone.
|
||
|
||
HOW TO COPY IT IN (three regions, all scoped under `.nuc-ios`, no collisions):
|
||
1. Copy the contents of <style data-nuc-ios> … </style> into the site's <style>.
|
||
2. Drop the <div class="nuc-ios"> … </div> markup wherever the phone should show.
|
||
3. Copy the <script data-nuc-ios> … </script> block before </body> (it sizes the
|
||
activity grid to its column, like the app's GeometryReader; idempotent + guarded).
|
||
|
||
TO REPLACE THE MAC COCKPIT ON MOBILE (in website/index.html — do NOT edit it from
|
||
here; this is just the recipe). The Mac window lives at `.showcase .nuc-cockpit`.
|
||
Put the phone next to it and let one CSS breakpoint trade them:
|
||
.nuc-ios{ display:none } /* desktop: phone hidden */
|
||
@media (max-width:860px){
|
||
.showcase .nuc-cockpit{ display:none } /* mobile: hide the Mac window */
|
||
.nuc-ios{ display:flex } /* …show the phone instead */
|
||
}
|
||
860px is the same breakpoint cockpit.html already uses to drop its sidebar.
|
||
|
||
Everything is namespaced under `.nuc-ios` with its own CSS variables, so it
|
||
neither reads from nor pollutes the site's :root tokens.
|
||
============================================================================
|
||
-->
|
||
|
||
<style data-nuc-ios>
|
||
/* ===== Nucleic iPhone cockpit — scoped, iOS light mode, Home tab ============ */
|
||
.nuc-ios{
|
||
/* Surfaces — iOS light system colors (UX_IOS / Theme.swift CardBackground) */
|
||
--bg:#ffffff; /* systemBackground — the Home ScrollView */
|
||
--card:#f2f2f7; /* secondarySystemBackground — .card() surfaces */
|
||
--field:#ffffff; /* .roundedBorder text field fill */
|
||
--hair:rgba(0,0,0,.07); /* Color.primary.opacity(.06) card hairline */
|
||
--field-hair:rgba(0,0,0,.16);
|
||
--tabbar:rgba(249,249,249,.94);
|
||
|
||
/* Text — iOS semantic label tiers (light) */
|
||
--label:#000000; /* UIColor.label */
|
||
--label2:rgba(60,60,67,.6); /* secondaryLabel */
|
||
--label3:rgba(60,60,67,.3); /* tertiaryLabel */
|
||
--tab-off:#999a9f; /* unselected tab item */
|
||
|
||
/* Palette.swift — the mobile categorical palette (exact sRGB) */
|
||
--accent:#0a8580; /* deep teal — Palette.accent (.04,.52,.50) */
|
||
--active:#338cf2; /* blue — running (.20,.55,.95) */
|
||
--attention:#ffa626;/* amber — awaiting approval (1,.65,.15) */
|
||
--success:#4dcc73; /* green — finished/done (.30,.80,.45) */
|
||
--paused:#9e7ded; /* purple — interrupted (.62,.49,.93) */
|
||
--danger:#eb5757; /* red — error / badge (.92,.34,.34) */
|
||
--frozen:#42a3f5; /* iced streak-freeze blue (.26,.64,.96) */
|
||
--orchestra:#e6a829;/* orchestra gold (.90,.66,.16) */
|
||
|
||
/* ActivityGrid shades — Palette.activity(intensity): success.opacity(i),
|
||
empty = secondary.opacity(.15) */
|
||
--a0:#e3e3e8;
|
||
--a1:rgba(77,204,115,.4);
|
||
--a2:rgba(77,204,115,.65);
|
||
--a3:rgba(77,204,115,.82);
|
||
--a4:#4dcc73;
|
||
|
||
--mono:"JetBrains Mono", ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
|
||
|
||
/* surface geometry — a borderless app card (no device frame); sizes to its
|
||
content with scrolling locked (the page scrolls); fits any viewport (max-width:100%) */
|
||
--w:360px;
|
||
|
||
font-family:-apple-system, BlinkMacSystemFont, "SF Pro Text", "Helvetica Neue", system-ui, "Space Grotesk", Arial, sans-serif;
|
||
color:var(--label);
|
||
display:flex;justify-content:center;
|
||
/* illustrative chrome — keep its text unselectable */
|
||
-webkit-user-select:none;user-select:none;
|
||
}
|
||
.nuc-ios *{box-sizing:border-box}
|
||
.nuc-ios svg{display:block}
|
||
|
||
/* ---- borderless app surface (framed like the desktop cockpit — no device
|
||
bezel, status bar, Dynamic Island, or home indicator; this already renders
|
||
on a phone) ------------------------------------------------------------- */
|
||
.nuc-ios .ios-phone{
|
||
position:relative;
|
||
width:var(--w);max-width:100%; /* height: natural (content-sized) */
|
||
display:flex;flex-direction:column;
|
||
background:var(--bg);
|
||
border:1px solid var(--hair);
|
||
border-radius:16px;overflow:hidden;
|
||
box-shadow:0 1px 0 rgba(255,255,255,.7) inset,
|
||
0 30px 70px -40px rgba(40,30,50,.40);
|
||
}
|
||
|
||
/* ---- Home content (no title bar — content starts at the top; scrolling locked,
|
||
the surface sizes to its content and the page scrolls) --------------------- */
|
||
.nuc-ios .ios-content{
|
||
padding:22px 16px 120px; /* bottom room for the chip + tab bar */
|
||
display:flex;flex-direction:column;gap:22px;
|
||
}
|
||
|
||
/* greeting + streak (HomeView header HStack) */
|
||
.nuc-ios .ios-hi{display:flex;align-items:flex-start;justify-content:space-between;gap:10px}
|
||
.nuc-ios .ios-hi h1{margin:0;font-size:27px;font-weight:700;letter-spacing:-.02em;line-height:1.05}
|
||
.nuc-ios .ios-hi .sub{margin:5px 0 0;font-size:14px;color:var(--label2)}
|
||
.nuc-ios .ios-streak{
|
||
flex:none;display:inline-flex;align-items:center;gap:7px;
|
||
background:var(--card);border-radius:999px;padding:7px 11px;
|
||
}
|
||
.nuc-ios .ios-streak .bolt{color:var(--frozen);filter:drop-shadow(0 0 4px rgba(66,163,245,.5))}
|
||
.nuc-ios .ios-streak .col{display:flex;flex-direction:column;line-height:1}
|
||
.nuc-ios .ios-streak .n{font-size:16px;font-weight:600;font-variant-numeric:tabular-nums}
|
||
.nuc-ios .ios-streak .lbl{font-size:10px;color:var(--label2);margin-top:2px}
|
||
.nuc-ios .ios-streak .fz{display:inline-flex;align-items:center;gap:2px;color:var(--frozen);font-size:12px;font-weight:600}
|
||
.nuc-ios .ios-streak .fz svg{width:12px;height:12px}
|
||
|
||
/* StatCard row — five across, like HomeView.statCards (tight at phone width,
|
||
exactly as the app is; labels wrap like SwiftUI Text, value never wraps) */
|
||
.nuc-ios .ios-stats{display:flex;gap:7px;align-items:stretch}
|
||
.nuc-ios .ios-stat{
|
||
flex:1 1 0;min-width:0;
|
||
background:var(--card);border:1px solid var(--hair);border-radius:13px;
|
||
padding:8px 7px;display:flex;flex-direction:column;gap:3px;
|
||
}
|
||
.nuc-ios .ios-stat .ic{color:var(--accent)}
|
||
.nuc-ios .ios-stat .ic svg{width:15px;height:15px}
|
||
.nuc-ios .ios-stat .n{font-size:15px;font-weight:600;font-family:var(--mono);letter-spacing:-.03em;white-space:nowrap}
|
||
.nuc-ios .ios-stat .l{font-size:9.5px;line-height:1.12;color:var(--label2);overflow-wrap:break-word}
|
||
|
||
/* a .card() block (CardBackground modifier) */
|
||
.nuc-ios .ios-card{background:var(--card);border:1px solid var(--hair);border-radius:14px;padding:14px}
|
||
.nuc-ios .ios-card-h{display:flex;align-items:center;justify-content:space-between;margin-bottom:10px}
|
||
.nuc-ios .ios-card-h .h{font-size:16px;font-weight:600;letter-spacing:-.01em}
|
||
.nuc-ios .ios-card-h .cnt{font-size:15px;color:var(--label2);font-variant-numeric:tabular-nums}
|
||
|
||
/* ActivityGrid (no legend on iOS — just the grid) */
|
||
.nuc-ios .ios-grid{display:flex;gap:3px;flex-wrap:nowrap;overflow:hidden}
|
||
.nuc-ios .ios-grid .col{display:flex;flex-direction:column;gap:3px}
|
||
.nuc-ios .ios-grid i{width:13px;height:13px;border-radius:2px;background:var(--a0);display:block}
|
||
.nuc-ios .ios-grid i.l1{background:var(--a1)} .nuc-ios .ios-grid i.l2{background:var(--a2)}
|
||
.nuc-ios .ios-grid i.l3{background:var(--a3)} .nuc-ios .ios-grid i.l4{background:var(--a4)}
|
||
.nuc-ios .ios-grid i.fz{background:var(--frozen)}
|
||
|
||
/* SessionRow */
|
||
.nuc-ios .ios-srow{display:flex;align-items:center;gap:12px;padding:3px 0}
|
||
.nuc-ios .ios-srow .sym{width:24px;flex:none;display:flex;justify-content:center}
|
||
.nuc-ios .ios-srow .sym svg{width:21px;height:21px}
|
||
.nuc-ios .ios-srow .sc{flex:1;min-width:0}
|
||
.nuc-ios .ios-srow .st{font-size:16px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
||
.nuc-ios .ios-srow .sp{font-size:12px;color:var(--label2);margin-top:1px}
|
||
.nuc-ios .ios-srow .diff{font-size:12px;font-family:var(--mono);color:var(--label2);flex:none}
|
||
|
||
/* QuickTodos */
|
||
.nuc-ios .ios-capture{display:flex;align-items:center;gap:10px;margin-bottom:10px}
|
||
.nuc-ios .ios-input{
|
||
flex:1;min-width:0;background:var(--field);border:1px solid var(--field-hair);border-radius:8px;
|
||
padding:8px 11px;font-size:14px;color:var(--label3);
|
||
}
|
||
.nuc-ios .ios-addbtn{color:var(--accent);flex:none;display:flex}
|
||
.nuc-ios .ios-addbtn svg{width:24px;height:24px}
|
||
.nuc-ios .ios-todo{display:flex;align-items:center;gap:10px;padding:6px 0}
|
||
.nuc-ios .ios-todo .box{color:var(--label3);flex:none;display:flex}
|
||
.nuc-ios .ios-todo .box svg{width:18px;height:18px}
|
||
.nuc-ios .ios-todo .tt{flex:1;min-width:0;font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
||
.nuc-ios .ios-todo .pn{font-size:11px;color:var(--label2);flex:none}
|
||
|
||
/* StartChatComposer */
|
||
.nuc-ios .ios-comp-row{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:10px}
|
||
.nuc-ios .ios-menu{display:inline-flex;align-items:center;gap:5px;font-size:14px;color:var(--label)}
|
||
.nuc-ios .ios-menu svg{width:15px;height:15px;color:var(--label2)}
|
||
.nuc-ios .ios-tint{display:inline-flex;align-items:center;gap:4px;font-size:13px;color:var(--accent);font-weight:500}
|
||
.nuc-ios .ios-tint svg{width:14px;height:14px}
|
||
.nuc-ios .ios-tint .badge{color:var(--label3);font-weight:400}
|
||
.nuc-ios .ios-auto{
|
||
display:inline-flex;align-items:center;gap:5px;font-size:13px;color:var(--label2);
|
||
border:1px solid var(--field-hair);border-radius:8px;padding:5px 9px;font-weight:500;
|
||
}
|
||
.nuc-ios .ios-auto svg{width:14px;height:14px}
|
||
.nuc-ios .ios-comp-field{display:flex;align-items:flex-end;gap:8px}
|
||
.nuc-ios .ios-comp-field .ios-input{padding:10px 12px;font-size:15px}
|
||
.nuc-ios .ios-send{color:var(--accent);flex:none;display:flex}
|
||
.nuc-ios .ios-send svg{width:30px;height:30px}
|
||
|
||
/* ConnectionChip — floating, pinned above the tab bar */
|
||
.nuc-ios .ios-chip{
|
||
position:absolute;left:50%;bottom:72px;transform:translateX(-50%);z-index:5;
|
||
display:inline-flex;align-items:center;gap:6px;
|
||
background:rgba(255,255,255,.74);
|
||
-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);
|
||
border:1px solid var(--hair);border-radius:999px;padding:6px 12px;
|
||
font-size:13px;font-weight:500;color:var(--label);
|
||
box-shadow:0 6px 18px -10px rgba(0,0,0,.35);
|
||
}
|
||
.nuc-ios .ios-chip .dot{width:8px;height:8px;border-radius:50%;background:#34c759}
|
||
|
||
/* ---- tab bar (RootView TabView) ------------------------------------------- */
|
||
.nuc-ios .ios-tabbar{
|
||
position:absolute;left:0;right:0;bottom:0;z-index:4;
|
||
display:flex;align-items:center;padding:6px 6px;height:60px;
|
||
background:var(--tabbar);
|
||
-webkit-backdrop-filter:blur(18px);backdrop-filter:blur(18px);
|
||
border-top:1px solid var(--hair);
|
||
}
|
||
.nuc-ios .ios-tab{
|
||
flex:1;display:flex;flex-direction:column;align-items:center;gap:3px;
|
||
color:var(--tab-off);position:relative;
|
||
}
|
||
.nuc-ios .ios-tab svg{width:25px;height:25px}
|
||
.nuc-ios .ios-tab .tl{font-size:10px;font-weight:500;letter-spacing:.01em}
|
||
.nuc-ios .ios-tab.on{color:var(--accent)}
|
||
.nuc-ios .ios-tab .tbadge{
|
||
position:absolute;top:-3px;left:calc(50% + 7px);
|
||
min-width:16px;height:16px;padding:0 4px;border-radius:999px;
|
||
background:var(--danger);color:#fff;font-size:10px;font-weight:700;
|
||
display:flex;align-items:center;justify-content:center;font-variant-numeric:tabular-nums;
|
||
}
|
||
</style>
|
||
</head>
|
||
|
||
<body style="margin:0;background:#faf7f3;background-image:radial-gradient(#e6ded4 1px,transparent 1px);background-size:26px 26px;background-position:-13px -13px;padding:48px 20px;font-family:'Space Grotesk',-apple-system,sans-serif;">
|
||
<div style="max-width:520px;margin:0 auto;">
|
||
|
||
<!-- ===== COPY FROM HERE: iPhone cockpit markup =============================== -->
|
||
<div class="nuc-ios" aria-label="The Nucleic iPhone app — Home tab">
|
||
<div class="ios-phone">
|
||
|
||
<!-- Home content (HomeView) -->
|
||
<div class="ios-content">
|
||
|
||
<!-- greeting + StreakBadge -->
|
||
<div class="ios-hi">
|
||
<div>
|
||
<h1>Good morning</h1>
|
||
<p class="sub">2 active of 5 chats · 2 projects</p>
|
||
</div>
|
||
<span class="ios-streak">
|
||
<svg class="bolt" width="20" height="20" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M13 2 4 14h6l-1 8 9-12h-6z"/></svg>
|
||
<span class="col"><span class="n">15</span><span class="lbl">day streak</span></span>
|
||
<span class="fz">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"><path d="M12 2v20M3.5 7l17 10M20.5 7l-17 10"/><path d="M12 6l2.2-2.2M12 6 9.8 3.8M12 18l2.2 2.2M12 18l-2.2 2.2"/></svg>
|
||
1
|
||
</span>
|
||
</span>
|
||
</div>
|
||
|
||
<!-- five StatCards -->
|
||
<div class="ios-stats">
|
||
<div class="ios-stat">
|
||
<span class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><path d="M3 7a2 2 0 0 1 2-2h3.5l2 2H19a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/></svg></span>
|
||
<span class="n">2</span><span class="l">Projects</span>
|
||
</div>
|
||
<div class="ios-stat">
|
||
<span class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7"><circle cx="12" cy="12" r="9"/><path d="M12 3a9 9 0 0 0 0 18z" fill="currentColor" stroke="none"/></svg></span>
|
||
<span class="n">1</span><span class="l">In progress</span>
|
||
</div>
|
||
<div class="ios-stat">
|
||
<span class="ic"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M13 2 4 14h6l-1 8 9-12h-6z"/></svg></span>
|
||
<span class="n">2</span><span class="l">Active</span>
|
||
</div>
|
||
<div class="ios-stat">
|
||
<span class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linejoin="round"><path d="M21 3 10 14M21 3l-7 18-4-7-7-4z"/></svg></span>
|
||
<span class="n">142</span><span class="l">Messages</span>
|
||
</div>
|
||
<div class="ios-stat">
|
||
<span class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"><path d="M4 8h7M4 12h11M4 16h6"/></svg></span>
|
||
<span class="n">1.3M</span><span class="l">Tokens</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Activity card -->
|
||
<div class="ios-card">
|
||
<div class="ios-card-h"><span class="h">Activity</span></div>
|
||
<div class="ios-grid" aria-hidden="true"><!-- cells injected by the scoped script --></div>
|
||
</div>
|
||
|
||
<!-- In progress card -->
|
||
<div class="ios-card">
|
||
<div class="ios-card-h"><span class="h">In progress</span><span class="cnt">1</span></div>
|
||
<div class="ios-srow">
|
||
<span class="sym" style="color:var(--active)">
|
||
<!-- circle.lefthalf.filled (running) -->
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7"><circle cx="12" cy="12" r="9"/><path d="M12 3a9 9 0 0 0 0 18z" fill="currentColor" stroke="none"/></svg>
|
||
</span>
|
||
<span class="sc"><div class="st">flaky-tests</div><div class="sp">nucleic</div></span>
|
||
<span class="diff">+88/−12</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- To-dos card (QuickTodos) -->
|
||
<div class="ios-card">
|
||
<div class="ios-card-h"><span class="h">To-dos</span><span class="cnt">3</span></div>
|
||
<div class="ios-capture">
|
||
<span class="ios-input">Capture an idea…</span>
|
||
<span class="ios-addbtn"><svg viewBox="0 0 24 24" fill="currentColor"><circle cx="12" cy="12" r="10"/><path d="M12 8v8M8 12h8" fill="none" stroke="#fff" stroke-width="1.8" stroke-linecap="round"/></svg></span>
|
||
</div>
|
||
<div class="ios-todo">
|
||
<span class="box"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7"><circle cx="12" cy="12" r="9"/></svg></span>
|
||
<span class="tt">Dark mode in settings</span>
|
||
<span class="pn">website</span>
|
||
</div>
|
||
<div class="ios-todo">
|
||
<span class="box"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7"><circle cx="12" cy="12" r="9"/></svg></span>
|
||
<span class="tt">Sync server memory leak</span>
|
||
<span class="pn">nucleic</span>
|
||
</div>
|
||
<div class="ios-todo">
|
||
<span class="box"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7"><circle cx="12" cy="12" r="9"/></svg></span>
|
||
<span class="tt">Write release notes</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- New chat composer (StartChatComposer) -->
|
||
<div class="ios-card">
|
||
<div class="ios-card-h"><span class="h">New chat</span></div>
|
||
<div class="ios-comp-row">
|
||
<span class="ios-menu"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><path d="M3 7a2 2 0 0 1 2-2h3.5l2 2H19a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/></svg>nucleic</span>
|
||
<span class="ios-auto"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"><path d="M13 2 4 14h6l-1 8 9-12h-6z"/><path d="M3 3l18 18"/></svg>Auto</span>
|
||
</div>
|
||
<div class="ios-comp-row">
|
||
<span class="ios-tint"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><rect x="4" y="4" width="16" height="16" rx="2"/><rect x="8.5" y="8.5" width="7" height="7" rx="1"/><path d="M9 1.5v2.5M15 1.5v2.5M9 20v2.5M15 20v2.5M1.5 9H4M1.5 15H4M20 9h2.5M20 15h2.5"/></svg>Default model</span>
|
||
<span class="ios-tint"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"><path d="M4 6h10M18 6h2M4 12h2M10 12h10M4 18h8M16 18h4"/><circle cx="16" cy="6" r="2.2" fill="#fff"/><circle cx="8" cy="12" r="2.2" fill="#fff"/><circle cx="14" cy="18" r="2.2" fill="#fff"/></svg>high</span>
|
||
</div>
|
||
<div class="ios-comp-field">
|
||
<span class="ios-input">Describe a task…</span>
|
||
<span class="ios-send"><svg viewBox="0 0 24 24" fill="currentColor"><circle cx="12" cy="12" r="11"/><path d="M12 17V8M8 11l4-4 4 4" fill="none" stroke="#fff" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"/></svg></span>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<!-- ConnectionChip -->
|
||
<span class="ios-chip"><span class="dot"></span>Connected · LAN</span>
|
||
|
||
<!-- tab bar -->
|
||
<nav class="ios-tabbar">
|
||
<span class="ios-tab on">
|
||
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M3 11.2 12 4l9 7.2V20a1.4 1.4 0 0 1-1.4 1.4h-4.1V15h-3v6.4H4.4A1.4 1.4 0 0 1 3 20z"/></svg>
|
||
<span class="tl">Home</span>
|
||
</span>
|
||
<span class="ios-tab">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round"><path d="M4 9.5 12 6l8 3.5-8 3.5z"/><path d="M5 13l7 3 7-3M5 16.5l7 3 7-3"/></svg>
|
||
<span class="tl">Sessions</span>
|
||
<span class="tbadge">2</span>
|
||
</span>
|
||
<span class="ios-tab">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7"><path d="M3 7a2 2 0 0 1 2-2h3.5l2 2H19a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/></svg>
|
||
<span class="tl">Projects</span>
|
||
</span>
|
||
<span class="ios-tab">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M4 6l1.6 1.6L8.5 4.7M11 6h9M4 12l1.6 1.6L8.5 10.7M11 12h9M4 18l1.6 1.6L8.5 16.7M11 18h9"/></svg>
|
||
<span class="tl">To-dos</span>
|
||
</span>
|
||
<span class="ios-tab">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="12" cy="12" r="3.2"/><path d="M12 2.5v3M12 18.5v3M2.5 12h3M18.5 12h3M5.2 5.2l2.1 2.1M16.7 16.7l2.1 2.1M18.8 5.2l-2.1 2.1M7.3 16.7l-2.1 2.1"/></svg>
|
||
<span class="tl">Settings</span>
|
||
</span>
|
||
</nav>
|
||
</div>
|
||
</div>
|
||
<!-- ===== COPY TO HERE ======================================================= -->
|
||
|
||
<p style="text-align:center;margin:22px 0 0;font-family:'JetBrains Mono',monospace;font-size:12px;color:#8b8590">The Nucleic iPhone app — Home tab. Mobile counterpart to the Mac cockpit. Illustrative.</p>
|
||
</div>
|
||
|
||
<!-- ===== COPY: scoped script that paints the activity grid (once, fixed width) ===== -->
|
||
<script data-nuc-ios>
|
||
(function () {
|
||
// Paint the activity grid ONCE with a fixed column count sized to the 360px
|
||
// card — no live width measuring and no resize rebuild, so it never reflows or
|
||
// "jumps" on load. Deterministic (seeded); recent weeks (right) trend busier,
|
||
// with two streak-freeze cells in the iced blue. The grid's overflow:hidden
|
||
// clips the rightmost column gracefully on phones narrower than the card.
|
||
var COLS = 19, ROWS = 7;
|
||
function build(grid) {
|
||
grid.textContent = '';
|
||
var seed = 20260629;
|
||
function rnd() { seed = (seed * 1103515245 + 12345) & 0x7fffffff; return seed / 0x7fffffff; }
|
||
var frozen = {};
|
||
frozen[(COLS - 7) + ',2'] = 1;
|
||
frozen[(COLS - 3) + ',5'] = 1;
|
||
for (var c = 0; c < COLS; c++) {
|
||
var col = document.createElement('div');
|
||
col.className = 'col';
|
||
var recency = c / (COLS - 1);
|
||
for (var r = 0; r < ROWS; r++) {
|
||
var i = document.createElement('i');
|
||
if (frozen[c + ',' + r]) {
|
||
i.className = 'fz';
|
||
} else {
|
||
var p = rnd() * 0.55 + recency * 0.6;
|
||
var lvl = p < 0.3 ? 0 : p < 0.52 ? 1 : p < 0.73 ? 2 : p < 0.9 ? 3 : 4;
|
||
if (lvl) i.className = 'l' + lvl;
|
||
}
|
||
col.appendChild(i);
|
||
}
|
||
grid.appendChild(col);
|
||
}
|
||
}
|
||
function fill() { document.querySelectorAll('.nuc-ios .ios-grid').forEach(build); }
|
||
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', fill);
|
||
else fill();
|
||
})();
|
||
</script>
|
||
</body>
|
||
</html>
|