react-native-bootsplash 7.0.1 → 7.1.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app.plugin.js +1 -1
- package/cli.js +1 -1
- package/dist/commonjs/extras/addon/index.js +97 -0
- package/dist/commonjs/extras/addon/index.js.map +1 -0
- package/dist/commonjs/{expo.js → extras/expo.js} +27 -23
- package/dist/commonjs/extras/expo.js.map +1 -0
- package/dist/commonjs/extras/generate.js +274 -0
- package/dist/commonjs/extras/generate.js.map +1 -0
- package/dist/commonjs/{generate.js → extras/utils.js} +110 -339
- package/dist/commonjs/extras/utils.js.map +1 -0
- package/dist/commonjs/package.json +1 -0
- package/dist/module/extras/addon/index.js +97 -0
- package/dist/module/extras/addon/index.js.map +1 -0
- package/dist/module/{expo.js → extras/expo.js} +6 -3
- package/dist/module/extras/expo.js.map +1 -0
- package/dist/module/extras/generate.js +267 -0
- package/dist/module/extras/generate.js.map +1 -0
- package/dist/module/{generate.js → extras/utils.js} +98 -326
- package/dist/module/extras/utils.js.map +1 -0
- package/dist/module/package.json +1 -0
- package/dist/typescript/{addon → commonjs/extras/addon}/index.d.ts +1 -1
- package/dist/typescript/commonjs/extras/addon/index.d.ts.map +1 -0
- package/dist/typescript/commonjs/extras/expo.d.ts +8 -0
- package/dist/typescript/commonjs/extras/expo.d.ts.map +1 -0
- package/dist/typescript/commonjs/extras/generate.d.ts +17 -0
- package/dist/typescript/commonjs/extras/generate.d.ts.map +1 -0
- package/dist/typescript/{generate.d.ts → commonjs/extras/utils.d.ts} +85 -50
- package/dist/typescript/commonjs/extras/utils.d.ts.map +1 -0
- package/dist/typescript/commonjs/index.d.ts.map +1 -0
- package/dist/typescript/commonjs/package.json +1 -0
- package/dist/typescript/commonjs/specs/NativeRNBootSplash.d.ts.map +1 -0
- package/dist/typescript/commonjs/specs/NativeRNBootSplash.web.d.ts.map +1 -0
- package/dist/typescript/module/extras/addon/index.d.ts +26 -0
- package/dist/typescript/module/extras/addon/index.d.ts.map +1 -0
- package/dist/typescript/module/extras/expo.d.ts +8 -0
- package/dist/typescript/module/extras/expo.d.ts.map +1 -0
- package/dist/typescript/module/extras/generate.d.ts +17 -0
- package/dist/typescript/module/extras/generate.d.ts.map +1 -0
- package/dist/typescript/module/extras/utils.d.ts +193 -0
- package/dist/typescript/module/extras/utils.d.ts.map +1 -0
- package/dist/typescript/module/index.d.ts +61 -0
- package/dist/typescript/module/index.d.ts.map +1 -0
- package/dist/typescript/module/package.json +1 -0
- package/dist/typescript/module/specs/NativeRNBootSplash.d.ts +14 -0
- package/dist/typescript/module/specs/NativeRNBootSplash.d.ts.map +1 -0
- package/dist/typescript/module/specs/NativeRNBootSplash.web.d.ts +9 -0
- package/dist/typescript/module/specs/NativeRNBootSplash.web.d.ts.map +1 -0
- package/package.json +52 -24
- package/src/{expo.ts → extras/expo.ts} +32 -33
- package/src/extras/generate.ts +410 -0
- package/src/{generate.ts → extras/utils.ts} +159 -471
- package/dist/commonjs/addon/index.js +0 -97
- package/dist/commonjs/addon/index.js.map +0 -1
- package/dist/commonjs/expo.js.map +0 -1
- package/dist/commonjs/generate.js.map +0 -1
- package/dist/module/addon/index.js +0 -97
- package/dist/module/addon/index.js.map +0 -1
- package/dist/module/expo.js.map +0 -1
- package/dist/module/generate.js.map +0 -1
- package/dist/typescript/addon/index.d.ts.map +0 -1
- package/dist/typescript/expo.d.ts +0 -6
- package/dist/typescript/expo.d.ts.map +0 -1
- package/dist/typescript/generate.d.ts.map +0 -1
- package/dist/typescript/index.d.ts.map +0 -1
- package/dist/typescript/specs/NativeRNBootSplash.d.ts.map +0 -1
- package/dist/typescript/specs/NativeRNBootSplash.web.d.ts.map +0 -1
- /package/dist/typescript/{index.d.ts → commonjs/index.d.ts} +0 -0
- /package/dist/typescript/{specs → commonjs/specs}/NativeRNBootSplash.d.ts +0 -0
- /package/dist/typescript/{specs → commonjs/specs}/NativeRNBootSplash.web.d.ts +0 -0
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
import * as Expo from "@expo/config-plugins";
|
|
2
|
+
import ExpoPlist from "@expo/plist";
|
|
3
|
+
import glob from "fast-glob";
|
|
4
|
+
import fs from "fs";
|
|
5
|
+
import { HTMLElement, parse as parseHtml } from "node-html-parser";
|
|
6
|
+
import path from "path";
|
|
7
|
+
import pc from "picocolors";
|
|
8
|
+
import { dedent } from "ts-dedent";
|
|
9
|
+
import formatXml from "xml-formatter";
|
|
10
|
+
import {
|
|
11
|
+
hfs,
|
|
12
|
+
log,
|
|
13
|
+
readXmlLike,
|
|
14
|
+
requireAddon,
|
|
15
|
+
setLoggerMode,
|
|
16
|
+
transformProps,
|
|
17
|
+
writeAndroidAssets,
|
|
18
|
+
writeGenericAssets,
|
|
19
|
+
writeIOSAssets,
|
|
20
|
+
writeWebAssets,
|
|
21
|
+
writeXmlLike,
|
|
22
|
+
} from "./utils";
|
|
23
|
+
|
|
24
|
+
const cwd = process.env.INIT_CWD ?? process.env.PWD ?? process.cwd();
|
|
25
|
+
setLoggerMode({ type: "cli", cwd });
|
|
26
|
+
|
|
27
|
+
const projectRoot = (() => {
|
|
28
|
+
let directory = path.resolve(cwd);
|
|
29
|
+
|
|
30
|
+
const { root } = path.parse(directory);
|
|
31
|
+
const ends = new Set([root, path.resolve(directory, root)]);
|
|
32
|
+
|
|
33
|
+
while (directory) {
|
|
34
|
+
const pkgPath = path.join(directory, "package.json");
|
|
35
|
+
const stats = fs.statSync(pkgPath, { throwIfNoEntry: false });
|
|
36
|
+
|
|
37
|
+
if (stats != null && stats.isFile()) {
|
|
38
|
+
return path.dirname(pkgPath);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (ends.has(directory)) {
|
|
42
|
+
break;
|
|
43
|
+
} else {
|
|
44
|
+
directory = path.dirname(directory);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
})();
|
|
48
|
+
|
|
49
|
+
if (!projectRoot) {
|
|
50
|
+
log.error("We couldn't find a package.json in your project.");
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const getAndroidOutputPath = ({ flavor }: { flavor: string }) => {
|
|
55
|
+
const sourceDir = path.join(projectRoot, "android");
|
|
56
|
+
|
|
57
|
+
if (!fs.existsSync(sourceDir)) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const appDir = path.join(sourceDir, "app");
|
|
62
|
+
|
|
63
|
+
const androidOutputPath = path.resolve(
|
|
64
|
+
sourceDir,
|
|
65
|
+
fs.existsSync(appDir) ? "app" : "",
|
|
66
|
+
"src",
|
|
67
|
+
flavor,
|
|
68
|
+
"res",
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
if (hfs.exists(androidOutputPath)) {
|
|
72
|
+
return androidOutputPath;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
log.warn(
|
|
76
|
+
`No ${path.relative(
|
|
77
|
+
cwd,
|
|
78
|
+
androidOutputPath,
|
|
79
|
+
)} directory found. Skipping Android assets generation…`,
|
|
80
|
+
);
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const getIOSOutputPath = () => {
|
|
84
|
+
const podfile = glob
|
|
85
|
+
.sync("**/Podfile", {
|
|
86
|
+
cwd: projectRoot.replace(/^([a-zA-Z]+:|\.\/)/, ""),
|
|
87
|
+
deep: 10,
|
|
88
|
+
ignore: ["**/@(Pods|node_modules|Carthage|vendor|android)/**"],
|
|
89
|
+
})
|
|
90
|
+
.find((project) => {
|
|
91
|
+
return path.dirname(project) === "ios";
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
if (!podfile) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const sourceDir = path.dirname(path.join(projectRoot, podfile));
|
|
99
|
+
|
|
100
|
+
const xcodeProjectName = fs
|
|
101
|
+
.readdirSync(sourceDir)
|
|
102
|
+
.sort()
|
|
103
|
+
.reverse()
|
|
104
|
+
.find((fileName) => {
|
|
105
|
+
const ext = path.extname(fileName);
|
|
106
|
+
return ext === ".xcodeproj" || ext === ".xcworkspace";
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
if (xcodeProjectName == null) {
|
|
110
|
+
log.warn("No Xcode project found. Skipping iOS assets generation…");
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const iosOutputPath = path
|
|
115
|
+
.resolve(sourceDir, xcodeProjectName)
|
|
116
|
+
.replace(/\.(xcodeproj|xcworkspace)$/, "");
|
|
117
|
+
|
|
118
|
+
if (hfs.exists(iosOutputPath)) {
|
|
119
|
+
return iosOutputPath;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
log.warn(
|
|
123
|
+
`No ${path.relative(
|
|
124
|
+
cwd,
|
|
125
|
+
iosOutputPath,
|
|
126
|
+
)} directory found. Skipping iOS assets generation…`,
|
|
127
|
+
);
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const getHtmlTemplatePath = ({ html }: { html: string }) => {
|
|
131
|
+
const htmlTemplatePath = path.resolve(cwd, html);
|
|
132
|
+
|
|
133
|
+
if (hfs.exists(htmlTemplatePath)) {
|
|
134
|
+
return htmlTemplatePath;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
log.warn(
|
|
138
|
+
`No ${path.relative(
|
|
139
|
+
cwd,
|
|
140
|
+
htmlTemplatePath,
|
|
141
|
+
)} found. Skipping HTML + CSS generation…`,
|
|
142
|
+
);
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
const getInfoPlistPath = ({
|
|
146
|
+
iosOutputPath,
|
|
147
|
+
plist,
|
|
148
|
+
}: {
|
|
149
|
+
iosOutputPath: string;
|
|
150
|
+
plist: string | undefined;
|
|
151
|
+
}) => {
|
|
152
|
+
if (plist != null) {
|
|
153
|
+
const infoPlistPath = path.resolve(cwd, plist);
|
|
154
|
+
|
|
155
|
+
if (!hfs.exists(infoPlistPath)) {
|
|
156
|
+
return log.warn(`No ${path.relative(cwd, infoPlistPath)} found`);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return infoPlistPath;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return path.resolve(iosOutputPath, "Info.plist");
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
export const generate = async ({
|
|
166
|
+
platforms,
|
|
167
|
+
html,
|
|
168
|
+
flavor,
|
|
169
|
+
plist,
|
|
170
|
+
...rawProps
|
|
171
|
+
}: {
|
|
172
|
+
platforms: Array<"android" | "ios" | "web">;
|
|
173
|
+
html: string;
|
|
174
|
+
flavor: string;
|
|
175
|
+
plist?: string;
|
|
176
|
+
|
|
177
|
+
logo: string;
|
|
178
|
+
background: string;
|
|
179
|
+
logoWidth: number;
|
|
180
|
+
assetsOutput: string;
|
|
181
|
+
licenseKey?: string;
|
|
182
|
+
brand?: string;
|
|
183
|
+
brandWidth: number;
|
|
184
|
+
darkBackground?: string;
|
|
185
|
+
darkLogo?: string;
|
|
186
|
+
darkBrand?: string;
|
|
187
|
+
}) => {
|
|
188
|
+
const props = await transformProps(cwd, rawProps);
|
|
189
|
+
const addon = requireAddon(props);
|
|
190
|
+
|
|
191
|
+
const { background, brand } = props;
|
|
192
|
+
|
|
193
|
+
const androidOutputPath = platforms.includes("android")
|
|
194
|
+
? getAndroidOutputPath({ flavor })
|
|
195
|
+
: undefined;
|
|
196
|
+
|
|
197
|
+
const iosOutputPath = platforms.includes("ios")
|
|
198
|
+
? getIOSOutputPath()
|
|
199
|
+
: undefined;
|
|
200
|
+
|
|
201
|
+
const htmlTemplatePath = platforms.includes("web")
|
|
202
|
+
? getHtmlTemplatePath({ html })
|
|
203
|
+
: undefined;
|
|
204
|
+
|
|
205
|
+
if (androidOutputPath != null) {
|
|
206
|
+
await writeAndroidAssets({ androidOutputPath, props });
|
|
207
|
+
|
|
208
|
+
const manifestXmlPath = path.resolve(
|
|
209
|
+
androidOutputPath,
|
|
210
|
+
"..",
|
|
211
|
+
"AndroidManifest.xml",
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
if (hfs.exists(manifestXmlPath)) {
|
|
215
|
+
const manifestXml = readXmlLike(manifestXmlPath);
|
|
216
|
+
const activities = manifestXml.root.querySelectorAll("activity");
|
|
217
|
+
|
|
218
|
+
for (const activity of activities) {
|
|
219
|
+
if (activity.getAttribute("android:name") === ".MainActivity") {
|
|
220
|
+
activity.setAttribute("android:theme", "@style/BootTheme");
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
await writeXmlLike(manifestXmlPath, manifestXml.root.toString(), {
|
|
225
|
+
...manifestXml.formatOptions,
|
|
226
|
+
formatter: "prettier",
|
|
227
|
+
htmlWhitespaceSensitivity: "ignore",
|
|
228
|
+
selfClosingTags: true,
|
|
229
|
+
singleAttributePerLine: true,
|
|
230
|
+
});
|
|
231
|
+
} else {
|
|
232
|
+
log.warn("No AndroidManifest.xml found");
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const valuesPath = path.resolve(androidOutputPath, "values");
|
|
236
|
+
hfs.ensureDir(valuesPath);
|
|
237
|
+
|
|
238
|
+
const colorsXmlPath = path.resolve(valuesPath, "colors.xml");
|
|
239
|
+
const colorsXmlEntry = `<color name="bootsplash_background">${background.hex}</color>`;
|
|
240
|
+
|
|
241
|
+
if (hfs.exists(colorsXmlPath)) {
|
|
242
|
+
const colorsXml = readXmlLike(colorsXmlPath);
|
|
243
|
+
const nextColor = parseHtml(colorsXmlEntry);
|
|
244
|
+
|
|
245
|
+
const prevColor = colorsXml.root.querySelector(
|
|
246
|
+
'color[name="bootsplash_background"]',
|
|
247
|
+
);
|
|
248
|
+
|
|
249
|
+
if (prevColor != null) {
|
|
250
|
+
prevColor.replaceWith(nextColor);
|
|
251
|
+
} else {
|
|
252
|
+
colorsXml.root.querySelector("resources")?.appendChild(nextColor);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
await writeXmlLike(colorsXmlPath, colorsXml.root.toString(), {
|
|
256
|
+
...colorsXml.formatOptions,
|
|
257
|
+
formatter: "xmlFormatter",
|
|
258
|
+
});
|
|
259
|
+
} else {
|
|
260
|
+
await writeXmlLike(
|
|
261
|
+
colorsXmlPath,
|
|
262
|
+
`<resources>${colorsXmlEntry}</resources>`,
|
|
263
|
+
{ formatter: "xmlFormatter" },
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const stylesXmlPath = path.resolve(valuesPath, "styles.xml");
|
|
268
|
+
|
|
269
|
+
if (hfs.exists(stylesXmlPath)) {
|
|
270
|
+
const stylesXml = readXmlLike(stylesXmlPath);
|
|
271
|
+
const prevStyle = stylesXml.root.querySelector('style[name="BootTheme"]');
|
|
272
|
+
const parent = prevStyle?.getAttribute("parent") ?? "Theme.BootSplash";
|
|
273
|
+
|
|
274
|
+
const extraItems = parseHtml(
|
|
275
|
+
prevStyle?.text
|
|
276
|
+
.split("\n")
|
|
277
|
+
.map((line) => line.trim())
|
|
278
|
+
.join("") ?? "",
|
|
279
|
+
)
|
|
280
|
+
.childNodes.filter((node) => {
|
|
281
|
+
if (!(node instanceof HTMLElement)) {
|
|
282
|
+
return true;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const name = node.getAttribute("name");
|
|
286
|
+
|
|
287
|
+
return (
|
|
288
|
+
name !== "bootSplashBackground" &&
|
|
289
|
+
name !== "bootSplashLogo" &&
|
|
290
|
+
name !== "bootSplashBrand" &&
|
|
291
|
+
name !== "postBootSplashTheme"
|
|
292
|
+
);
|
|
293
|
+
})
|
|
294
|
+
.map((node) => node.toString());
|
|
295
|
+
|
|
296
|
+
const styleItems: string[] = [
|
|
297
|
+
...(extraItems.length > 0 ? [...extraItems, ""] : []),
|
|
298
|
+
|
|
299
|
+
'<item name="bootSplashBackground">@color/bootsplash_background</item>',
|
|
300
|
+
'<item name="bootSplashLogo">@drawable/bootsplash_logo</item>',
|
|
301
|
+
|
|
302
|
+
...(brand != null
|
|
303
|
+
? ['<item name="bootSplashBrand">@drawable/bootsplash_brand</item>']
|
|
304
|
+
: []),
|
|
305
|
+
|
|
306
|
+
'<item name="postBootSplashTheme">@style/AppTheme</item>',
|
|
307
|
+
];
|
|
308
|
+
|
|
309
|
+
const nextStyle = parseHtml(dedent`
|
|
310
|
+
<style name="BootTheme" parent="${parent}">
|
|
311
|
+
${styleItems.join("\n")}
|
|
312
|
+
</style>
|
|
313
|
+
`);
|
|
314
|
+
|
|
315
|
+
prevStyle?.remove(); // remove the existing style
|
|
316
|
+
stylesXml.root.querySelector("resources")?.appendChild(nextStyle);
|
|
317
|
+
|
|
318
|
+
await writeXmlLike(stylesXmlPath, stylesXml.root.toString(), {
|
|
319
|
+
...stylesXml.formatOptions,
|
|
320
|
+
formatter: "prettier",
|
|
321
|
+
htmlWhitespaceSensitivity: "ignore",
|
|
322
|
+
});
|
|
323
|
+
} else {
|
|
324
|
+
log.warn("No styles.xml found");
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
if (iosOutputPath != null) {
|
|
329
|
+
await writeIOSAssets({ iosOutputPath, props });
|
|
330
|
+
|
|
331
|
+
const pbxprojectPath = Expo.IOSConfig.Paths.getPBXProjectPath(projectRoot);
|
|
332
|
+
|
|
333
|
+
const xcodeProjectPath =
|
|
334
|
+
Expo.IOSConfig.Paths.getXcodeProjectPath(projectRoot);
|
|
335
|
+
|
|
336
|
+
const project = Expo.IOSConfig.XcodeUtils.getPbxproj(projectRoot);
|
|
337
|
+
const projectName = path.basename(iosOutputPath);
|
|
338
|
+
const groupName = path.parse(xcodeProjectPath).name;
|
|
339
|
+
|
|
340
|
+
Expo.IOSConfig.XcodeUtils.addResourceFileToGroup({
|
|
341
|
+
project,
|
|
342
|
+
filepath: path.join(projectName, "BootSplash.storyboard"),
|
|
343
|
+
groupName,
|
|
344
|
+
isBuildFile: true,
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
Expo.IOSConfig.XcodeUtils.addResourceFileToGroup({
|
|
348
|
+
project,
|
|
349
|
+
filepath: path.join(projectName, "Colors.xcassets"),
|
|
350
|
+
groupName,
|
|
351
|
+
isBuildFile: true,
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
hfs.write(pbxprojectPath, project.writeSync());
|
|
355
|
+
log.write(pbxprojectPath);
|
|
356
|
+
|
|
357
|
+
const infoPlistPath = getInfoPlistPath({ iosOutputPath, plist });
|
|
358
|
+
|
|
359
|
+
if (infoPlistPath != null) {
|
|
360
|
+
const infoPlist = ExpoPlist.parse(hfs.text(infoPlistPath)) as Record<
|
|
361
|
+
string,
|
|
362
|
+
unknown
|
|
363
|
+
>;
|
|
364
|
+
|
|
365
|
+
infoPlist["UILaunchStoryboardName"] = "BootSplash";
|
|
366
|
+
|
|
367
|
+
const formatted = formatXml(ExpoPlist.build(infoPlist), {
|
|
368
|
+
collapseContent: true,
|
|
369
|
+
forceSelfClosingEmptyTag: false,
|
|
370
|
+
indentation: "\t",
|
|
371
|
+
lineSeparator: "\n",
|
|
372
|
+
whiteSpaceAtEndOfSelfclosingTag: false,
|
|
373
|
+
})
|
|
374
|
+
.replace(/<string\/>/gm, "<string></string>")
|
|
375
|
+
.replace(/^\t/gm, "");
|
|
376
|
+
|
|
377
|
+
hfs.write(infoPlistPath, formatted);
|
|
378
|
+
log.write(infoPlistPath);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
if (htmlTemplatePath != null) {
|
|
383
|
+
await writeWebAssets({ htmlTemplatePath, props });
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
await writeGenericAssets({ props });
|
|
387
|
+
|
|
388
|
+
if (addon != null) {
|
|
389
|
+
await addon.execute({
|
|
390
|
+
props,
|
|
391
|
+
androidOutputPath,
|
|
392
|
+
iosOutputPath,
|
|
393
|
+
htmlTemplatePath,
|
|
394
|
+
});
|
|
395
|
+
} else {
|
|
396
|
+
console.log(`
|
|
397
|
+
${pc.blue("┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓")}
|
|
398
|
+
${pc.blue("┃")} 🔑 ${pc.bold(
|
|
399
|
+
"Get a license key for brand image / dark mode support",
|
|
400
|
+
)} ${pc.blue("┃")}
|
|
401
|
+
${pc.blue("┃")} ${pc.underline(
|
|
402
|
+
"https://zoontek.gumroad.com/l/bootsplash-generator",
|
|
403
|
+
)} ${pc.blue("┃")}
|
|
404
|
+
${pc.blue("┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛")}`);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
console.log(
|
|
408
|
+
`\n💖 Thanks for using ${pc.underline("react-native-bootsplash")}`,
|
|
409
|
+
);
|
|
410
|
+
};
|