|
| 1 | +import { writeFileSync } from 'node:fs' |
| 2 | +import { join } from 'node:path' |
| 3 | +import glob from 'fast-glob' |
| 4 | +import type { PluginLog } from '../types' |
| 5 | + |
| 6 | +function hexToRgbColor(hex: string) { |
| 7 | + const cleanHex = hex.replace('#', '').trim() |
| 8 | + const r = Number.parseInt(cleanHex.substring(0, 2), 16) / 255 |
| 9 | + const g = Number.parseInt(cleanHex.substring(2, 4), 16) / 255 |
| 10 | + const b = Number.parseInt(cleanHex.substring(4, 6), 16) / 255 |
| 11 | + return `red="${r}" green="${g}" blue="${b}" alpha="1" colorSpace="calibratedRGB"` |
| 12 | +} |
| 13 | + |
| 14 | +const templateApple = ( |
| 15 | + backgroundColor: string, |
| 16 | + title: string, |
| 17 | + titleColor: string, |
| 18 | + subtitle: string, |
| 19 | + subtitleColor: string, |
| 20 | +) => `<?xml version="1.0" encoding="UTF-8"?> |
| 21 | +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM"> |
| 22 | + <device id="retina4_7" orientation="portrait" appearance="light"/> |
| 23 | + <dependencies> |
| 24 | + <deployment identifier="iOS"/> |
| 25 | + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/> |
| 26 | + <capability name="Safe area layout guides" minToolsVersion="9.0"/> |
| 27 | + <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> |
| 28 | + </dependencies> |
| 29 | + <scenes> |
| 30 | + <!--View Controller--> |
| 31 | + <scene sceneID="EHf-IW-A2E"> |
| 32 | + <objects> |
| 33 | + <viewController id="01J-lp-oVM" sceneMemberID="viewController"> |
| 34 | + <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3"> |
| 35 | + <rect key="frame" x="0.0" y="0.0" width="375" height="667"/> |
| 36 | + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> |
| 37 | + <subviews> |
| 38 | + <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="${title}" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="GJd-Yh-RWb"> |
| 39 | + <rect key="frame" x="0.0" y="202" width="375" height="43"/> |
| 40 | + <fontDescription key="fontDescription" type="boldSystem" pointSize="36"/> |
| 41 | + <color key="textColor" ${titleColor}/> |
| 42 | + <nil key="highlightedColor"/> |
| 43 | + </label> |
| 44 | + <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="${subtitle}" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="MN2-I3-ftu"> |
| 45 | + <rect key="frame" x="0.0" y="626" width="375" height="21"/> |
| 46 | + <fontDescription key="fontDescription" type="system" pointSize="17"/> |
| 47 | + <color key="textColor" ${subtitleColor}/> |
| 48 | + <nil key="highlightedColor"/> |
| 49 | + </label> |
| 50 | + </subviews> |
| 51 | + <viewLayoutGuide key="safeArea" id="Bcu-3y-fUS"/> |
| 52 | + <color key="backgroundColor" ${backgroundColor}/> |
| 53 | + <constraints> |
| 54 | + <constraint firstItem="Bcu-3y-fUS" firstAttribute="bottom" secondItem="MN2-I3-ftu" secondAttribute="bottom" constant="20" id="OZV-Vh-mqD"/> |
| 55 | + <constraint firstItem="Bcu-3y-fUS" firstAttribute="centerX" secondItem="GJd-Yh-RWb" secondAttribute="centerX" id="Q3B-4B-g5h"/> |
| 56 | + <constraint firstItem="MN2-I3-ftu" firstAttribute="centerX" secondItem="Bcu-3y-fUS" secondAttribute="centerX" id="akx-eg-2ui"/> |
| 57 | + <constraint firstItem="MN2-I3-ftu" firstAttribute="leading" secondItem="Bcu-3y-fUS" secondAttribute="leading" id="i1E-0Y-4RG"/> |
| 58 | + <constraint firstItem="GJd-Yh-RWb" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="bottom" multiplier="1/3" constant="1" id="moa-c2-u7t"/> |
| 59 | + <constraint firstItem="GJd-Yh-RWb" firstAttribute="leading" secondItem="Bcu-3y-fUS" secondAttribute="leading" symbolic="YES" id="x7j-FC-K8j"/> |
| 60 | + </constraints> |
| 61 | + </view> |
| 62 | + </viewController> |
| 63 | + <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/> |
| 64 | + </objects> |
| 65 | + <point key="canvasLocation" x="52.173913043478265" y="375"/> |
| 66 | + </scene> |
| 67 | + </scenes> |
| 68 | +</document>` |
| 69 | + |
| 70 | +interface Options { |
| 71 | + launchscreen?: { background?: string; title?: string; titleColor?: string; subtitle?: 'year' | string; subtitleColor?: string } |
| 72 | +} |
| 73 | + |
| 74 | +interface PluginInput { |
| 75 | + // Root project path. |
| 76 | + projectPath?: string |
| 77 | + // Location of /android or /ios folders, either root or inside /.numic. |
| 78 | + nativePath?: string |
| 79 | + log?: PluginLog |
| 80 | + options: Options |
| 81 | + // Currently installed React Native version. |
| 82 | + version?: string |
| 83 | + // App name. |
| 84 | + name: string |
| 85 | +} |
| 86 | + |
| 87 | +export default ({ nativePath = process.cwd(), log = console.log, options = { launchscreen: {} }, name }: PluginInput) => { |
| 88 | + const { launchscreen } = options |
| 89 | + if (typeof launchscreen !== 'object') { |
| 90 | + return |
| 91 | + } |
| 92 | + |
| 93 | + const launchScreenFilePath = glob.sync(join(nativePath, 'ios/*/LaunchScreen.storyboard'), { |
| 94 | + cwd: nativePath, |
| 95 | + })[0] |
| 96 | + |
| 97 | + if (!launchScreenFilePath) { |
| 98 | + log('LaunchScreen.storyboard file not found', 'warning') |
| 99 | + return |
| 100 | + } |
| 101 | + |
| 102 | + const currentYear = new Date().getFullYear().toString() |
| 103 | + const iOsLaunchScreen = templateApple( |
| 104 | + hexToRgbColor(launchscreen.background ?? '#FFFFFF'), |
| 105 | + launchscreen.title ?? name, |
| 106 | + hexToRgbColor(launchscreen.titleColor ?? '#000000'), |
| 107 | + (launchscreen.subtitle === 'year' ? currentYear : launchscreen.subtitle) ?? currentYear, |
| 108 | + hexToRgbColor(launchscreen.subtitleColor ?? '#000000'), |
| 109 | + ) |
| 110 | + |
| 111 | + writeFileSync(launchScreenFilePath, iOsLaunchScreen, 'utf-8') |
| 112 | +} |
0 commit comments