newcandies 0.1.5 → 0.1.7
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/dist/index.js +226 -60
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -151,11 +151,13 @@ async function writeBaseline({ dest, name, withQuery }) {
|
|
|
151
151
|
"react-native-worklets": "0.5.1",
|
|
152
152
|
// Styling
|
|
153
153
|
tailwindcss: "^4.1.16",
|
|
154
|
-
uniwind: "^1.0.0"
|
|
154
|
+
uniwind: "^1.0.0",
|
|
155
|
+
"@expo/vector-icons": "latest"
|
|
155
156
|
};
|
|
156
157
|
if (withQuery) {
|
|
157
158
|
baseDeps["@tanstack/react-query"] = "latest";
|
|
158
159
|
}
|
|
160
|
+
baseDeps["tailwind-merge"] = "latest";
|
|
159
161
|
const pkg = {
|
|
160
162
|
name,
|
|
161
163
|
version: "0.0.0",
|
|
@@ -169,7 +171,8 @@ async function writeBaseline({ dest, name, withQuery }) {
|
|
|
169
171
|
dependencies: baseDeps,
|
|
170
172
|
devDependencies: {
|
|
171
173
|
"@types/react": "~19.1.0",
|
|
172
|
-
typescript: "~5.9.2"
|
|
174
|
+
typescript: "~5.9.2",
|
|
175
|
+
"babel-plugin-module-resolver": "latest"
|
|
173
176
|
}
|
|
174
177
|
};
|
|
175
178
|
await fs.writeJSON(path.join(dest, "package.json"), pkg, { spaces: 2 });
|
|
@@ -209,7 +212,7 @@ async function writeBaseline({ dest, name, withQuery }) {
|
|
|
209
212
|
output: "static",
|
|
210
213
|
favicon: "./assets/images/favicon.png"
|
|
211
214
|
},
|
|
212
|
-
plugins: ["expo-router"],
|
|
215
|
+
plugins: [["expo-router", { appRoot: "./src/app" }]],
|
|
213
216
|
experiments: {
|
|
214
217
|
typedRoutes: true
|
|
215
218
|
}
|
|
@@ -221,6 +224,7 @@ async function writeBaseline({ dest, name, withQuery }) {
|
|
|
221
224
|
return {
|
|
222
225
|
presets: ['babel-preset-expo'],
|
|
223
226
|
plugins: [
|
|
227
|
+
['module-resolver', { alias: { '~': './' } }],
|
|
224
228
|
'react-native-reanimated/plugin'
|
|
225
229
|
]
|
|
226
230
|
};
|
|
@@ -239,22 +243,79 @@ module.exports = withUniwindConfig(config, {
|
|
|
239
243
|
`;
|
|
240
244
|
await fs.writeFile(path.join(dest, "metro.config.js"), metro);
|
|
241
245
|
const tsconfig = {
|
|
246
|
+
extends: "expo/tsconfig.base",
|
|
242
247
|
compilerOptions: {
|
|
243
248
|
strict: true,
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
types: ["react", "react-native"]
|
|
249
|
+
paths: {
|
|
250
|
+
"~/*": ["./*"]
|
|
251
|
+
}
|
|
248
252
|
},
|
|
249
|
-
include: [
|
|
253
|
+
include: [
|
|
254
|
+
"**/*.ts",
|
|
255
|
+
"**/*.tsx",
|
|
256
|
+
".expo/types/**/*.ts",
|
|
257
|
+
"expo-env.d.ts",
|
|
258
|
+
"./uniwind-types.d.ts"
|
|
259
|
+
]
|
|
250
260
|
};
|
|
251
261
|
await fs.writeJSON(path.join(dest, "tsconfig.json"), tsconfig, { spaces: 2 });
|
|
252
262
|
const expoEnv = `/// <reference types="expo" />
|
|
253
263
|
/// <reference types="expo-router" />
|
|
254
264
|
`;
|
|
255
265
|
await fs.writeFile(path.join(dest, "expo-env.d.ts"), expoEnv);
|
|
256
|
-
const
|
|
266
|
+
const srcDir = path.join(dest, "src");
|
|
267
|
+
const appDir = path.join(srcDir, "app");
|
|
257
268
|
await fs.ensureDir(appDir);
|
|
269
|
+
await fs.ensureDir(path.join(srcDir, "core"));
|
|
270
|
+
await fs.ensureDir(path.join(srcDir, "api"));
|
|
271
|
+
await fs.ensureDir(path.join(srcDir, "lib"));
|
|
272
|
+
await fs.ensureDir(path.join(srcDir, "types"));
|
|
273
|
+
await fs.ensureDir(path.join(srcDir, "components", "screens", "home"));
|
|
274
|
+
await fs.ensureDir(path.join(srcDir, "components", "screens", "profile"));
|
|
275
|
+
await fs.ensureDir(path.join(srcDir, "components", "core"));
|
|
276
|
+
const textCore = `import { Text as RNText, TextProps } from 'react-native';
|
|
277
|
+
import { twMerge } from 'tailwind-merge';
|
|
278
|
+
|
|
279
|
+
type TypographyVariant =
|
|
280
|
+
| 'title'
|
|
281
|
+
| 'subtitle'
|
|
282
|
+
| 'body'
|
|
283
|
+
| 'caption'
|
|
284
|
+
| 'button'
|
|
285
|
+
| 'display'
|
|
286
|
+
| 'caption-primary'
|
|
287
|
+
| 'body-primary'
|
|
288
|
+
| 'subtitle-primary';
|
|
289
|
+
|
|
290
|
+
interface TextComponentProps extends TextProps {
|
|
291
|
+
className?: string;
|
|
292
|
+
variant?: TypographyVariant;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const variantStyles: Record<TypographyVariant, string> = {
|
|
296
|
+
title: 'text-2xl font-bold',
|
|
297
|
+
subtitle: 'text-xl font-semibold',
|
|
298
|
+
'subtitle-primary': 'text-xl font-semibold text-primary',
|
|
299
|
+
body: 'text-base',
|
|
300
|
+
'body-primary': 'text-base text-primary',
|
|
301
|
+
caption: 'text-sm font-medium',
|
|
302
|
+
'caption-primary': 'text-sm text-primary font-medium',
|
|
303
|
+
button: 'text-xl text-primary font-semibold text-white text-center',
|
|
304
|
+
display: 'text-3x font-bold',
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
const Text = ({ variant = 'body', children, className, ...props }: TextComponentProps) => {
|
|
308
|
+
const textStyle = twMerge('text-black', variantStyles[variant], className);
|
|
309
|
+
return (
|
|
310
|
+
<RNText className={textStyle} {...props}>
|
|
311
|
+
{children}
|
|
312
|
+
</RNText>
|
|
313
|
+
);
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
export default Text;
|
|
317
|
+
`;
|
|
318
|
+
await fs.writeFile(path.join(srcDir, "components", "core", "text.tsx"), textCore);
|
|
258
319
|
const easJson = {
|
|
259
320
|
cli: { version: ">= 7.0.0" },
|
|
260
321
|
build: {
|
|
@@ -285,80 +346,185 @@ module.exports = withUniwindConfig(config, {
|
|
|
285
346
|
`;
|
|
286
347
|
await fs.writeFile(path.join(dest, "global.css"), globalCss);
|
|
287
348
|
{
|
|
288
|
-
const rootLayout = withQuery ? `import
|
|
289
|
-
import
|
|
290
|
-
import {
|
|
291
|
-
import
|
|
292
|
-
import {
|
|
293
|
-
import
|
|
349
|
+
const rootLayout = withQuery ? `import FontAwesome from "@expo/vector-icons/FontAwesome";
|
|
350
|
+
import { useFonts } from "expo-font";
|
|
351
|
+
import { Stack } from "expo-router";
|
|
352
|
+
import * as SplashScreen from "expo-splash-screen";
|
|
353
|
+
import { useEffect } from "react";
|
|
354
|
+
import "react-native-reanimated";
|
|
355
|
+
import "../../global.css";
|
|
356
|
+
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
357
|
+
|
|
358
|
+
export { ErrorBoundary } from "expo-router";
|
|
359
|
+
|
|
360
|
+
export const unstable_settings = {
|
|
361
|
+
initialRouteName: "(tabs)",
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
SplashScreen.preventAutoHideAsync();
|
|
294
365
|
|
|
295
366
|
const queryClient = new QueryClient();
|
|
296
367
|
|
|
297
|
-
|
|
368
|
+
export default function RootLayout() {
|
|
369
|
+
const [loaded, error] = useFonts({
|
|
370
|
+
SpaceMono: require("../../assets/fonts/SpaceMono-Regular.ttf"),
|
|
371
|
+
...FontAwesome.font,
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
useEffect(() => {
|
|
375
|
+
if (error) throw error;
|
|
376
|
+
}, [error]);
|
|
377
|
+
|
|
378
|
+
useEffect(() => {
|
|
379
|
+
if (loaded) {
|
|
380
|
+
SplashScreen.hideAsync();
|
|
381
|
+
}
|
|
382
|
+
}, [loaded]);
|
|
383
|
+
|
|
384
|
+
if (!loaded) {
|
|
385
|
+
return null;
|
|
386
|
+
}
|
|
387
|
+
|
|
298
388
|
return (
|
|
299
|
-
<
|
|
300
|
-
<
|
|
301
|
-
|
|
302
|
-
<Slot />
|
|
303
|
-
</QueryClientProvider>
|
|
304
|
-
</SafeAreaProvider>
|
|
305
|
-
</GestureHandlerRootView>
|
|
389
|
+
<QueryClientProvider client={queryClient}>
|
|
390
|
+
<RootLayoutNav />
|
|
391
|
+
</QueryClientProvider>
|
|
306
392
|
);
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
export default RootLayout;
|
|
310
|
-
` : `import 'react-native-gesture-handler';
|
|
311
|
-
import '../global.css';
|
|
312
|
-
import { Slot } from 'expo-router';
|
|
313
|
-
import { GestureHandlerRootView } from 'react-native-gesture-handler';
|
|
314
|
-
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
|
393
|
+
}
|
|
315
394
|
|
|
316
|
-
|
|
395
|
+
function RootLayoutNav() {
|
|
317
396
|
return (
|
|
318
|
-
<
|
|
319
|
-
<
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
</GestureHandlerRootView>
|
|
397
|
+
<Stack>
|
|
398
|
+
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
|
|
399
|
+
<Stack.Screen name="modal" options={{ presentation: "modal" }} />
|
|
400
|
+
</Stack>
|
|
323
401
|
);
|
|
402
|
+
}
|
|
403
|
+
` : `import FontAwesome from "@expo/vector-icons/FontAwesome";
|
|
404
|
+
import { useFonts } from "expo-font";
|
|
405
|
+
import { Stack } from "expo-router";
|
|
406
|
+
import * as SplashScreen from "expo-splash-screen";
|
|
407
|
+
import { useEffect } from "react";
|
|
408
|
+
import "react-native-reanimated";
|
|
409
|
+
import "../../global.css";
|
|
410
|
+
|
|
411
|
+
export { ErrorBoundary } from "expo-router";
|
|
412
|
+
|
|
413
|
+
export const unstable_settings = {
|
|
414
|
+
initialRouteName: "(tabs)",
|
|
324
415
|
};
|
|
325
416
|
|
|
326
|
-
|
|
417
|
+
SplashScreen.preventAutoHideAsync();
|
|
418
|
+
|
|
419
|
+
export default function RootLayout() {
|
|
420
|
+
const [loaded, error] = useFonts({
|
|
421
|
+
SpaceMono: require("../../assets/fonts/SpaceMono-Regular.ttf"),
|
|
422
|
+
...FontAwesome.font,
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
useEffect(() => {
|
|
426
|
+
if (error) throw error;
|
|
427
|
+
}, [error]);
|
|
428
|
+
|
|
429
|
+
useEffect(() => {
|
|
430
|
+
if (loaded) {
|
|
431
|
+
SplashScreen.hideAsync();
|
|
432
|
+
}
|
|
433
|
+
}, [loaded]);
|
|
434
|
+
|
|
435
|
+
if (!loaded) {
|
|
436
|
+
return null;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
return <RootLayoutNav />;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
function RootLayoutNav() {
|
|
443
|
+
return (
|
|
444
|
+
<Stack>
|
|
445
|
+
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
|
|
446
|
+
<Stack.Screen name="modal" options={{ presentation: "modal" }} />
|
|
447
|
+
</Stack>
|
|
448
|
+
);
|
|
449
|
+
}
|
|
327
450
|
`;
|
|
328
451
|
await fs.writeFile(path.join(appDir, "_layout.tsx"), rootLayout);
|
|
329
452
|
const tabsDir = path.join(appDir, "(tabs)");
|
|
330
453
|
await fs.ensureDir(tabsDir);
|
|
331
|
-
const layout = `import
|
|
454
|
+
const layout = `import React from 'react';
|
|
455
|
+
import FontAwesome from '@expo/vector-icons/FontAwesome';
|
|
456
|
+
import { Link, Tabs } from 'expo-router';
|
|
457
|
+
import { Pressable } from 'react-native';
|
|
458
|
+
import '../../global.css';
|
|
332
459
|
|
|
333
|
-
|
|
334
|
-
return <
|
|
335
|
-
}
|
|
460
|
+
function TabBarIcon(props: { name: React.ComponentProps<typeof FontAwesome>['name']; color: string; }) {
|
|
461
|
+
return <FontAwesome size={28} style={{ marginBottom: -3 }} {...props} />;
|
|
462
|
+
}
|
|
336
463
|
|
|
337
|
-
export default
|
|
464
|
+
export default function TabLayout() {
|
|
465
|
+
return (
|
|
466
|
+
<Tabs screenOptions={{ headerShown: true }}>
|
|
467
|
+
<Tabs.Screen
|
|
468
|
+
name="index"
|
|
469
|
+
options={{
|
|
470
|
+
title: 'Tab One',
|
|
471
|
+
tabBarIcon: ({ color }) => <TabBarIcon name="code" color={color} />,
|
|
472
|
+
headerRight: () => (
|
|
473
|
+
<Link href="/modal" asChild>
|
|
474
|
+
<Pressable>
|
|
475
|
+
{({ pressed }) => (
|
|
476
|
+
<FontAwesome name="info-circle" size={25} color={"#1f2937"} style={{ marginRight: 15, opacity: pressed ? 0.5 : 1 }} />
|
|
477
|
+
)}
|
|
478
|
+
</Pressable>
|
|
479
|
+
</Link>
|
|
480
|
+
),
|
|
481
|
+
}}
|
|
482
|
+
/>
|
|
483
|
+
<Tabs.Screen
|
|
484
|
+
name="two"
|
|
485
|
+
options={{
|
|
486
|
+
title: 'Tab Two',
|
|
487
|
+
tabBarIcon: ({ color }) => <TabBarIcon name="code" color={color} />,
|
|
488
|
+
}}
|
|
489
|
+
/>
|
|
490
|
+
</Tabs>
|
|
491
|
+
);
|
|
492
|
+
}
|
|
338
493
|
`;
|
|
339
494
|
await fs.writeFile(path.join(tabsDir, "_layout.tsx"), layout);
|
|
340
|
-
const
|
|
341
|
-
|
|
342
|
-
const Home = () => (
|
|
343
|
-
<View className="flex-1 items-center justify-center bg-background">
|
|
344
|
-
<Text className="text-foreground text-xl">Home Tab</Text>
|
|
345
|
-
</View>
|
|
346
|
-
);
|
|
495
|
+
const tabOne = `import { View, Text } from 'react-native';
|
|
347
496
|
|
|
348
|
-
export default
|
|
497
|
+
export default function Index() {
|
|
498
|
+
return (
|
|
499
|
+
<View className="flex-1 items-center justify-center bg-background">
|
|
500
|
+
<Text className="text-foreground text-xl">Tab One</Text>
|
|
501
|
+
</View>
|
|
502
|
+
);
|
|
503
|
+
}
|
|
349
504
|
`;
|
|
350
|
-
await fs.writeFile(path.join(tabsDir, "index.tsx"),
|
|
351
|
-
const
|
|
505
|
+
await fs.writeFile(path.join(tabsDir, "index.tsx"), tabOne);
|
|
506
|
+
const tabTwo = `import { View, Text } from 'react-native';
|
|
352
507
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
<
|
|
356
|
-
|
|
357
|
-
|
|
508
|
+
export default function Two() {
|
|
509
|
+
return (
|
|
510
|
+
<View className="flex-1 items-center justify-center bg-background">
|
|
511
|
+
<Text className="text-foreground text-xl">Tab Two</Text>
|
|
512
|
+
</View>
|
|
513
|
+
);
|
|
514
|
+
}
|
|
515
|
+
`;
|
|
516
|
+
await fs.writeFile(path.join(tabsDir, "two.tsx"), tabTwo);
|
|
517
|
+
const modal = `import { View, Text } from 'react-native';
|
|
358
518
|
|
|
359
|
-
export default
|
|
519
|
+
export default function Modal() {
|
|
520
|
+
return (
|
|
521
|
+
<View className="flex-1 items-center justify-center bg-background">
|
|
522
|
+
<Text className="text-foreground text-xl">Modal screen</Text>
|
|
523
|
+
</View>
|
|
524
|
+
);
|
|
525
|
+
}
|
|
360
526
|
`;
|
|
361
|
-
await fs.writeFile(path.join(
|
|
527
|
+
await fs.writeFile(path.join(appDir, "modal.tsx"), modal);
|
|
362
528
|
}
|
|
363
529
|
}
|
|
364
530
|
async function applyTemplateOverlay({ dest, type, template, category, variant }) {
|