Files
wehub-resource-sync 070959e133
landing-page-staging / Deploy landing page to staging (push) Has been skipped
landing-page-ci / Validate landing page (push) Failing after 4s
visual-baseline / Capture visual baselines (push) Has been cancelled
bake-plugin-previews / Bake plugin previews (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:00:47 +08:00

180 lines
5.6 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<!--
Shared frame: iPhone 15 Pro (390 × 844).
Usage: <iframe src="iphone-15-pro.html?screen=path/to/screen.html"></iframe>
Renders: the bezel + Dynamic Island + status bar + home indicator,
with the ?screen content embedded as an iframe in the screen area.
-->
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>iPhone 15 Pro frame</title>
<style>
*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; height: 100%; background: transparent; }
body {
display: grid;
place-items: center;
font: 15px/1.4 -apple-system, BlinkMacSystemFont, 'SF Pro Text', system-ui, sans-serif;
color: #1a1916;
-webkit-font-smoothing: antialiased;
}
.device {
position: relative;
width: 390px;
height: 844px;
border-radius: 56px;
padding: 12px;
background:
linear-gradient(160deg, #2a2a2c 0%, #1a1a1c 50%, #0e0e10 100%);
box-shadow:
0 0 0 1px rgba(255,255,255,0.04) inset,
0 0 0 2px #000 inset,
0 28px 60px -12px rgba(0,0,0,0.45),
0 8px 20px -8px rgba(0,0,0,0.35);
isolation: isolate;
}
.device::before, .device::after {
content: '';
position: absolute;
width: 3px;
background: linear-gradient(to bottom, transparent 0%, rgba(255,255,255,0.06) 8%, transparent 16%, transparent 84%, rgba(255,255,255,0.04) 92%, transparent 100%);
top: 100px;
bottom: 100px;
pointer-events: none;
}
.device::before { left: -1px; }
.device::after { right: -1px; }
.island {
position: absolute;
top: 22px;
left: 50%;
transform: translateX(-50%);
width: 124px;
height: 36px;
background: #000;
border-radius: 999px;
z-index: 5;
}
.btn-rail {
position: absolute;
width: 4px;
background: #0a0a0c;
border-radius: 2px;
}
.btn-rail.left-1 { left: -3px; top: 174px; height: 32px; }
.btn-rail.left-2 { left: -3px; top: 220px; height: 60px; }
.btn-rail.left-3 { left: -3px; top: 290px; height: 60px; }
.btn-rail.right-1 { right: -3px; top: 250px; height: 100px; }
.screen {
position: relative;
width: 100%; height: 100%;
background: #fafaf7;
border-radius: 44px;
overflow: hidden;
display: flex;
flex-direction: column;
}
.statusbar {
flex: 0 0 47px;
padding: 18px 26px 0;
display: flex;
align-items: flex-start;
justify-content: space-between;
font-size: 15px;
font-weight: 600;
letter-spacing: -0.01em;
color: var(--statusbar-fg, #1a1916);
pointer-events: none;
}
.statusbar .right { display: inline-flex; align-items: center; gap: 6px; }
.statusbar svg { width: 17px; height: 11px; fill: currentColor; }
.statusbar .battery { width: 25px; }
.inner {
flex: 1 1 auto;
width: 100%;
border: 0;
background: #fafaf7;
}
.home-indicator {
flex: 0 0 28px;
position: relative;
pointer-events: none;
}
.home-indicator::after {
content: '';
position: absolute;
left: 50%; bottom: 8px;
transform: translateX(-50%);
width: 134px; height: 5px;
background: var(--home-fg, #1a1916);
border-radius: 999px;
opacity: 0.85;
}
</style>
</head>
<body>
<div class="device">
<span class="btn-rail left-1" aria-hidden></span>
<span class="btn-rail left-2" aria-hidden></span>
<span class="btn-rail left-3" aria-hidden></span>
<span class="btn-rail right-1" aria-hidden></span>
<span class="island" aria-hidden></span>
<div class="screen">
<div class="statusbar">
<span>9:41</span>
<span class="right">
<svg viewBox="0 0 17 11" aria-hidden>
<rect x="0" y="7" width="3" height="4" rx="0.6"/>
<rect x="4" y="5" width="3" height="6" rx="0.6"/>
<rect x="8" y="3" width="3" height="8" rx="0.6"/>
<rect x="12" y="0" width="3" height="11" rx="0.6"/>
</svg>
<svg viewBox="0 0 17 11" aria-hidden>
<path d="M8.5 1.5C5.5 1.5 2.7 2.6 0.5 4.6L2 6.1C3.8 4.5 6.1 3.6 8.5 3.6c2.4 0 4.7 0.9 6.5 2.5l1.5-1.5c-2.2-2-5-3.1-8-3.1zM3.5 7.6L5 9.1c1-0.9 2.2-1.4 3.5-1.4 1.3 0 2.5 0.5 3.5 1.4l1.5-1.5c-1.4-1.3-3.1-2-5-2-1.9 0-3.6 0.7-5 2zM6.5 10.6l2 2 2-2c-0.5-0.5-1.2-0.8-2-0.8s-1.5 0.3-2 0.8z"/>
</svg>
<svg class="battery" viewBox="0 0 25 11" aria-hidden>
<rect x="0.5" y="0.5" width="21" height="10" rx="2.5" fill="none" stroke="currentColor" stroke-opacity="0.45"/>
<rect x="22" y="3.5" width="1.5" height="4" rx="0.4" fill="currentColor" fill-opacity="0.45"/>
<rect x="2" y="2" width="18" height="7" rx="1.4"/>
</svg>
</span>
</div>
<iframe
class="inner"
id="screen"
title="Inner screen"
sandbox="allow-scripts allow-same-origin"
loading="lazy"
src="about:blank"
></iframe>
<div class="home-indicator" aria-hidden></div>
</div>
</div>
<script>
(function () {
var qs = new URLSearchParams(location.search);
var raw = qs.get('screen');
var iframe = document.getElementById('screen');
if (!raw) return;
var isAbsolute = /^[a-zA-Z][a-zA-Z\d+.\-]*:/.test(raw) || raw.charAt(0) === '/';
iframe.src = isAbsolute
? raw
: new URL(raw, document.referrer || location.href).toString();
})();
</script>
</body>
</html>