preview.html 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>手机预览 - 实验室安全教育考试系统</title>
  7. <style>
  8. * { box-sizing: border-box; margin: 0; padding: 0; }
  9. body {
  10. min-height: 100vh;
  11. background: linear-gradient(135deg, #0f1728 0%, #1a2a4a 50%, #0f1728 100%);
  12. display: flex;
  13. align-items: center;
  14. justify-content: center;
  15. font-family: -apple-system, "PingFang SC", "Microsoft YaHei", sans-serif;
  16. }
  17. /* ===== AMBIENT GLOW ===== */
  18. body::before {
  19. content: '';
  20. position: fixed;
  21. top: 50%; left: 50%;
  22. transform: translate(-50%, -50%);
  23. width: 600px; height: 600px;
  24. background: radial-gradient(circle, rgba(22,119,255,0.15) 0%, transparent 70%);
  25. pointer-events: none;
  26. }
  27. /* ===== DEVICE SWITCHER ===== */
  28. .toolbar {
  29. position: fixed;
  30. top: 24px;
  31. left: 50%;
  32. transform: translateX(-50%);
  33. display: flex;
  34. gap: 8px;
  35. background: rgba(255,255,255,0.08);
  36. backdrop-filter: blur(12px);
  37. border: 1px solid rgba(255,255,255,0.12);
  38. border-radius: 40px;
  39. padding: 6px 10px;
  40. z-index: 100;
  41. }
  42. .device-btn {
  43. padding: 6px 16px;
  44. border-radius: 30px;
  45. border: none;
  46. background: transparent;
  47. color: rgba(255,255,255,0.55);
  48. font-size: 13px;
  49. cursor: pointer;
  50. transition: all .2s;
  51. display: flex;
  52. align-items: center;
  53. gap: 6px;
  54. white-space: nowrap;
  55. }
  56. .device-btn.active {
  57. background: rgba(22,119,255,0.85);
  58. color: #fff;
  59. box-shadow: 0 2px 12px rgba(22,119,255,0.4);
  60. }
  61. .device-btn:hover:not(.active) {
  62. background: rgba(255,255,255,0.1);
  63. color: rgba(255,255,255,0.85);
  64. }
  65. /* ===== PHONE SHELL ===== */
  66. .phone-wrap {
  67. position: relative;
  68. transition: all 0.35s cubic-bezier(0.4, 0, 0.2, 1);
  69. }
  70. /* iPhone 14 Pro style */
  71. .phone-shell {
  72. position: relative;
  73. background: #1a1a1e;
  74. border-radius: 54px;
  75. padding: 14px;
  76. box-shadow:
  77. 0 0 0 1px rgba(255,255,255,0.08),
  78. 0 0 0 2px #2a2a2e,
  79. 0 0 0 3px rgba(255,255,255,0.05),
  80. 0 40px 80px rgba(0,0,0,0.6),
  81. 0 0 60px rgba(22,119,255,0.08);
  82. transition: all 0.35s cubic-bezier(0.4, 0, 0.2, 1);
  83. }
  84. /* Side buttons */
  85. .phone-shell::before {
  86. content: '';
  87. position: absolute;
  88. left: -3px;
  89. top: 110px;
  90. width: 3px;
  91. height: 36px;
  92. background: #2a2a2e;
  93. border-radius: 2px 0 0 2px;
  94. box-shadow: 0 46px 0 #2a2a2e, 0 90px 0 #2a2a2e;
  95. }
  96. .phone-shell::after {
  97. content: '';
  98. position: absolute;
  99. right: -3px;
  100. top: 140px;
  101. width: 3px;
  102. height: 68px;
  103. background: #2a2a2e;
  104. border-radius: 0 2px 2px 0;
  105. }
  106. /* Screen bezel */
  107. .phone-screen {
  108. background: #000;
  109. border-radius: 42px;
  110. overflow: hidden;
  111. position: relative;
  112. }
  113. /* Dynamic island */
  114. .dynamic-island {
  115. position: absolute;
  116. top: 12px;
  117. left: 50%;
  118. transform: translateX(-50%);
  119. width: 120px;
  120. height: 34px;
  121. background: #000;
  122. border-radius: 20px;
  123. z-index: 10;
  124. display: flex;
  125. align-items: center;
  126. justify-content: flex-end;
  127. padding-right: 10px;
  128. gap: 6px;
  129. }
  130. .di-camera {
  131. width: 12px; height: 12px;
  132. border-radius: 50%;
  133. background: #1a1a1e;
  134. border: 1px solid #2a2a2e;
  135. position: relative;
  136. }
  137. .di-camera::after {
  138. content: '';
  139. position: absolute;
  140. top: 50%; left: 50%;
  141. transform: translate(-50%,-50%);
  142. width: 5px; height: 5px;
  143. border-radius: 50%;
  144. background: #0a0a10;
  145. }
  146. /* Status bar */
  147. .status-bar {
  148. height: 54px;
  149. background: #fff;
  150. display: flex;
  151. align-items: flex-end;
  152. justify-content: space-between;
  153. padding: 0 28px 8px;
  154. font-size: 12px;
  155. font-weight: 600;
  156. color: #1a1a1a;
  157. font-family: -apple-system, sans-serif;
  158. flex-shrink: 0;
  159. }
  160. .status-time { font-size: 15px; font-weight: 700; letter-spacing: -0.3px; }
  161. .status-icons { display: flex; align-items: center; gap: 6px; }
  162. .status-icons svg { color: #1a1a1a; }
  163. /* Home indicator */
  164. .home-indicator {
  165. height: 34px;
  166. background: #fff;
  167. display: flex;
  168. align-items: center;
  169. justify-content: center;
  170. flex-shrink: 0;
  171. }
  172. .home-bar {
  173. width: 134px; height: 5px;
  174. background: #1a1a1a;
  175. border-radius: 3px;
  176. opacity: 0.2;
  177. }
  178. /* The iframe */
  179. .phone-iframe {
  180. width: 100%;
  181. border: none;
  182. display: block;
  183. flex: 1;
  184. min-height: 0;
  185. }
  186. /* ===== SIZE VARIANTS ===== */
  187. /* iPhone 14 Pro: 393x852 logical px */
  188. .size-iphone .phone-shell { width: 421px; }
  189. .size-iphone .phone-screen { height: 754px; display: flex; flex-direction: column; }
  190. .size-iphone .phone-iframe { height: 666px; }
  191. /* iPad mini */
  192. .size-ipad .phone-shell { width: 560px; border-radius: 32px; padding: 12px; }
  193. .size-ipad .phone-screen { border-radius: 24px; height: 820px; display: flex; flex-direction: column; }
  194. .size-ipad .phone-iframe { height: 732px; }
  195. .size-ipad .dynamic-island { display: none; }
  196. .size-ipad .status-bar { height: 44px; background: #f0f2f5; }
  197. .size-ipad .home-indicator { background: #f0f2f5; }
  198. /* Small phone (SE style) */
  199. .size-small .phone-shell { width: 360px; }
  200. .size-small .phone-screen { height: 660px; display: flex; flex-direction: column; }
  201. .size-small .phone-iframe { height: 572px; }
  202. /* ===== SCALE HINT ===== */
  203. .scale-hint {
  204. position: fixed;
  205. bottom: 24px;
  206. left: 50%;
  207. transform: translateX(-50%);
  208. color: rgba(255,255,255,0.3);
  209. font-size: 12px;
  210. letter-spacing: 0.5px;
  211. white-space: nowrap;
  212. }
  213. /* ===== ROTATE PHONE (landscape tablet) ===== */
  214. .size-ipad .phone-shell::before,
  215. .size-ipad .phone-shell::after { display: none; }
  216. /* ===== CLOCK UPDATE ===== */
  217. </style>
  218. </head>
  219. <body>
  220. <!-- Device selector toolbar -->
  221. <div class="toolbar">
  222. <button class="device-btn active" onclick="setDevice('iphone')" id="btn-iphone">
  223. <svg width="13" height="16" viewBox="0 0 13 16" fill="currentColor">
  224. <rect x="1" y="0" width="11" height="16" rx="2.5" fill="none" stroke="currentColor" stroke-width="1.2"/>
  225. <rect x="4" y="13.5" width="5" height="1.2" rx="0.6"/>
  226. <rect x="4.5" y="1.2" width="4" height="0.8" rx="0.4"/>
  227. </svg>
  228. iPhone 14 Pro
  229. </button>
  230. <button class="device-btn" onclick="setDevice('small')" id="btn-small">
  231. <svg width="11" height="14" viewBox="0 0 11 14" fill="currentColor">
  232. <rect x="1" y="0" width="9" height="14" rx="2" fill="none" stroke="currentColor" stroke-width="1.2"/>
  233. <rect x="3.5" y="11.5" width="4" height="1" rx="0.5"/>
  234. </svg>
  235. 小屏手机
  236. </button>
  237. <button class="device-btn" onclick="setDevice('ipad')" id="btn-ipad">
  238. <svg width="16" height="13" viewBox="0 0 16 13" fill="currentColor">
  239. <rect x="0" y="1" width="16" height="11" rx="2" fill="none" stroke="currentColor" stroke-width="1.2"/>
  240. <rect x="13.2" y="4" width="1.2" height="5" rx="0.6"/>
  241. </svg>
  242. 平板
  243. </button>
  244. </div>
  245. <!-- Phone frame -->
  246. <div class="phone-wrap size-iphone" id="phoneWrap">
  247. <div class="phone-shell">
  248. <div class="phone-screen">
  249. <!-- Dynamic island -->
  250. <div class="dynamic-island">
  251. <div class="di-camera"></div>
  252. </div>
  253. <!-- Status bar -->
  254. <div class="status-bar">
  255. <span class="status-time" id="clockTime">9:41</span>
  256. <div class="status-icons">
  257. <!-- Signal -->
  258. <svg width="17" height="12" viewBox="0 0 17 12" fill="currentColor">
  259. <rect x="0" y="7" width="3" height="5" rx="0.5"/>
  260. <rect x="4.5" y="4.5" width="3" height="7.5" rx="0.5"/>
  261. <rect x="9" y="2" width="3" height="10" rx="0.5"/>
  262. <rect x="13.5" y="0" width="3" height="12" rx="0.5" opacity="0.3"/>
  263. </svg>
  264. <!-- WiFi -->
  265. <svg width="16" height="12" viewBox="0 0 16 12" fill="currentColor">
  266. <path d="M8 10.5 L8 10.5 A0.7 0.7 0 0 1 8 10.5Z" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
  267. <path d="M5.5 8.2 Q8 5.8 10.5 8.2" stroke="currentColor" stroke-width="1.4" fill="none" stroke-linecap="round"/>
  268. <path d="M3 5.8 Q8 1.2 13 5.8" stroke="currentColor" stroke-width="1.4" fill="none" stroke-linecap="round"/>
  269. <path d="M0.5 3.2 Q8 -3.5 15.5 3.2" stroke="currentColor" stroke-width="1.4" fill="none" stroke-linecap="round" opacity="0.3"/>
  270. </svg>
  271. <!-- Battery -->
  272. <svg width="25" height="12" viewBox="0 0 25 12" fill="currentColor">
  273. <rect x="0" y="1" width="21" height="10" rx="2.5" fill="none" stroke="currentColor" stroke-width="1.2"/>
  274. <rect x="1.5" y="2.5" width="16" height="7" rx="1.5" opacity="0.9"/>
  275. <path d="M22.5 4 Q24.5 4 24.5 6 Q24.5 8 22.5 8Z" opacity="0.4"/>
  276. </svg>
  277. </div>
  278. </div>
  279. <!-- App iframe -->
  280. <iframe
  281. class="phone-iframe"
  282. id="appFrame"
  283. src="index.html"
  284. title="实验室安全教育考试系统"
  285. ></iframe>
  286. <!-- Home indicator -->
  287. <div class="home-indicator">
  288. <div class="home-bar"></div>
  289. </div>
  290. </div>
  291. </div>
  292. </div>
  293. <div class="scale-hint" id="scaleHint">393 × 852 · iPhone 14 Pro</div>
  294. <script>
  295. // Clock
  296. function updateClock() {
  297. var now = new Date();
  298. var h = now.getHours(), m = now.getMinutes();
  299. document.getElementById('clockTime').textContent =
  300. h + ':' + (m < 10 ? '0' : '') + m;
  301. }
  302. updateClock();
  303. setInterval(updateClock, 10000);
  304. // Device switcher
  305. var devices = {
  306. iphone: { cls: 'size-iphone', hint: '393 × 852 · iPhone 14 Pro' },
  307. small: { cls: 'size-small', hint: '360 × 780 · 小屏手机' },
  308. ipad: { cls: 'size-ipad', hint: '768 × 1024 · 平板' }
  309. };
  310. var current = 'iphone';
  311. function setDevice(name) {
  312. var wrap = document.getElementById('phoneWrap');
  313. wrap.classList.remove(devices[current].cls);
  314. wrap.classList.add(devices[name].cls);
  315. document.getElementById('btn-' + current).classList.remove('active');
  316. document.getElementById('btn-' + name).classList.add('active');
  317. document.getElementById('scaleHint').textContent = devices[name].hint;
  318. current = name;
  319. // Resize iframe to fit
  320. var frame = document.getElementById('appFrame');
  321. frame.src = frame.src; // reload for clean state
  322. }
  323. // Auto-scale phone to fit viewport height
  324. function autoScale() {
  325. var wrap = document.getElementById('phoneWrap');
  326. var shell = wrap.querySelector('.phone-shell');
  327. var vh = window.innerHeight - 100; // leave room for toolbar+hint
  328. var shellH = shell.offsetHeight;
  329. if (shellH > vh) {
  330. var s = vh / shellH;
  331. wrap.style.transform = 'scale(' + s + ')';
  332. wrap.style.marginTop = ((shellH * s - shellH) / 2) + 'px';
  333. wrap.style.marginBottom = ((shellH * s - shellH) / 2) + 'px';
  334. } else {
  335. wrap.style.transform = '';
  336. wrap.style.marginTop = '';
  337. wrap.style.marginBottom = '';
  338. }
  339. }
  340. window.addEventListener('resize', autoScale);
  341. setTimeout(autoScale, 100);
  342. </script>
  343. </body>
  344. </html>