-[](https://github.com/tterb/atomic-design-ui/blob/master/LICENSEs)
-[](https://img.shields.io/npm/v/@binarapps/expo-ts-template?style=flat-square)
-[](https://img.shields.io/npm/dt/@binarapps/expo-ts-template?style=flat-square)
-[](https://img.shields.io/github/stars/binarapps/expo-ts-template?style=flat-square)
+[](https://github.com/tterb/atomic-design-ui/blob/master/LICENSEs)
+[](https://img.shields.io/npm/v/@binarapps/baca-react-native-template?style=flat-square)
+[](https://img.shields.io/npm/dt/@binarapps/baca-react-native-template?style=flat-square)
+[](https://img.shields.io/github/stars/binarapps/baca-react-native-template?style=flat-square)
[](https://expo.dev/client)
# @binarapps/baca-react-native-template
@@ -18,7 +18,7 @@ This is a template to be used with react native and expo. It includes all the ne
## Documentation
-Check out our [documentation page](https://baca-docs.vercel.app/docs/bootstrap/intro), it contains:
+Check out our [documentation page](https://baca-docs.vercel.app/docs/overview), it contains:
- Bootstrapping project - tutorial how to easy setup from scratch
- Deploying app
@@ -28,15 +28,15 @@ Check out our [documentation page](https://baca-docs.vercel.app/docs/bootstrap/i
## Why to use?
-We know there are a lot of project starters for react native, but we have some good features:
+There are a lot of project starters for react native, we have some good features that other starters usually don't have:
- Fully works with **EXPO GO**
- Good for start of the project, later you can switch to expo-dev-client
- Fully works on **WEB**
- If you want to develop apps both on web and mobile this starter is good choice for you
-- **Code generators** (create new screen / create new component)
+- **Code generators** (create new screen / create new component and others)
- **Fully + Strong typed**
-- **App deployment documentation** (currently in progress, but it will be added in near future)
+- **App deployment documentation**
## How it looks?
@@ -48,35 +48,38 @@ We know there are a lot of project starters for react native, but we have some g
-[](https://www.youtube.com/watch?v=NmTd5nXXTLI)
+[](https://www.youtube.com/watch?v=NmTd5nXXTLI)
## How to use?
-We have prepared a detailed documentation for how to run project with this template - **[Bootstrap docs](https://baca-docs.vercel.app/docs/bootstrap/intro)**
+We have prepared a detailed documentation for how to run project with this template - **[Bootstrap docs](https://baca-docs.vercel.app/docs/overview)**
It's great for production project, but if you want to just test it, you can follow the quick steps (on the bottom).
### Quick steps:
-- `npx create-expo-app --template=@binarapps/expo-ts-template name_of_your_app`
+- `npx create-expo-app --template=@binarapps/baca-react-native-template name_of_your_app`
- `cd name_of_your_app`
- `yarn bootstrap` - the cli will ask you some questions about your app (you can fill all this data later)
## What's inside?
-[](https://img.shields.io/npm/types/@binarapps/expo-ts-template?style=flat-square)
-[](https://img.shields.io/github/package-json/dependency-version/binarapps/expo-ts-template/expo?style=flat-square)
-[](https://img.shields.io/github/package-json/dependency-version/binarapps/expo-ts-template/@react-navigation/native?style=flat-square)
+[](https://img.shields.io/npm/types/@binarapps/baca-react-native-template?style=flat-square)
+[](https://img.shields.io/github/package-json/dependency-version/binarapps/baca-react-native-template/expo?style=flat-square)
+[](https://img.shields.io/github/package-json/dependency-version/binarapps/baca-react-native-template/@react-navigation/native?style=flat-square)
### Implemented custom features
+- custom cli
+ - run `yarn baca` to see available options
- generators:
- - create screen - `yarn generate:screen`
- - create component - `yarn generate:component`
+ - `yarn baca generate` | `yarn g`
- support of multiple environments
- production, staging, qa
- eas configuration
- update, build, submit
+- deployment docs
+ - https://baca-docs.vercel.app/docs/overview
- verifying code on pull request - pipelines
- when creating pull request on github, there are tests, linters and types checks. If there will be some error you will be notified that something is wrong.
- custom fonts
@@ -117,11 +120,11 @@ It's great for production project, but if you want to just test it, you can foll
- [Reanimated v2](https://github.com/software-mansion/react-native-reanimated)
- Axios + React query
- Fetching data from backend
+- Jotai
+ - State management
## What is planned in the future?
-- add some state management tool - in progress
-- write docs (app deployment, app setup and more) - in progress
- tutorial on how to use features
- navigation
- deepLinking
@@ -136,7 +139,6 @@ It's great for production project, but if you want to just test it, you can foll
- Create sample app and document the process of deployment
- Improve mock server logic
- add commit lint
-- add script that display last update information (eas update)
### Implementations to add
@@ -157,13 +159,13 @@ Please adhere to this project's `code of conduct`.
Clone the project
```bash
- git clone https://github.com/binarapps/expo-ts-template.git
+ git clone https://github.com/binarapps/baca-react-native-template.git
```
Go to the project directory
```bash
- cd expo-ts-template
+ cd baca-react-native-template
```
Install dependencies
diff --git a/docs/docs/OVERVIEW.md b/docs/docs/OVERVIEW.md
new file mode 100644
index 00000000..0e48ea39
--- /dev/null
+++ b/docs/docs/OVERVIEW.md
@@ -0,0 +1,48 @@
+---
+id: overview
+slug: /overview
+title: Overview
+sidebar_position: 1
+tags:
+ - Bootstrap
+ - Getting started
+ - Project structure
+description: Bootstrap project structure, that is needed to start development your new project
+---
+
+# Overview
+
+**Welcome in BACA starter!**
+
+It is specialy designed to make react native apps development much easier and much faster.
+
+## Why to use?
+
+There are a lot of project starters for react native, we have some good features that other starters usually don't have:
+
+- Fully works with **EXPO GO**
+ - Good for start of the project, later you can switch to expo-dev-client
+- Fully works on **WEB**
+ - If you want to develop apps both on web and mobile this starter is good choice for you
+- **Code generators** (create new screen / create new component and others)
+- **Fully + Strong typed**
+- **App deployment documentation**
+
+## How to start?
+
+1. Create new app - follow [this docs](/docs/bootstrap/create-new-app)
+
+ - At this point you can start development
+ - When you will need to show app to testers or client go to next step
+
+2. Fill needed data to start deployment - follow [this docs](/docs/bootstrap/testing)
+
+ - This will make all required changes to the code base
+
+3. Prepare deployment - follow [this docs](/docs/deploy/intro)
+
+ - Thanks to this docs you will have possibility to automatically deploy app to testers and
+
+4. Send app to review and publish it on app stores
+
+ - We don't plan to make docs about that, but maybe in the future we will do that!
diff --git a/docs/docs/bootstrap/BOOTSTRAP_TESTING.mdx b/docs/docs/bootstrap/BOOTSTRAP_TESTING.mdx
index 9d0fe62c..95cd4b0e 100644
--- a/docs/docs/bootstrap/BOOTSTRAP_TESTING.mdx
+++ b/docs/docs/bootstrap/BOOTSTRAP_TESTING.mdx
@@ -1,7 +1,7 @@
---
id: bootstrap-testing
slug: /bootstrap/testing
-title: Bootstrap - testing
+title: Prepare for testing
sidebar_position: 2
tags:
- Bootstrap
@@ -103,6 +103,16 @@ If you have some domain, for example: example.com, your bundle id could be: `com
open your app when tapped. It is only available in standalone apps.
+
+
+> **Optional step** - You can run the bootstrap script later
+
+This can be found in developer apple console.
+
+> Image will be added in future
+
+
+
You can generate this data and save it in some notepad or somewhere else.
@@ -115,7 +125,8 @@ You can generate this data and save it in some notepad or somewhere else.
"slug": "expo_app_slug",
"easProjectId": "xxx-xxx-xxx-xx",
"scheme": "yourUrlScheme",
- "adaptiveIconBackgroundColor": "#2E7AF0CC"
+ "adaptiveIconBackgroundColor": "#2E7AF0CC",
+ "appleTeamId": "1234XXXYYX"
}
```
@@ -126,8 +137,15 @@ You can generate this data and save it in some notepad or somewhere else.
### **After you will collect all necessary data run this command:**
+> If you don't have some value you can use default value, bootstrap script is collecting current data from code, so you can run this script multiple times
+> **REMEBER** to have empty git repo because this script will do changes in your codebase
+
```sh
-yarn bootstrap:new_app
+yarn b
+
+## OR
+
+yarn baca bootstrap
```
## Potential issues
diff --git a/docs/docs/bootstrap/BOOTSTRAP_INTRO.mdx b/docs/docs/bootstrap/CREATE_NEW_APP.mdx
similarity index 79%
rename from docs/docs/bootstrap/BOOTSTRAP_INTRO.mdx
rename to docs/docs/bootstrap/CREATE_NEW_APP.mdx
index 226de4bf..056755fb 100644
--- a/docs/docs/bootstrap/BOOTSTRAP_INTRO.mdx
+++ b/docs/docs/bootstrap/CREATE_NEW_APP.mdx
@@ -1,10 +1,11 @@
---
id: bootstrap
-slug: /bootstrap/intro
-title: Bootstrap - start development
+slug: /bootstrap/create-new-app
+title: Create new app
sidebar_position: 1
tags:
- Bootstrap
+ - Create new app
- Getting started
- Project structure
description: Bootstrap project structure, that is needed to start development your new project
@@ -16,7 +17,7 @@ import Details from '@site/src/components/Details'
Bootstrap project structure, that is needed to start development
-## **What you need to do to start development?**
+## **What you need to do, to start development**
---
@@ -62,7 +63,12 @@ If you do not have expo account → register on your company email. In terminal
eas register
```
-You will be redirected to expo registration page. If something is not right please make sure you have eas cli installed - `npm install -g eas-cli`
+You will be redirected to expo registration page. If something is not right please make sure you have eas cli installed
+
+```bash
+npm install -g eas-cli
+
+```
Login to expo account on your local machine.
@@ -112,22 +118,28 @@ eas whoami
### Step 4.Sync project with code.
-Synchronize the newly created Expo Project to your app.
+Please gather this data:
+
+1. **app name** - you can add **display name** from previous step, or add anything you want here, this name will be displayed for users later
+2. **slug name** - created in 1-st point.
+3. **owner** - organization picked from the list in 1-st point
-In `app.json` file please insert the following:
+:::note
-1. **slug name** - created in 1-st point.
-2. **owner** - organization picked from the list in 1-st point
+If you will have issues with finding this values, please check [bootstrap testing docs](/docs/bootstrap/testing)
-```json
-{
- "expo": {
- "owner": "your_organization_name",
- "slug": "your_app_name"
- }
-}
+:::
+
+If you gather all this data please run this command:
+
+```bash
+yarn baca bootstrap --simple
```
+:::warning
+Please verify all changes made with the script
+:::
+
---
### Step 5. Make environment variables setup - [tutorial](/docs/doppler-config)
diff --git a/docs/docs/bootstrap/_category_.json b/docs/docs/bootstrap/_category_.json
index 9be6a2fc..db02be29 100644
--- a/docs/docs/bootstrap/_category_.json
+++ b/docs/docs/bootstrap/_category_.json
@@ -1,6 +1,6 @@
{
"label": "Start development",
- "position": 1,
+ "position": 2,
"collapsible": true,
"collapsed": false,
"link": {
diff --git a/docs/docs/deploy/_category_.json b/docs/docs/deploy/_category_.json
index 7f821806..1c146b5f 100644
--- a/docs/docs/deploy/_category_.json
+++ b/docs/docs/deploy/_category_.json
@@ -1,6 +1,6 @@
{
"label": "Deployment",
- "position": 2,
+ "position": 3,
"collapsible": true,
"collapsed": false,
"link": {
diff --git a/docs/docs/tutorials/ICONS.md b/docs/docs/tutorials/ICONS.md
index 1b1e326f..5ee9b766 100644
--- a/docs/docs/tutorials/ICONS.md
+++ b/docs/docs/tutorials/ICONS.md
@@ -40,4 +40,4 @@ It is added to the app as a font generated by [icomoon app](https://icomoon.io/a
9. Generate new types for icons
- - run script generating icon types `yarn generate:icon:types`
+ - run script generating icon types `yarn baca generate icon-types`
diff --git a/docs/docs/tutorials/NOTIFICATIONS_SETUP.md b/docs/docs/tutorials/NOTIFICATIONS_SETUP.md
index a4dfe463..785ec5f5 100644
--- a/docs/docs/tutorials/NOTIFICATIONS_SETUP.md
+++ b/docs/docs/tutorials/NOTIFICATIONS_SETUP.md
@@ -21,7 +21,7 @@ Expo notifications are already preconfigured in this template. However, you stil
## Usage in expo dev client (expo run:\[android:ios\])
1. Make sure you have created your account in [expo.dev](http://expo.dev).
-2. Follow [bootstrap](/docs/bootstrap/intro) docs
+2. Follow [bootstrap](/docs/bootstrap/create-new-app) docs
3. Follow platform specific configuration.
### Android
diff --git a/docs/docs/tutorials/SCRIPTS.md b/docs/docs/tutorials/SCRIPTS.md
new file mode 100644
index 00000000..eccc98a0
--- /dev/null
+++ b/docs/docs/tutorials/SCRIPTS.md
@@ -0,0 +1,74 @@
+---
+id: scripts
+slug: /scripts
+title: Scripts
+sidebar_position: 8
+tags:
+ - Scripts
+ - Expo
+ - React
+ - React Native
+description: BACA - scripts
+---
+
+
+
+# Scripts
+
+Here is a list of useful scripts in this starter:
+
+- [yarn g](#generators)
+- [yarn b](#bootstrap-new-app)
+- [yarn generate:last:publish](#generate-last-update-info)
+
+## Generators
+
+Run this command to see magic:
+
+```
+yarn g
+```
+
+OR
+
+```bash
+yarn baca generate
+```
+
+This will show you list of generators, run this to test it :)
+
+## Boostrap new app
+
+Check [boostrap docs](/docs/bootstrap/testing) to see more details.
+
+```
+yarn b
+```
+
+OR
+
+```bash
+yarn baca:boostrap
+```
+
+## Envrionment variables
+
+Check [doppler documentantion](/docs/doppler-config) to see more details
+
+## Generate last update info
+
+This script is automatically executed after running `yarn update:production` (or staging|qa), this will return ids of last udpate:
+
+```
+BACA - 2.1.0:
+- android: 8f6577b8-f1a6-46de-9471-8a0ff072ccc9
+- ios: a8bdc3aa-239a-48da-b76e-c259af5567b0
+```
+
+You can easily share this with testers or clients, thanks to that users will be sure what version is currently in the app.
+
+## Generate icon types
+
+This script has to be executed when new icons where added to the icomoon.ttf icons set in case to provide proper types for components which use icons.
+
+If script won't be executed typescript will throw an error when trying to use newly added icon.
diff --git a/docs/docs/tutorials/_category_.json b/docs/docs/tutorials/_category_.json
index 95985d9e..4ec1db4c 100644
--- a/docs/docs/tutorials/_category_.json
+++ b/docs/docs/tutorials/_category_.json
@@ -1,6 +1,6 @@
{
"label": "Tutorials",
- "position": 3,
+ "position": 4,
"collapsible": true,
"collapsed": false,
"link": {
diff --git a/docs/docusaurus.config.ts b/docs/docusaurus.config.ts
index 95c575b1..4e7a919b 100644
--- a/docs/docusaurus.config.ts
+++ b/docs/docusaurus.config.ts
@@ -72,9 +72,13 @@ const config: Config = {
{
title: 'Docs',
items: [
+ {
+ label: 'Overview',
+ to: '/docs/overview',
+ },
{
label: 'Intro',
- to: '/docs/bootstrap/intro',
+ to: '/docs/bootstrap/create-new-app',
},
],
},
@@ -106,6 +110,7 @@ const config: Config = {
prism: {
theme: prismThemes.github,
darkTheme: prismThemes.dracula,
+ additionalLanguages: ['bash'],
},
} satisfies Preset.ThemeConfig,
}
diff --git a/docs/src/pages/index.tsx b/docs/src/pages/index.tsx
index b54f693f..066b1fc0 100644
--- a/docs/src/pages/index.tsx
+++ b/docs/src/pages/index.tsx
@@ -18,7 +18,7 @@ function HomepageHeader() {
{siteConfig.tagline}
-
+
See docs
diff --git a/package.json b/package.json
index 3b70b3ea..5443f517 100644
--- a/package.json
+++ b/package.json
@@ -25,8 +25,11 @@
"license": "MIT",
"scripts": {
"android:dev-client": "IS_DEV=1 npx expo run:android",
- "bootstrap:new_app": "yarn && node ./scripts/bootstrap.js",
- "build:production:android": "yarn prepare:production && eas build --platform android --profile production",
+ "baca": "yarn build:baca-cli && node ./scripts/cli/build/scripts/cli",
+ "b": "yarn baca b",
+ "g": "yarn baca g",
+ "build:baca-cli": "npx tsc -p ./scripts/cli/tsconfig.cli.json",
+ "build:production:android": "yarnx prepare:production && eas build --platform android --profile production",
"build:production:ios": "yarn prepare:production && eas build --platform ios --profile production",
"build:production": "yarn prepare:production && eas build --platform all --profile production",
"build:qa:android": "yarn prepare:qa && eas build --platform android --profile qa",
@@ -44,20 +47,17 @@
"deploy:staging:android": "yarn prepare:staging && eas build --platform android --profile staging --auto-submit --non-interactive",
"deploy:staging:ios": "yarn prepare:staging && eas build --platform ios --profile staging --auto-submit --non-interactive",
"deploy:staging": "yarn prepare:staging && eas build --platform all --profile staging --auto-submit --non-interactive",
- "eas-build-pre-install": "base64 --help && echo $ANDROID_FIREBASE_CONFIG | base64 --decode > google-services.json && cat google-services.json && echo $IOS_FIREBASE_CONFIG | base64 --decode > GoogleService-Info.plist && cat GoogleService-Info.plist",
- "generate:component": "node ./scripts/create_new_component.js && yarn eslint src --fix && yarn tsc",
+ "eas-build-pre-install": "base64 --help && echo $ANDROID_FIREBASE_CONFIG | base64 --decode > google-services.json && cat google-services.json && echo $IOS_FIREBASE_CONFIG | base64 --decode > GoogleService-Info.plist && cat GoogleService-Info.plist",
"generate:env:production": "scripts/generate_dotenv.sh production",
"generate:env:qa": "scripts/generate_dotenv.sh qa",
"generate:env:staging": "scripts/generate_dotenv.sh staging",
"generate:google-services-config": "./scripts/generate_firebase_config.sh",
- "generate:icon:types": "node ./scripts/generate_icon_types.js",
"generate:last:publish": "node ./scripts/generate_last_update_id.js",
"generate:query": "yarn orval --config ./orval.config.ts",
- "generate:screen": "node ./scripts/create_new_screen.js && yarn eslint src --fix && yarn tsc",
"ios:dev-client": "IS_DEV=1 npx expo run:ios",
"lint:fix": "eslint src --fix",
"lint": "eslint src && yarn tsc",
- "postinstall": "patch-package",
+ "postinstall": "patch-package && yarn build:baca-cli",
"prebuild:android": "IS_DEV=1 npx expo prebuild --clean -p android",
"prebuild:ios": "IS_DEV=1 npx expo prebuild --clean -p ios",
"prepare:env_file": "cp ./templates/doppler_variables_template.sh ./scripts/doppler_variables.sh",
@@ -178,8 +178,10 @@
"babel-loader": "^9.1.3",
"babel-plugin-module-resolver": "^5.0.0",
"babel-preset-expo": "^10.0.0",
+ "commander": "^12.0.0",
"cross-env": "^7.0.3",
"dotenv": "^16.4.1",
+ "enquirer": "^2.4.1",
"eslint": "^8.56.0",
"eslint-config-prettier": "^8.8.0",
"eslint-config-universe": "^11.2.0",
@@ -198,11 +200,9 @@
"patch-package": "^7.0.1",
"prettier": "^2.8.8",
"pretty-quick": "^4.0.0",
- "prompt-sync": "^4.2.0",
"react-native-url-polyfill": "^2.0.0",
"react-test-renderer": "^18.2.0",
"readline": "^1.3.0",
- "select-prompt": "^0.3.2",
"text-encoding-polyfill": "^0.6.7",
"typescript": "^5.3.0",
"xmlhttprequest": "^1.8.0"
diff --git a/scripts/README.md b/scripts/README.md
index a4332363..b835ebfb 100644
--- a/scripts/README.md
+++ b/scripts/README.md
@@ -44,20 +44,23 @@ yarn prepare:qa
yarn prepare:staging
```
-## 3. `generate_icon_types.sh`
+## 3. generators
-This script has to be executed when new icons where added to the icomoon.ttf icons set in case to provide proper types for components which use icons.
-If script won't be executed typescript will throw an error when trying to use newly added icon.
-
-## 4. generators
+Run this command to see all available commands
```bash
-## Create new component
-yarn generate:screen
+yarn baca
+```
-## Create new screen
-yarn generate:component
+Our custom cli for now contain this screens:
-## Bootstrap the app
-yarn bootstrap:new_app
-```
+1. Generators
+
+- create new screen - `yarn baca generate screen`
+- create new component - `yarn baca generate component`
+- create icon types - `yarn baca generate icon-types`
+- create theme - `yarn baca generate theme`
+
+2. Bootstrap the app
+
+- `yarn baca bootstrap`
diff --git a/scripts/bootstrap.js b/scripts/bootstrap.js
deleted file mode 100644
index f7919222..00000000
--- a/scripts/bootstrap.js
+++ /dev/null
@@ -1,200 +0,0 @@
-/* eslint-disable @typescript-eslint/no-var-requires */
-const fs = require('fs')
-const prompt = require('prompt-sync')()
-
-const { logger, addAfter } = require('./utils')
-
-const paths = {
- appJson: './app.json',
- appConfig: './app.config.ts',
- readme: './README.md',
- readmeTemplate: './templates/readme_template.md',
- pullRequestTemplate: './.github/pull_request_template.md',
- newPullReuestTemplate: './templates/pull_request_template.md',
-}
-
-// 1.
-const replaceReadme = (appName, organizationOwner) => {
- let contents = fs.readFileSync(paths.readmeTemplate, 'utf8')
- contents = contents.replaceAll('_NAME_', appName)
- contents = contents.replaceAll('_OWNER_', organizationOwner)
-
- fs.writeFileSync(paths.readme, contents)
-}
-
-// 2.
-const setUpAppConfig = (appName, bundleId, androidPackageName, scheme, easId, androidIconColor) => {
- let contents = fs.readFileSync(paths.appConfig, 'utf8')
-
- const appConfig = `
-export const APP_CONFIG = {
- androidPackageName: '${androidPackageName}', // CONFIG: Add your android package name here
- appName: '${appName}', // CONFIG: Add your app name here
- easProjectId: '${easId}', // CONFIG: Add your eas project ID here
- iosBundleIdentifier: '${bundleId}', // CONFIG: Add your ios bundle identifier here
- scheme: '${scheme}', // CONFIG: Add your url scheme to link to your app
- adaptiveIconBackgroundColor: '${androidIconColor}', // CONFIG: Add your url scheme to link to your app
-} as const
-`
-
- contents = contents.replace(/(\/\/ APP_CONFIG_START)[\s\S]*?(\/\/ APP_CONFIG_END)/g, '$1$2')
-
- contents = addAfter(contents, '// APP_CONFIG_START', `${appConfig}`)
- fs.writeFileSync(paths.appConfig, contents)
-}
-
-// 3.
-const replatePullRequestTemplate = () => {
- const contents = fs.readFileSync(paths.newPullReuestTemplate, 'utf8')
-
- fs.writeFileSync(paths.pullRequestTemplate, contents)
-}
-
-// 4.
-const changeAppJson = (appName, appSlug, organizationOwner) => {
- const newAppJson = JSON.parse(fs.readFileSync(paths.appJson, 'utf8'))
- newAppJson.expo.slug = appSlug
- newAppJson.expo.name = appName
- newAppJson.expo.owner = organizationOwner
- newAppJson.version = '1.0.0'
- fs.writeFileSync(paths.appJson, JSON.stringify(newAppJson, null, 2))
-}
-
-// 5.
-const changePackageJson = (appName, organizationOwner) => {
- const packageJson = JSON.parse(fs.readFileSync('./package.json', 'utf8'))
- packageJson.name = `@${organizationOwner}/${appName}`
- packageJson.description = `App created from expo-template powered by binarapps`
- packageJson.version = '1.0.0'
-
- delete packageJson.repository
- delete packageJson.bugs
- delete packageJson.keywords
-
- fs.writeFileSync('./package.json', JSON.stringify(packageJson, null, 2))
-}
-
-// 6.
-const removeIssueTemplates = () => {
- fs.rm('./.github/ISSUE_TEMPLATE', { recursive: true, force: true }, () => {})
-}
-
-// 7.
-const removeDocsFolder = () => {
- fs.rm('./documentation', { recursive: true, force: true }, () => {})
-}
-
-const setUpProject = async (
- appName,
- bundleId,
- androidPackageName,
- scheme,
- easId,
- organizationOwner,
- androidIconColor,
- appSlug
-) => {
- // START
- logger.success('Start ...')
-
- // 1. Delete readme -> and create new, with new app name etc.
- logger.info('Generating new readme file')
- replaceReadme(appName, organizationOwner)
-
- // 2. Replace appName, bundleId, androidPackageName,scheme and easProjectId in app.config.ts file
- logger.info('Change project variables in app.config.ts file')
- setUpAppConfig(appName, bundleId, androidPackageName, scheme, easId, androidIconColor)
-
- // 3. Delete exist pull request template -> generate the new
- logger.info('Generating new pull request template file')
- replatePullRequestTemplate()
-
- // 4. Change app.json file
- logger.info('Change app.json file')
- changeAppJson(appName, appSlug, organizationOwner)
-
- // 5. Change package.json file
- logger.info('Change package.json file')
- changePackageJson(appName, organizationOwner)
-
- // 6. Remove issue templates
- logger.info('Remove issue templates')
- removeIssueTemplates()
-
- // 7. Remove docs folder
- logger.info('Remove docs folder')
- removeDocsFolder()
-
- //Finish
- logger.success(`Config your project has been success`)
-}
-
-const bootstrap = () => {
- logger.info('Please give me this information to setup your project:')
- const appName = prompt('App name: ')
- if (!appName) {
- return logger.error('Please write correct app name')
- }
-
- const appSlug = prompt('App slug (from expo dashboard): ')
- if (!appSlug) {
- return logger.error('Please write app slug')
- }
-
- const organizationOwner = prompt('Organization owner (from expo dashboard): ')
- if (!organizationOwner) {
- return logger.error('Please write organziation owner')
- }
-
- const easId = prompt('EAS project ID (from expo dashboard): ')
- if (!easId) {
- return logger.error('Please write correct eas project ID')
- }
-
- const androidIconColor =
- prompt('Android adaptive icon color (you can leave it empty and fill it later): ') ||
- '#2E7AF0CC'
-
- const bundleId = prompt('Bundle ID (ios): ')
- if (!bundleId) {
- return logger.error('Please write correct bundle ID')
- }
-
- const androidPackageName = prompt('Package name (android): ')
- if (!androidPackageName) {
- return logger.error('Please write correct android package name')
- }
-
- const scheme = prompt('URL scheme (for deeplinking): ')
- if (!scheme) {
- return logger.error('Please write correct scheme')
- }
-
- // 1. Setup project -> set ( appName, bundleId, androidPackageName, appScheme, easProjectId, organizationOwner, androidIconColor )
- setUpProject(
- appName,
- bundleId,
- androidPackageName,
- scheme,
- easId,
- organizationOwner,
- androidIconColor,
- appSlug
- )
-
- logger.info(
- '\nYou can also add images right now, go to assets folder and replace images to match your app \n'
- )
- logger.info('\nPlease verify the changes made by this script and commit it to your repository \n')
-}
-
-bootstrap()
-
-// INSTRUCTION:
-// 1. Delete readme and write the new one
-// 2. Setup app.config.ts file
-// 3. Setup pull_request_template.md
-// 4. Setup app.json file
-// 5. Setup package.json file
-// 6. Remove issue templates
-// 7. Remove docs folder
diff --git a/scripts/cli/actions/bootstrap.ts b/scripts/cli/actions/bootstrap.ts
new file mode 100644
index 00000000..38548722
--- /dev/null
+++ b/scripts/cli/actions/bootstrap.ts
@@ -0,0 +1,285 @@
+import { prompt } from 'enquirer'
+import fs from 'fs'
+
+import { APP_CONFIG } from '../../../app.config'
+import {
+ README_PATH,
+ APP_CONFIG_PATH,
+ NEW_PULL_REQUEST_TEMPLATE_PATH,
+ PULL_REQUEST_TEMPLATE_PATH,
+ APP_JSON_PATH,
+} from '../constants'
+import { logger, addAfter } from '../utils'
+
+const packageJson = JSON.parse(fs.readFileSync('./package.json', 'utf8'))
+const newAppJson = JSON.parse(fs.readFileSync(APP_JSON_PATH, 'utf8'))
+
+type SetupProjectProps = {
+ appName: string
+ bundleId: string
+ androidPackageName: string
+ scheme: string
+ easId: string
+ organizationOwner: string
+ androidIconColor: string
+ appSlug: string
+ appleTeamId: string
+}
+
+// Check types of questions here:
+// - https://github.com/enquirer/enquirer/blob/master/examples/enquirer/questions.js
+type Questions = keyof SetupProjectProps
+
+type QuestionsObject = {
+ [k in Questions]: {
+ type: string
+ message: string
+ initial: string
+ simple?: boolean
+ order: number
+ }
+}
+
+type Question = {
+ type: string
+ message: string
+ initial: string
+ order: number
+ name: string
+}
+
+const questionsObject: QuestionsObject = {
+ appName: {
+ type: 'text',
+ message: 'What is your app name?',
+ initial: APP_CONFIG.appName,
+ simple: true,
+ order: 1,
+ },
+ appSlug: {
+ type: 'text',
+ message: 'What is your expo app slug?',
+ initial: newAppJson.expo.slug,
+ simple: true,
+ order: 2,
+ },
+ organizationOwner: {
+ type: 'text',
+ message: 'What is your expo organization owner?',
+ initial: newAppJson.expo.owner,
+ simple: true,
+ order: 3,
+ },
+ bundleId: {
+ type: 'text',
+ message: 'What is your bundle Id?',
+ initial: APP_CONFIG.iosBundleIdentifier,
+ order: 4,
+ },
+ androidPackageName: {
+ type: 'text',
+ message: 'What is your android package name?',
+ initial: APP_CONFIG.androidPackageName,
+ order: 5,
+ },
+ scheme: {
+ type: 'text',
+ message: 'What is your scheme name?',
+ initial: APP_CONFIG.scheme,
+ order: 6,
+ },
+ easId: {
+ type: 'text',
+ message: 'What is your eas id?',
+ initial: APP_CONFIG.easProjectId,
+ order: 7,
+ },
+ androidIconColor: {
+ type: 'text',
+ message: 'What is your android icon color?',
+ initial: APP_CONFIG.adaptiveIconBackgroundColor,
+ order: 8,
+ },
+ appleTeamId: {
+ type: 'text',
+ message: 'What is your apple team id? (Optional)',
+ // FIXME: GET IT FROM EAS.JSON
+ initial: '5764GC687R',
+ order: 9,
+ },
+}
+
+/**
+ * Replaces placeholders in the README file with the provided app name and organization owner.
+ *
+ * @param appName - The name of the app.
+ * @param organizationOwner - The owner of the organization.
+ */
+const replaceReadme = ({ appName, organizationOwner }: SetupProjectProps) => {
+ let contents = fs.readFileSync(README_PATH, 'utf-8')
+
+ contents = contents.replaceAll('_NAME_', appName)
+ contents = contents.replaceAll('_OWNER_', organizationOwner)
+
+ fs.writeFileSync(README_PATH, contents)
+}
+
+/**
+ * Sets up the app configuration by updating the contents of the app config file.
+ *
+ * @param appName - The name of the app.
+ * @param bundleId - The bundle identifier for iOS.
+ * @param androidPackageName - The package name for Android.
+ * @param scheme - The URL scheme to link to the app.
+ * @param easId - The EAS project ID.
+ * @param androidIconColor - The background color for the adaptive icon on Android.
+ */
+const setUpAppConfig = ({
+ appName,
+ bundleId,
+ androidPackageName,
+ scheme,
+ easId,
+ androidIconColor,
+}: SetupProjectProps) => {
+ let contents = fs.readFileSync(APP_CONFIG_PATH, 'utf8')
+
+ const appConfig = `
+export const APP_CONFIG = {
+ androidPackageName: '${androidPackageName}', // CONFIG: Add your android package name here
+ appName: '${appName}', // CONFIG: Add your app name here
+ easProjectId: '${easId}', // CONFIG: Add your eas project ID here
+ iosBundleIdentifier: '${bundleId}', // CONFIG: Add your ios bundle identifier here
+ scheme: '${scheme}', // CONFIG: Add your url scheme to link to your app
+ adaptiveIconBackgroundColor: '${androidIconColor}', // CONFIG: Add your android adaptive icon background color here
+} as const
+`
+
+ contents = contents.replace(/(\/\/ APP_CONFIG_START)[\s\S]*?(\/\/ APP_CONFIG_END)/g, '$1$2')
+
+ contents = addAfter(contents, '// APP_CONFIG_START', `${appConfig}`)
+ fs.writeFileSync(APP_CONFIG_PATH, contents)
+}
+
+/**
+ * Replaces the contents of the pull request template file with the contents of a new pull request template file.
+ */
+const replacePullRequestTemplate = () => {
+ const contents = fs.readFileSync(NEW_PULL_REQUEST_TEMPLATE_PATH, 'utf8')
+
+ fs.writeFileSync(PULL_REQUEST_TEMPLATE_PATH, contents)
+}
+
+const changeAppJson = ({ appName, appSlug, organizationOwner }: SetupProjectProps) => {
+ newAppJson.expo.slug = appSlug
+ newAppJson.expo.name = appName
+ newAppJson.expo.owner = organizationOwner
+ newAppJson.expo.version = '1.0.0'
+
+ fs.writeFileSync(APP_JSON_PATH, JSON.stringify(newAppJson, null, 2))
+}
+
+const changePackageJson = ({ appName, organizationOwner }: SetupProjectProps) => {
+ packageJson.name = `@${organizationOwner}/${appName}`
+ packageJson.description = `App created from expo-template powered by binarapps`
+ packageJson.version = '1.0.0'
+
+ delete packageJson.repository
+ delete packageJson.bugs
+ delete packageJson.keywords
+
+ fs.writeFileSync('./package.json', JSON.stringify(packageJson, null, 2))
+}
+
+const removeIssueTemplates = () => {
+ fs.rm('./.github/ISSUE_TEMPLATE', { recursive: true, force: true }, () => {})
+}
+
+const removeDocsFolder = () => {
+ fs.rm('./docs', { recursive: true, force: true }, () => {})
+}
+
+// TODO: Implement changeEasJson and changeDeeplinkFiles functions
+const changeEasJson = (config: SetupProjectProps) => {}
+const changeDeeplinkFiles = (config: SetupProjectProps) => {}
+
+const setUpProject = async (config: SetupProjectProps) => {
+ // START
+ logger.success('Start bootstrapping ...')
+
+ // 1. Delete readme -> and create new, with new app name etc.
+ logger.info('Generating new readme file')
+ replaceReadme(config)
+
+ // 2. Replace appName, bundleId, androidPackageName,scheme and easProjectId in app.config.ts file
+ logger.info('Change project variables in app.config.ts file')
+ setUpAppConfig(config)
+
+ // 3. Delete exist pull request template -> generate the new
+ logger.info('Generating new pull request template file')
+ replacePullRequestTemplate()
+
+ // 4. Change app.json file
+ logger.info('Change app.json file')
+ changeAppJson(config)
+
+ // 5. Change package.json file
+ logger.info('Change package.json file')
+ changePackageJson(config)
+
+ // 6. Remove issue templates
+ logger.info('Remove issue templates')
+ removeIssueTemplates()
+
+ // 7. Remove docs folder
+ logger.info('Remove docs folder')
+ removeDocsFolder()
+
+ // 8. Change eas.json
+ changeEasJson(config)
+
+ // 9. Change deeplink files
+ changeDeeplinkFiles(config)
+
+ //Finish
+ logger.success(`Config your project has been success`)
+}
+
+type BootstrapConfig = { isSimple: boolean }
+
+const sortQuestions = (questions: Question[]) => {
+ return questions.sort((a, b) => a.order - b.order)
+}
+
+const getQuesstions = ({ isSimple }: BootstrapConfig) => {
+ const questions = Object.entries(questionsObject).map((value) => ({
+ name: value[0],
+ ...value[1],
+ }))
+
+ if (isSimple) {
+ return sortQuestions(questions.filter((question) => question.simple))
+ }
+
+ return sortQuestions(questions)
+}
+
+export const bootstrap = async (config: BootstrapConfig) => {
+ try {
+ logger.info('Please give me this information to setup your project:')
+
+ const answers = (await prompt(getQuesstions(config))) as unknown as SetupProjectProps
+
+ await setUpProject(answers)
+
+ logger.info(
+ '\nYou can also add images (splash screen, app icon, logos) right now, \nGo to `assets` folder and replace images to match your app.\n'
+ )
+ logger.info('\nPlease verify the changes made by this script and commit it to your repository.')
+ } catch (e) {
+ logger.error(
+ '\nError while bootstraping project \nERROR:',
+ e ? e : "Couldn't find what's happened"
+ )
+ }
+}
diff --git a/scripts/cli/actions/generate.ts b/scripts/cli/actions/generate.ts
new file mode 100644
index 00000000..8ef67d07
--- /dev/null
+++ b/scripts/cli/actions/generate.ts
@@ -0,0 +1,53 @@
+import { prompt } from 'enquirer'
+
+import { generateIconTypes, generateScreen, generateTheme, generateComponent } from '../commands'
+
+export const generators = [
+ {
+ title: 'Screen',
+ description: 'Generate new screen',
+ value: 'screen',
+ command: generateScreen,
+ },
+ {
+ title: 'Component',
+ description: 'Generate new component',
+ value: 'component',
+ command: generateComponent,
+ },
+ {
+ title: 'Icon types',
+ description: 'Generate new icon types - based on icon - `selection.json`',
+ value: 'icon-types',
+ command: generateIconTypes,
+ },
+ {
+ title: 'Generate theme',
+ description: 'Generate new theme - based on figma variables',
+ value: 'generate-theme',
+ command: generateTheme,
+ },
+] as const
+
+export const generate = async () => {
+ const promptAnswer = await prompt({
+ name: 'generator',
+ message: 'What do you want to generate?',
+ type: 'select',
+ choices: generators.map((generator) => ({
+ name: generator.title,
+ value: generator.value,
+ })),
+ })
+
+ // @ts-expect-error: generator not found on promptAnswer
+ const answerValue = promptAnswer?.generator as string
+
+ const command = generators.find((item) => item.title === answerValue)?.command
+
+ if (command) {
+ command()
+ } else {
+ console.log('There was some issue while running the script ', answerValue)
+ }
+}
diff --git a/scripts/cli/actions/index.ts b/scripts/cli/actions/index.ts
new file mode 100644
index 00000000..cb6fe6ad
--- /dev/null
+++ b/scripts/cli/actions/index.ts
@@ -0,0 +1,7 @@
+import { bootstrap } from './bootstrap'
+import { generate } from './generate'
+
+export const actions = {
+ generate,
+ bootstrap,
+}
diff --git a/scripts/create_new_component.js b/scripts/cli/commands/generateComponent.ts
similarity index 51%
rename from scripts/create_new_component.js
rename to scripts/cli/commands/generateComponent.ts
index a650cad8..882a95a2 100644
--- a/scripts/create_new_component.js
+++ b/scripts/cli/commands/generateComponent.ts
@@ -1,16 +1,17 @@
+import { prompt } from 'enquirer'
+
+import { COMPONENT_TEMPLATE_PATH, COMPONENTS_PATH } from '../constants'
+import { logger } from '../utils'
+
/* eslint-disable @typescript-eslint/no-var-requires */
const fs = require('fs')
-const prompt = require('prompt-sync')()
-const selectPrompt = require('select-prompt')
-
-const { logger } = require('./utils')
const paths = {
- template: './templates/component_template.tsx',
- componentsIndex: './src/components/index.ts',
+ template: COMPONENT_TEMPLATE_PATH,
+ componentsIndex: COMPONENTS_PATH,
}
-const createComponentFile = (name, type) => {
+const createComponentFile = (name: string, type: string) => {
const newCommonComponentPath = `./src/components/${name}.tsx`
const newAtomicComponentPath = `./src/components/${type}s/${name}.tsx`
const componentFromFile = fs.readFileSync(paths.template, 'utf8')
@@ -23,7 +24,7 @@ const createComponentFile = (name, type) => {
fs.writeFileSync(newAtomicComponentPath, componentContent)
}
-const addToIndex = (name, type) => {
+const addToIndex = (name: string, type: string) => {
const atomicComponentIndexPath = `./src/components/${type}s/index.ts`
const newExport = `
export * from './${name}'`
@@ -38,7 +39,7 @@ export * from './${name}'`
fs.writeFileSync(atomicComponentIndexPath, contents + newExport)
}
-const generateComponent = async (name, type) => {
+const generateNewComponent = async (name: string, type: string) => {
// Generate Component file
logger.info('Generating component files')
createComponentFile(name, type)
@@ -50,24 +51,30 @@ const generateComponent = async (name, type) => {
logger.success(`Component ${name} created successfully`)
}
-const generateNewComponent = async () => {
+export const generateComponent = async () => {
const componentTypes = [
- { title: 'Atom', value: 'atom' },
- { title: 'Molecule', value: 'molecule' },
- { title: 'Organism', value: 'organism' },
- { title: 'Common', value: 'common' },
+ { name: 'Molecule', value: 'molecule' },
+ { name: 'Organism', value: 'organism' },
+ { name: 'Common', value: 'common' },
]
- selectPrompt('Select type for new component', componentTypes, {
- cursor: 0,
- }).on('submit', async (type) => {
- const name = prompt('What is component name? ')
- if (!name) {
- return logger.error('No component name passed')
- }
- // 1. New component -> component_name + component_type (atom | molecule | organism | common)
- await generateComponent(name, type)
- })
-}
+ const promptAnswer = await prompt([
+ {
+ message: 'What is your component type?',
+ name: 'componentType',
+ type: 'select',
+ choices: componentTypes,
+ },
+ {
+ message: 'What is your component name?',
+ name: 'componentName',
+ type: 'input',
+ },
+ ])
+ // @ts-expect-error: componentType not found on promptAnswer
+ const componentType = promptAnswer.componentType as string
+ // @ts-expect-error: componentName not found on promptAnswer
+ const componentName = promptAnswer.componentName as string
-generateNewComponent()
+ await generateNewComponent(componentName, componentType)
+}
diff --git a/scripts/cli/commands/generateIconTypes.ts b/scripts/cli/commands/generateIconTypes.ts
new file mode 100644
index 00000000..e0c23a56
--- /dev/null
+++ b/scripts/cli/commands/generateIconTypes.ts
@@ -0,0 +1,17 @@
+import fs from 'fs'
+
+const prefix = `export type IconNames =
+ | `
+
+export const generateIconTypes = () => {
+ const json = fs.readFileSync('./assets/icomoon/selection.json')
+
+ const types = JSON.parse(json.toString())
+ .icons.map((icon: { properties: { name: string } }) => `'${icon.properties.name}'`)
+ .join('\n | ')
+ .concat('\n')
+
+ const content = prefix + types
+
+ fs.writeFileSync('./src/types/icon.d.ts', content)
+}
diff --git a/scripts/cli/commands/generateScreen.ts b/scripts/cli/commands/generateScreen.ts
new file mode 100644
index 00000000..27a18dc7
--- /dev/null
+++ b/scripts/cli/commands/generateScreen.ts
@@ -0,0 +1,192 @@
+import { prompt } from 'enquirer'
+// eslint-disable-next-line import/order
+import fs from 'fs'
+
+import { APP_ROUTER_DIRECTORY, SCREENS_DIRECTORY } from '../constants'
+import { getDirectoryNames, logger } from '../utils'
+
+const addAfter = (content: string, searchText: string, textToAdd: string) => {
+ return content.replace(searchText, searchText + textToAdd)
+}
+
+/**
+ * Recursively prompts the user to select a subdirectory and calls itself with the selected subdirectory path.
+ *
+ * @param basePath - The path of the current directory.
+ */
+const selectPath = async (basePath: string): Promise => {
+ const subDirectories = getDirectoryNames(basePath)
+ const hasSubDirectories = subDirectories.length > 0
+
+ // Return the result when there are no subdirectories
+ if (!hasSubDirectories) {
+ return basePath
+ }
+
+ const subDirectoryPrompt = subDirectories.map((directoryName) => ({
+ name: directoryName,
+ value: directoryName,
+ }))
+
+ if (basePath.includes('tabs')) {
+ subDirectoryPrompt.unshift({ name: '_New Tab_', value: 'new-tab' })
+ }
+
+ if (basePath !== APP_ROUTER_DIRECTORY) {
+ subDirectoryPrompt.unshift({ name: '.', value: '.' })
+ }
+
+ const promptAnswer = await prompt({
+ name: 'subValue',
+ message: 'What screen type do you want to generate?',
+ type: 'select',
+ choices: subDirectoryPrompt,
+ })
+
+ const subValue = subDirectoryPrompt.find(
+ // @ts-expect-error: subValue not found on promptAnswer
+ (promptValue) => promptValue.name === promptAnswer.subValue
+ )?.value
+
+ // Return the result when user selects current directory
+ if (subValue === '.') {
+ return basePath
+ }
+ // Recursively execute path selection when subValue is not the current directory
+ const subResult = await selectPath(`${basePath}/${subValue}`)
+
+ return subResult
+}
+
+/**
+ * Validates if a route with the given name already exists in the specified path.
+ * @param routeName - The name of the route.
+ * @param routePath - The path where the route should be generated.
+ * @throws Error if the route already exists in the specified path.
+ */
+const validateRoute = (routeName: string, routePath: string) => {
+ const filePath = `${routePath}/${routeName}.tsx`
+ if (fs.existsSync(filePath)) {
+ logger.error(`Route ${routeName} already exists in ${routePath}`)
+ }
+}
+
+/**
+ * Creates a route file with the given route name and path.
+ * @param {string} routeName - The name of the route.
+ * @param {string} routePath - The path where the route file will be created.
+ */
+const createRouteFile = (routeName: string, routePath: string) => {
+ const screenName = `${routeName.charAt(0).toUpperCase() + routeName.slice(1)}Screen`
+ fs.writeFileSync(
+ `${routePath}/${routeName.toLowerCase()}.tsx`,
+ `import { ${screenName} } from '@baca/screens'
+
+export default ${screenName}
+`
+ )
+}
+
+/**
+ * Validates if a screen with the given name already exists.
+ * @param screenName - The name of the screen.
+ * @throws Error if the screen already exists.
+ */
+const validateScreen = (screenName: string) => {
+ const filePath = `${SCREENS_DIRECTORY}/${screenName}.tsx`
+ if (fs.existsSync(filePath)) {
+ logger.error(`Screen ${screenName} already exists`)
+ }
+}
+
+/**
+ * Creates a screen file with the given screen name.
+ * @param {string} screenName - The name of the screen.
+ */
+const createScreenFile = (screenName: string) => {
+ const screenFromFile = fs.readFileSync('./templates/screen_template.tsx', 'utf8')
+ const screenContent = screenFromFile.replaceAll('_NAME_', screenName)
+
+ fs.writeFileSync(`${SCREENS_DIRECTORY}/${screenName}.tsx`, screenContent)
+}
+
+const addToScreensIndex = (screenName: string) => {
+ const indexFilePath = `${SCREENS_DIRECTORY}/index.ts`
+ const indexFile = fs.readFileSync(indexFilePath, 'utf8')
+ const newIndexFile = indexFile.padEnd(indexFile.length) + `export * from './${screenName}'\n`
+
+ fs.writeFileSync(indexFilePath, newIndexFile)
+}
+
+const promptTabName = async () => {
+ const promptAnswer = await prompt({
+ message: 'What is your screen name?',
+ name: 'tabName',
+ type: 'input',
+ })
+
+ // @ts-expect-error: generator not found on promptAnswer
+ const tabName = promptAnswer.tabName as string
+
+ if (!tabName) {
+ throw new Error('Tab name is required')
+ }
+ return tabName
+}
+
+const createNewNavTab = (tabName: string) => {
+ const navigationConfigFile = fs.readFileSync(
+ './src/navigation/tabNavigator/navigation-config.ts',
+ 'utf8'
+ )
+
+ const tabContent = `
+ {
+ displayedName: '${tabName.charAt(0).toUpperCase() + tabName.slice(1)}',
+ icon: 'zzz-line', // CONFIG: Add your icon name here
+ iconFocused: 'zzz-fill', // CONFIG: Add your icon name here
+ id: '${tabName}',
+ name: '${tabName}',
+ },`
+
+ const newContent = addAfter(navigationConfigFile, '// UPPER SIDE TABS', tabContent)
+ fs.writeFileSync('./src/navigation/tabNavigator/navigation-config.ts', newContent)
+}
+
+/**
+ * Generates a screen based on user input.
+ * Prompts the user to enter a screen name and selects a screen path.
+ * Validates the screen name and path.
+ */
+export const generateScreen = async () => {
+ const promptAnswer = await prompt({
+ message: 'What is your screen name?',
+ name: 'screenName',
+ type: 'input',
+ })
+
+ // @ts-expect-error: generator not found on promptAnswer
+ const routeName = promptAnswer.screenName as string
+
+ let routePath = await selectPath(APP_ROUTER_DIRECTORY)
+
+ const isNewTab = routePath.includes('(tabs)') && routePath.includes('new-tab')
+ if (isNewTab) {
+ const tabName = promptTabName()
+ createNewNavTab(routeName)
+
+ const newTabPath = routePath.replace('/new-tab', `/${tabName}`)
+ routePath = newTabPath
+
+ fs.mkdirSync(newTabPath)
+ }
+
+ validateRoute(routeName, routePath)
+ createRouteFile(routeName, routePath)
+
+ const screenName = `${routeName.charAt(0).toUpperCase() + routeName.slice(1)}Screen`
+ validateScreen(screenName)
+ createScreenFile(screenName)
+
+ addToScreensIndex(screenName)
+}
diff --git a/scripts/generate_theme.js b/scripts/cli/commands/generateTheme.ts
similarity index 56%
rename from scripts/generate_theme.js
rename to scripts/cli/commands/generateTheme.ts
index a0162168..72367247 100644
--- a/scripts/generate_theme.js
+++ b/scripts/cli/commands/generateTheme.ts
@@ -1,41 +1,44 @@
#!/usr/bin/env node
+/* eslint-disable @typescript-eslint/no-explicit-any */
// eslint-disable-next-line @typescript-eslint/no-var-requires
-const fs = require('fs')
-const json = fs.readFileSync('./assets/figma/variables.json')
+import fs from 'fs'
+
+const json = fs.readFileSync('./assets/figma/variables.json') as unknown as string
const figmaVariables = JSON.parse(json)
-const collections = figmaVariables.collections
+const collections = figmaVariables.collections as any
-const primitivesCollection = collections.find((collection) => collection.name === '_Primitives')
-const colorsCollection = collections.find((collection) => collection.name === '1. Color modes')
+const primitivesCollection = collections.find(
+ (collection: any) => collection.name === '_Primitives'
+)
+const colorsCollection = collections.find((collection: any) => collection.name === '1. Color modes')
-const primitivesColors = primitivesCollection.modes
- .find((mode) => mode.name === 'Style')
- .variables.filter((variable) => variable.type === 'color')
- .map((color) => ({ name: color.name, value: color.value }))
+const primitivesColors = primitivesCollection?.modes
+ ?.find((mode: any) => mode.name === 'Style')
+ ?.variables.filter((variable: any) => variable.type === 'color')
+ ?.map((color: any) => ({ name: color.name, value: color.value }))
// colorMode could be either 'light' or 'dark'
-const getModeColors = (colorMode) => {
+const getModeColors = (colorMode: string) => {
const modeName = colorMode === 'light' ? 'Light mode' : 'Dark mode'
- const modeColors = colorsCollection.modes.find((mode) => mode.name === modeName)?.variables
+ const modeColors = colorsCollection?.modes.find((mode: any) => mode.name === modeName)?.variables
const colors = modeColors
- .map((variable) => {
+ ?.map((variable: any) => {
if (variable.isAlias) {
- if (variable.value.collection === '_Primitives') {
- const primitiveColor = primitivesColors.find(
- (color) => color.name === variable.value.name
- )
+ const valueName = variable.value.name
+ if (variable?.value?.collection === '_Primitives') {
+ const primitiveColor = primitivesColors?.find((color: any) => color.name === valueName)
if (primitiveColor) {
return { name: variable.name, value: primitiveColor.value }
}
return null
} else {
- const newColor = modeColors.find((color) => color.name === variable.value.name)
+ const newColor = modeColors.find((color: any) => color.name === valueName)
if (newColor) {
- const primitiveColor = primitivesColors.find(
- (color) => color.name === newColor.value.name
+ const primitiveColor = primitivesColors?.find(
+ (color: any) => color.name === newColor.value.name
)
if (primitiveColor) {
return { name: variable.name, value: primitiveColor.value }
@@ -49,11 +52,12 @@ const getModeColors = (colorMode) => {
})
.filter(Boolean)
- const colorsArray = colors.map((color) => {
- return { [color.name.split('/').pop().split(' ').shift() || '']: color.value }
+ const colorsArray = colors?.map((color: any) => {
+ const keyName = color?.name?.split?.('/')?.pop()?.split(' ').shift() || ''
+ return { [keyName]: color?.value }
})
- const colorsInMode = colorsArray.reduceRight((acc, color) => {
+ const colorsInMode = colorsArray?.reduceRight((acc: any, color: any) => {
const [entries] = Object.entries(color)
const nestedKeys = entries[0].split('-')
@@ -63,6 +67,10 @@ const getModeColors = (colorMode) => {
return mergeObjects(acc, newValue)
}, {})
+ if (!colorsInMode) {
+ return
+ }
+
const sortedColors = sortObject(colorsInMode)
return sortedColors
}
@@ -70,11 +78,11 @@ const getModeColors = (colorMode) => {
const light = getModeColors('light')
const dark = getModeColors('dark')
-const primitivesColorsArray = primitivesColors.map((color) => {
+const primitivesColorsArray = primitivesColors?.map((color: any) => {
return { [color.name.split('/').slice(1).join('-')]: color.value }
})
-const primitives = primitivesColorsArray.reduceRight((acc, color) => {
+const primitives = primitivesColorsArray?.reduceRight((acc: any, color: any) => {
const [entries] = Object.entries(color)
const colorName = entries[0].split('_')
@@ -94,18 +102,20 @@ const primitives = primitivesColorsArray.reduceRight((acc, color) => {
const theme = {
darkMode: dark,
lightMode: light,
- primitives: sortObject(primitives),
+ primitives: primitives ? sortObject(primitives) : undefined,
}
const objectString = `export const themeColors = ${JSON.stringify(theme, null, 2)}`
-// Specify the file path
-const filePath = './src/design-system/config/colors.ts'
+export const generateTheme = () => {
+ // Specify the file path
+ const filePath = './src/design-system/config/colors.ts'
-fs.writeFileSync(filePath, objectString, 'utf-8')
+ fs.writeFileSync(filePath, objectString, 'utf-8')
+}
// Utils
-function createNestedObject(keys, value) {
+function createNestedObject(keys: any[], value: any) {
if (keys.length === 0) {
return value
}
@@ -113,15 +123,15 @@ function createNestedObject(keys, value) {
const key = keys[0]
const remainingKeys = keys.slice(1)
- const nestedObject = {}
+ const nestedObject: any = {}
nestedObject[key] = createNestedObject(remainingKeys, value)
return nestedObject
}
-function mergeObjects(obj1, obj2) {
+function mergeObjects(obj1: any, obj2: any) {
// Initialize the result object
- const result = {}
+ const result: any = {}
// Loop through keys in obj1
for (const key in obj1) {
@@ -146,7 +156,7 @@ function mergeObjects(obj1, obj2) {
return result
}
-function sortObject(obj) {
+function sortObject(obj?: object): any {
if (typeof obj !== 'object' || obj === null) {
return obj
}
@@ -155,11 +165,12 @@ function sortObject(obj) {
return obj.map(sortObject)
}
- const sorted = {}
+ const sorted: any = {}
Object.keys(obj)
.sort()
.forEach((key) => {
- sorted[key] = sortObject(obj[key])
+ const objectToSort = (obj as any)[key]
+ sorted[key] = sortObject(objectToSort)
})
return sorted
}
diff --git a/scripts/cli/commands/index.ts b/scripts/cli/commands/index.ts
new file mode 100644
index 00000000..e738d13e
--- /dev/null
+++ b/scripts/cli/commands/index.ts
@@ -0,0 +1,4 @@
+export * from './generateComponent'
+export * from './generateIconTypes'
+export * from './generateScreen'
+export * from './generateTheme'
diff --git a/scripts/cli/constants.ts b/scripts/cli/constants.ts
new file mode 100644
index 00000000..7b35d2f6
--- /dev/null
+++ b/scripts/cli/constants.ts
@@ -0,0 +1,16 @@
+export const CLI_ACTIONS = ['generate', 'g', 'bootstrap', 'b']
+
+export const APP_ROUTER_DIRECTORY = 'app/(app)'
+export const SCREENS_DIRECTORY = 'src/screens'
+
+// Paths
+export const NAVIGATION_CONFIG_PATH = 'navigation/tabNavigator/navigation-config.ts'
+export const APP_JSON_PATH = 'app.json'
+export const APP_CONFIG_PATH = 'app.config.ts'
+export const README_PATH = 'README.md'
+
+export const COMPONENTS_PATH = 'src/components/index.ts'
+export const COMPONENT_TEMPLATE_PATH = 'templates/component_template.tsx'
+export const README_TEMPLATE_PATH = 'templates/README.md'
+export const PULL_REQUEST_TEMPLATE_PATH = '.github/pull_request_template.md'
+export const NEW_PULL_REQUEST_TEMPLATE_PATH = 'templates/pull_request_template.md'
diff --git a/scripts/cli/index.ts b/scripts/cli/index.ts
new file mode 100644
index 00000000..0e0aa4c6
--- /dev/null
+++ b/scripts/cli/index.ts
@@ -0,0 +1,51 @@
+// #!/usr/bin/env node
+import { Command } from 'commander'
+
+import { actions } from './actions'
+import { generators } from './actions/generate'
+
+class CommandWithTrace extends Command {
+ createCommand(name: string) {
+ const cmd = new CommandWithTrace(name)
+ // Add an option to subcommands created using `.command()`
+ cmd.option('-t, --trace', 'display extra information when run command')
+ return cmd
+ }
+}
+
+function inpectCommand(command: Command) {
+ // The option value is stored as property on command because we called .storeOptionsAsProperties()
+
+ console.log(command.helpInformation())
+}
+
+const program = new CommandWithTrace('baca').action((options, command) => {
+ inpectCommand(command)
+})
+
+const generateGroup = program
+ .command('generate [params...]')
+ .description('Run generators, please check `g -h` to check available generators')
+ .alias('g')
+ .action(() => {
+ actions.generate()
+ })
+
+generators.forEach((generator) => {
+ generateGroup
+ .command(generator.value)
+ .description(generator.description)
+ .action(() => generator.command())
+})
+
+program
+ .command('bootstrap')
+ .option('-s, --simple', 'Run bootstrap simple with needed values')
+ .description('Bootstrap of new project')
+ .alias('b')
+ .action((buildTarget) => {
+ const isSimple = buildTarget.simple ?? false
+ actions.bootstrap({ isSimple })
+ })
+
+program.parse()
diff --git a/scripts/cli/tsconfig.cli.json b/scripts/cli/tsconfig.cli.json
new file mode 100644
index 00000000..0aa0ebac
--- /dev/null
+++ b/scripts/cli/tsconfig.cli.json
@@ -0,0 +1,17 @@
+{
+ "$schema": "https://json.schemastore.org/tsconfig",
+ "compilerOptions": {
+ "noImplicitAny": false,
+ "outDir": "build",
+ "strict": true,
+ "lib": ["ESNext"],
+ "target": "es6",
+ "module": "commonjs",
+ "sourceMap": false,
+ "esModuleInterop": true,
+ "moduleResolution": "node",
+ "skipLibCheck": true,
+ "allowJs": false
+ },
+ "include": ["../../app.config.ts", "**/*"]
+}
diff --git a/scripts/cli/utils/content.ts b/scripts/cli/utils/content.ts
new file mode 100644
index 00000000..105bd1c0
--- /dev/null
+++ b/scripts/cli/utils/content.ts
@@ -0,0 +1,34 @@
+/**
+ * Adds the specified text after the first occurrence of the search text in the content.
+ *
+ * @param content - The original content string.
+ * @param searchText - The text to search for in the content.
+ * @param textToAdd - The text to add after the first occurrence of the search text.
+ * @returns The modified content string with the text added.
+ */
+export const addAfter = (content: string, searchText: string, textToAdd: string) => {
+ return content.replace(searchText, searchText + textToAdd)
+}
+
+/**
+ * Adds the specified text before the first occurrence of the search text in the content.
+ *
+ * @param content - The original content string.
+ * @param searchText - The text to search for in the content.
+ * @param textToAdd - The text to add before the first occurrence of the search text.
+ * @returns The modified content string with the text added before the first occurrence of the search text.
+ */
+export const addBefore = (content: string, searchText: string, textToAdd: string) => {
+ return content.replace(searchText, textToAdd + searchText)
+}
+
+/**
+ * Deletes all occurrences of a specified search text from the given content.
+ *
+ * @param content - The content from which to delete the search text.
+ * @param searchText - The text to be deleted from the content.
+ * @returns The updated content with all occurrences of the search text removed.
+ */
+export const deleteText = (content: string, searchText: string) => {
+ return content.replace(searchText, '')
+}
diff --git a/scripts/cli/utils/getDirectoryNames.ts b/scripts/cli/utils/getDirectoryNames.ts
new file mode 100644
index 00000000..494b7ba0
--- /dev/null
+++ b/scripts/cli/utils/getDirectoryNames.ts
@@ -0,0 +1,28 @@
+import fs from 'fs'
+
+import { logger } from './logger'
+
+/**
+ * Retrieves the names of all sub-directories in the specified directory.
+ *
+ * @param directoryPath - The path of the directory to retrieve directory names from.
+ * @returns An array of directory names.
+ */
+export const getDirectoryNames = (directoryPath: string): string[] => {
+ try {
+ if (directoryPath.includes('new-tab')) return []
+ // Read the contents of the directory
+ const contents = fs.readdirSync(directoryPath)
+
+ // Filter out only directories
+ const folderNames = contents.filter((item) => {
+ const stat = fs.statSync(`${directoryPath}/${item}`)
+ return stat.isDirectory()
+ })
+
+ return folderNames
+ } catch (err) {
+ logger.error(`Error reading directory: ${err}`)
+ return []
+ }
+}
diff --git a/scripts/cli/utils/index.ts b/scripts/cli/utils/index.ts
new file mode 100644
index 00000000..b2d0878f
--- /dev/null
+++ b/scripts/cli/utils/index.ts
@@ -0,0 +1,3 @@
+export * from './getDirectoryNames'
+export * from './content'
+export * from './logger'
diff --git a/scripts/cli/utils/logger.ts b/scripts/cli/utils/logger.ts
new file mode 100644
index 00000000..f55b9dd1
--- /dev/null
+++ b/scripts/cli/utils/logger.ts
@@ -0,0 +1,19 @@
+const LCERROR = '\x1b[31m%s\x1b[0m' //red
+const LCWARN = '\x1b[33m%s\x1b[0m' //yellow
+const LCINFO = '\x1b[36m%s\x1b[0m' //cyan
+const LCSUCCESS = '\x1b[32m%s\x1b[0m' //green
+
+export const logger = {
+ error: (message: string, ...optionalParams: unknown[]) => {
+ console.error(LCERROR, message, ...optionalParams)
+ },
+ warn: (message: string, ...optionalParams: unknown[]) => {
+ console.warn(LCWARN, message, ...optionalParams)
+ },
+ info: (message: string, ...optionalParams: unknown[]) => {
+ console.info(LCINFO, message, ...optionalParams)
+ },
+ success: (message: string, ...optionalParams: unknown[]) => {
+ console.info(LCSUCCESS, message, ...optionalParams)
+ },
+}
diff --git a/scripts/create_new_screen.js b/scripts/create_new_screen.js
deleted file mode 100644
index 04579139..00000000
--- a/scripts/create_new_screen.js
+++ /dev/null
@@ -1,318 +0,0 @@
-/* eslint-disable @typescript-eslint/no-var-requires */
-const fs = require('fs')
-const prompt = require('prompt-sync')()
-const selectPrompt = require('select-prompt')
-
-const Content = require('./contents/content')
-const { addAfter, addBefore, execPromise, logger } = require('./utils')
-
-const enumsFileSrc = './src/navigation/config/enums.ts'
-const screensFileSrc = './src/navigation/config/screens.ts'
-const tabsFileSrc = './src/navigation/config/tabs.ts'
-const typesFileSrc = './src/navigation/config/navigation.d.ts'
-const screensIndexFileSrc = './src/screens/index.ts'
-
-/**
- * @param {string} name
- */
-const validateScreen = (name) => {
- const enumsFile = require('./temp/enums')
-
- Object.values(enumsFile).forEach((enumValue) => {
- if (enumValue[name]) {
- logger.error(`Screen with name ${name} already exists`)
- process.exit(1)
- }
- })
-}
-
-/**
- * @typedef {{
- * "tabs",
- * "tabs_new",
- * "root",
- * }} TYPES
- */
-
-const createScreenFile = (name) => {
- const screenFromFile = fs.readFileSync('./templates/screen_template.tsx', 'utf8')
- const screenContent = screenFromFile
- .replaceAll('_NAME_', name)
- .replace("// @ts-expect-error: it's a template and will be removed", '')
-
- fs.writeFileSync(`./src/screens/${name}Screen.tsx`, screenContent)
-}
-
-/**
- * @param {string} name
- * @param {Object} screenType
- * @param {string} screenType.value
- * @param {keyof TYPES} screenType.type
- */
-const addToEnums = (name, screenType) => {
- const enumsFile = require('./temp/enums')
- const contents = fs.readFileSync(enumsFileSrc, 'utf8')
- const StackScreens =
- screenType.type === 'root' ? 'RootStackScreens' : screenType.value + 'Screens'
-
- // 3. a) LOGIC WHEN ADDING NEW TAB
- if (screenType.type === 'tabs_new') {
- let newContents = addAfter(
- contents,
- 'export const BottomTabsScreens = {',
- Content.bottomTab(screenType.value)
- )
-
- newContents = addBefore(
- newContents,
- '// ExamplesStack_SCREENS',
- Content.tabEnum(screenType.value, StackScreens, name)
- )
-
- fs.writeFileSync(enumsFileSrc, newContents)
- return
- }
-
- // 1. a), 2. a) LOGIC WHEN ADDING ONLY NEW SCREEN - ROOT STACK AND BOTTOM TABS
- const startIdx = contents.indexOf(`export const ${StackScreens} = {`)
- const endIdxString = '} as const'
- const endIdx = contents.indexOf(endIdxString, startIdx) + endIdxString.length
- const rootStackScreensData = enumsFile[StackScreens]
- rootStackScreensData[name] = name
-
- // Convert the updated object back to a string
- const updatedRootStackScreensDataStr = `export const ${StackScreens} = ${JSON.stringify(
- rootStackScreensData,
- null,
- 2
- )} as const`
-
- // Write the updated contents back to the file
- fs.writeFileSync(
- enumsFileSrc,
- contents.substring(0, startIdx) + updatedRootStackScreensDataStr + contents.substring(endIdx)
- )
-}
-
-/**
- * @param {string} name
- * @param {Object} screenType
- * @param {string} screenType.value
- * @param {keyof TYPES} screenType.type
- */
-const addToScreens = (name, screenType) => {
- const screenNameType = screenType.type === 'root' ? 'RootStack' : screenType.value
- const newScreen = Content.screenOptions(name, screenNameType)
- let contents =
- screenType.type === 'root'
- ? fs.readFileSync(screensFileSrc, 'utf8')
- : fs.readFileSync(tabsFileSrc, 'utf8')
-
- if (screenType.type === 'tabs_new') {
- // 3. c) Add new tab to bottomTabs and create stack with screen
- contents = addBefore(contents, '// StackEnums', Content.screenEnumImport(screenType.value))
- contents = addBefore(contents, "} from '@baca/screens'", Content.screenNameImport(name))
- contents = addBefore(
- contents,
- '// ExamplesStack_SCREENS_START',
- Content.newTab(screenType.value, newScreen)
- )
- contents = addBefore(contents, '// BottomTab_SCREENS_END', Content.tabOptions(screenType.value))
- } else {
- // 1. c), 2. c) Add screen to specific group (screens or tabs)
- const typeToSearch = `// ${screenType.value}_SCREENS_END`
-
- typeToSearch.replace(screenType.value, screenType.value)
- contents = addBefore(contents, typeToSearch, newScreen)
- contents = addBefore(contents, "} from '@baca/screens'", Content.screenNameImport(name))
- }
-
- const path = screenType.type === 'root' ? screensFileSrc : tabsFileSrc
- fs.writeFileSync(path, contents)
-}
-
-/**
- * @param {string} name
- * @param {Object} screenType
- * @param {string} screenType.value
- * @param {keyof TYPES} screenType.type
- */
-const addToTypes = (name, screenType) => {
- let contents = fs.readFileSync(typesFileSrc, 'utf8')
- // 1. b) Add screen to navigation types
- if (screenType.type === 'root') {
- contents = addAfter(contents, `// Root_${screenType.value}`, Content.newAuthorizedScreen(name))
- contents = addAfter(contents, ' // RootStack_SCREENS', Content.screenComposite(name))
- }
- // 2. b) Add screen to certain params list in navigation types
- if (screenType.type === 'tabs') {
- contents = addAfter(
- contents,
- `type ${screenType.value}ParamList = {`,
- Content.newAuthorizedScreen(name)
- )
- contents = addAfter(contents, ` // ${screenType.value}_SCREENS`, Content.screenComposite(name))
- }
-
- // 3. b) Add stack param list with new screen
- if (screenType.type === 'tabs_new') {
- contents = addAfter(contents, '// PARAMS', Content.bottomTabParamsList(screenType.value, name))
- contents = addBefore(
- contents,
- ' // BottomTabScreenProps END',
- Content.bottomTabScreenProps(screenType.value)
- )
- contents = addBefore(
- contents,
- ' ExamplesStackParamList) = keyof RootStackParamList',
- Content.screenCompositeKey(screenType.value)
- )
- contents = addAfter(
- contents,
- '> = StackScreenProps<',
- Content.screenCompositeValue(screenType.value)
- )
- contents = addBefore(
- contents,
- '// MainTabParamList END',
- Content.navigatorScreenParams(screenType.value)
- )
- contents = addBefore(contents, '// WebTabParamListEnd', Content.webTabBar(screenType.value))
- contents = addBefore(
- contents,
- ` // HomeStack_SCREENS`,
- Content.newBottomTabScreenComposite(screenType.value, name)
- )
- }
-
- fs.writeFileSync(typesFileSrc, contents)
-}
-
-const addToIndex = (name) => {
- const newExport = `
-export * from './${name}Screen'`
-
- const contents = fs.readFileSync(screensIndexFileSrc, 'utf8')
-
- fs.writeFileSync(screensIndexFileSrc, contents + newExport)
-}
-
-const makeFirstLetterUppercase = (name) => {
- return name.charAt(0).toUpperCase() + name.slice(1)
-}
-
-/**
- * @param {string} name
- * @param {Object} screenType
- * @param {string} screenType.value
- * @param {keyof TYPES} screenType.type
- */
-const generateScreen = async (name, screenType) => {
- // Make the first letter of the screen name uppercase
- const newScreenName = makeFirstLetterUppercase(name)
-
- // VALIDATE IF SCREEN NAME IS VALID
- validateScreen(newScreenName)
-
- // GENERATE SCREEN FILE
- logger.info('Generating screen files')
- createScreenFile(newScreenName)
-
- // ADD SCREEN TO INDEX, ENUMS, SCREENS, TYPES
- addToIndex(newScreenName)
- addToEnums(newScreenName, screenType)
- addToScreens(newScreenName, screenType)
- addToTypes(newScreenName, screenType)
-
- // Remove temp files
- logger.info('Removing temp files')
- await execPromise('rm -rf ./scripts/temp')
-
- // FISNISH
- logger.success(`Screen ${name} created successfully`)
-}
-
-const generateNewScreen = async () => {
- logger.info('Creating temp files files')
- await execPromise(`yarn tsc ${enumsFileSrc} --outDir ./scripts/temp --skipLibCheck`)
-
- const rootVsBottomTabs = [
- { title: 'Root stack', value: 'root' },
- { title: 'Bottom tabs', value: 'tabs' },
- ]
-
- const rootScreenTypes = [
- { title: 'Authorized', value: 'authorized' },
- { title: 'Not authorized', value: 'unauthorized' },
- { title: 'Modal', value: 'modals' },
- { title: 'Normal - authorized and not authorized', value: 'normal' },
- ]
-
- const enumsFile = require('./temp/enums')
-
- const bottomTabsScreens = Object.keys(enumsFile.BottomTabsScreens)
- const bottomTabsTypes = bottomTabsScreens
- .map((tab) => ({ title: tab, value: tab }))
- .concat({ title: 'New tab', value: '_new' })
-
- selectPrompt('Do you want this screen on root stack or on bottom tabs?', rootVsBottomTabs, {
- cursor: 0,
- }).on('submit', async (stackType) => {
- if (stackType === 'root') {
- selectPrompt('Select what type is this screen', rootScreenTypes, {
- cursor: 1,
- }).on('submit', async (screenType) => {
- const name = prompt('What is screen name? ')
- if (!name) {
- return logger.error('No screen name passed')
- }
- // 1. NEW root screen -> screen_name + screen_type (authorized | not_authorized | modal | normal)
- generateScreen(name, { type: 'root', value: screenType })
- })
- }
-
- if (stackType === 'tabs') {
- selectPrompt('Select what type is this screen', bottomTabsTypes, {
- cursor: 1,
- }).on('submit', async (screenType) => {
- const name = prompt('What is screen name? ')
- if (!name) {
- return console.log('No screen name passed')
- }
-
- // Logic when adding new tab
- if (screenType === '_new') {
- const bottomTabName = prompt('What is bottom tab name? ')
- // 2. New bottom tab screen - screen_name + bottom_tab_name
- generateScreen(name, { type: 'tabs_new', value: bottomTabName + 'Stack' })
- return
- }
-
- // 3. New bottom tab => screen_name + bottom_tab_name
- generateScreen(name, { type: 'tabs', value: screenType })
- })
- }
- })
-}
-
-generateNewScreen()
-
-// INSTRUCTION
-// 0. Common
-// a) index.ts -> export
-// b) screen_name.ts -> screen_name component
-
-// 1. NEW root screen -> screen_name + screen_type (authorized | not_authorized | modal | normal)
-// a) enums.ts -> const RootStackScreens = {
-// b) navigation.d.ts -> type RootStackParamList = {
-// c) screens.ts -> import + rootStackScreensData.authorized
-
-// 2. New bottom tab screen - screen_name + bottom_tab_name (ExampleStack)
-// a) enums.ts -> const {bottom_tab_name}Screens = {
-// b) navigation.d.ts -> type {bottom_tab_name}ParamList = {
-// c) tabs.ts -> import + // HomeStack_SCREENS_END (before)
-
-// 3. New bottom tab => screen_name + bottom_tab_name
-// a) enums.ts -> const {bottom_tab_name}StackScreens = { + export const BottomTabsScreens = { (after)
-// b) navigation.d.ts -> type {bottom_tab_name}ParamList = {
-// c) tabs.ts -> import + // ${bottom_tab_name}_SCREENS_END (before)
diff --git a/scripts/generate_icon_types.js b/scripts/generate_icon_types.js
deleted file mode 100644
index aaa50f06..00000000
--- a/scripts/generate_icon_types.js
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/usr/bin/env node
-
-// eslint-disable-next-line @typescript-eslint/no-var-requires
-const fs = require('fs')
-
-const prefix = `export type IconNames =
- | `
-const json = fs.readFileSync('./assets/icomoon/selection.json')
-
-const types = JSON.parse(json)
- .icons.map((icon) => `'${icon.properties.name}'`)
- .join('\n | ')
- .concat('\n')
-
-const content = prefix + types
-
-fs.writeFileSync('./src/types/icon.d.ts', content)
diff --git a/src/components/README.md b/src/components/README.md
index 3a7d493b..e2f39956 100644
--- a/src/components/README.md
+++ b/src/components/README.md
@@ -1,6 +1,6 @@
# Components
-Components in [expo-ts-template](https://github.com/binarapps/expo-ts-template) follows [atomic design methodology](https://atomicdesign.bradfrost.com/).
+Components in [baca-react-native-template](https://github.com/binarapps/baca-react-native-template) follows [atomic design methodology](https://atomicdesign.bradfrost.com/).
For more information on such a design methodology, visit the page above.
On the other hand, below you can find documentation of the implemented components
diff --git a/src/navigation/tabNavigator/navigation-config.ts b/src/navigation/tabNavigator/navigation-config.ts
index 1ca342d7..9fc6862e 100644
--- a/src/navigation/tabNavigator/navigation-config.ts
+++ b/src/navigation/tabNavigator/navigation-config.ts
@@ -12,6 +12,7 @@ type Tabs = Tab[]
// name with '/' at the begging will not be resolved as 'bottom tab', will be as usual screen
export const upperSideTabs: Tabs = [
+ // UPPER SIDE TABS
{
displayedName: 'Home',
icon: 'home-5-line',
@@ -47,7 +48,6 @@ export const upperSideTabs: Tabs = [
id: 'profile',
name: 'profile',
},
-
// In case you want to navigate to screen with params you can do this like this
// {
// displayedName: 'Details',
diff --git a/src/types/icon.d.ts b/src/types/icon.d.ts
index 1da43419..1de1dbb9 100644
--- a/src/types/icon.d.ts
+++ b/src/types/icon.d.ts
@@ -1,8 +1,3 @@
-/**
- * @see https://remixicon.com/
- * You can find visually all icons that you need
- */
-
export type IconNames =
| 'layout-right-2-line'
| 'drag-drop-line'
diff --git a/templates/readme_template.md b/templates/readme_template.md
index aaf2a759..2e779565 100644
--- a/templates/readme_template.md
+++ b/templates/readme_template.md
@@ -9,26 +9,21 @@ Version in the `package.json` is one to one the latest expo on which the templat
#### 1. Bootstrap - At start you should trigger script
```
-node ./scripts/bootstrap.js
+yarn b
```
The script gives you opportunity to setup the essentialest variables for your project like app name, bundle ID or android package name
-#### 2. Generate new screen
+#### 2. Generators
```
-node ./scripts/create_new_screen.js
+yarn g
```
-You can use this script for generate new common screen, tabs screen or new bottom tab, from screen template. You have possiblity to change screen template for your own.
+Usage:
-#### 3. Generate new component
-
-```
-node ./scripts/create_new_component.js
-```
-
-You can use this script for generate new common component (atom, molecule, organism, common) from component template. You have possiblity to change component template for your own.
+- You can use this script to generate new common screen, tabs screen or new bottom tab, from screen template. You have possiblity to change screen template for your own.
+- You can use this script for generate new common component (atom, molecule, organism, common) from component template. You have possiblity to change component template for your own.
## Run Locally
@@ -89,14 +84,16 @@ It is added to the app as a font generated by [icomoon app](https://icomoon.io/a
9. Generate new types for icons
-- run script generating icon types `yarn generate:icon:types`
+- run script generating icon types `yarn g icon-types` and pick icon types
+
+
## Sync up with template:
1. Add template remote
```bash
-git remote add template git@github.com:binarapps/expo-ts-template.git
+git remote add template git@github.com:binarapps/baca-react-native-template.git
```
2. Go to new branch (for safety reason)
@@ -128,7 +125,7 @@ git commit -m "chore: sync up with template code"
```