ios_frame.jsx
1 /** 2 * IosFrame — iPhone device frame 3 * 4 * Based on iPhone 15 Pro (393×852 logical pixels) 5 * Includes: Dynamic Island + status bar (time/signal/battery) + Home Indicator + rounded corners 6 * 7 * Usage: 8 * <IosFrame time="9:41" battery={85}> 9 * <YourAppContent /> 10 * </IosFrame> 11 * 12 * Customization: 13 * <IosFrame width={390} height={844} darkMode showKeyboard> 14 * ... 15 * </IosFrame> 16 */ 17 18 const iosFrameStyles = { 19 wrapper: { 20 display: 'inline-block', 21 padding: 12, 22 background: '#000', 23 borderRadius: 60, 24 boxShadow: '0 0 0 2px #1f2937, 0 20px 60px rgba(0,0,0,0.3)', 25 position: 'relative', 26 }, 27 screen: { 28 position: 'relative', 29 borderRadius: 48, 30 overflow: 'hidden', 31 background: '#fff', 32 }, 33 statusBar: { 34 position: 'absolute', 35 top: 0, 36 left: 0, 37 right: 0, 38 height: 54, 39 display: 'flex', 40 alignItems: 'center', 41 justifyContent: 'space-between', 42 padding: '0 32px 0 32px', 43 fontSize: 16, 44 fontWeight: 600, 45 fontFamily: '-apple-system, "SF Pro Text", sans-serif', 46 zIndex: 20, 47 pointerEvents: 'none', 48 }, 49 dynamicIsland: { 50 position: 'absolute', 51 top: 12, 52 left: '50%', 53 transform: 'translateX(-50%)', 54 width: 124, 55 height: 36, 56 background: '#000', 57 borderRadius: 999, 58 zIndex: 30, 59 }, 60 statusIcons: { 61 display: 'flex', 62 alignItems: 'center', 63 gap: 6, 64 }, 65 signalIcon: { 66 display: 'flex', 67 alignItems: 'flex-end', 68 gap: 2, 69 height: 12, 70 }, 71 signalBar: { 72 width: 3, 73 background: 'currentColor', 74 borderRadius: 1, 75 }, 76 wifiIcon: { 77 width: 16, 78 height: 12, 79 position: 'relative', 80 }, 81 batteryIcon: { 82 width: 26, 83 height: 12, 84 border: '1.5px solid currentColor', 85 borderRadius: 3, 86 padding: 1, 87 position: 'relative', 88 opacity: 0.8, 89 }, 90 batteryCap: { 91 position: 'absolute', 92 top: 3, 93 right: -3, 94 width: 2, 95 height: 6, 96 background: 'currentColor', 97 borderRadius: '0 1px 1px 0', 98 }, 99 content: { 100 position: 'absolute', 101 top: 54, 102 left: 0, 103 right: 0, 104 bottom: 34, 105 overflow: 'auto', 106 }, 107 homeIndicator: { 108 position: 'absolute', 109 bottom: 10, 110 left: '50%', 111 transform: 'translateX(-50%)', 112 width: 140, 113 height: 5, 114 background: 'rgba(0,0,0,0.3)', 115 borderRadius: 999, 116 zIndex: 10, 117 }, 118 homeIndicatorDark: { 119 background: 'rgba(255,255,255,0.5)', 120 }, 121 }; 122 123 function IosFrame({ 124 children, 125 width = 393, 126 height = 852, 127 time = '9:41', 128 battery = 100, 129 darkMode = false, 130 showStatusBar = true, 131 showDynamicIsland = true, 132 showHomeIndicator = true, 133 }) { 134 const textColor = darkMode ? '#fff' : '#000'; 135 136 return ( 137 <div style={iosFrameStyles.wrapper}> 138 <div style={{ 139 ...iosFrameStyles.screen, 140 width, 141 height, 142 background: darkMode ? '#000' : '#fff', 143 }}> 144 {showStatusBar && ( 145 <div style={{ ...iosFrameStyles.statusBar, color: textColor }}> 146 <span>{time}</span> 147 <div style={iosFrameStyles.statusIcons}> 148 <div style={iosFrameStyles.signalIcon}> 149 <div style={{ ...iosFrameStyles.signalBar, height: 4 }} /> 150 <div style={{ ...iosFrameStyles.signalBar, height: 6 }} /> 151 <div style={{ ...iosFrameStyles.signalBar, height: 9 }} /> 152 <div style={{ ...iosFrameStyles.signalBar, height: 11 }} /> 153 </div> 154 <svg width="16" height="12" viewBox="0 0 16 12" fill="none" style={{ color: textColor }}> 155 <path d="M8 11.5a1 1 0 100-2 1 1 0 000 2z" fill="currentColor" /> 156 <path d="M3 7.5a7 7 0 0110 0" stroke="currentColor" strokeWidth="1.3" fill="none" strokeLinecap="round" /> 157 <path d="M1 4.5a11 11 0 0114 0" stroke="currentColor" strokeWidth="1.3" fill="none" strokeLinecap="round" opacity="0.7" /> 158 </svg> 159 <div style={iosFrameStyles.batteryIcon}> 160 <div style={{ 161 width: `${battery}%`, 162 height: '100%', 163 background: 'currentColor', 164 borderRadius: 1, 165 opacity: 0.9, 166 }} /> 167 <div style={iosFrameStyles.batteryCap} /> 168 </div> 169 </div> 170 </div> 171 )} 172 173 {showDynamicIsland && <div style={iosFrameStyles.dynamicIsland} />} 174 175 <div style={iosFrameStyles.content}> 176 {children} 177 </div> 178 179 {showHomeIndicator && ( 180 <div style={{ 181 ...iosFrameStyles.homeIndicator, 182 ...(darkMode ? iosFrameStyles.homeIndicatorDark : {}), 183 }} /> 184 )} 185 </div> 186 </div> 187 ); 188 } 189 190 if (typeof window !== 'undefined') { 191 window.IosFrame = IosFrame; 192 }