Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
## 작업 내용
## 작업 요약

> 해당 PR에서 작업한 내용을 정리해주세요.
> Slack 요약에는 1단계 불릿만 반영됩니다. 예) - 로그인 API를 연동합니다

## 작업 세부 내용

## 스크린샷

## 연관 이슈
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/slack-pr-bot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ jobs:
if (in_task == 1) exit
r = $0
sub(/^##[[:space:]]+/, "", r)
ok = (match(r, /^작업 내용([^A-Za-z]|$)/) || match(r, /[[:space:]]작업 내용([^A-Za-z]|$)/))
ok = (match(r, /^작업 요약([^A-Za-z]|$)/) || match(r, /[[:space:]]작업 요약([^A-Za-z]|$)/))
if (ok) { in_task=1; next }
next
}
Expand Down
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ This Turborepo includes the following packages/apps:

- `docs`: a [Next.js](https://nextjs.org/) app
- `web`: another [Next.js](https://nextjs.org/) app
- `@repo/ui`: a stub React component library shared by both `web` and `docs` applications
- `@repo/eslint-config`: `eslint` configurations (includes `eslint-config-next` and `eslint-config-prettier`)
- `@repo/typescript-config`: `tsconfig.json`s used throughout the monorepo

Each package/app is 100% [TypeScript](https://www.typescriptlang.org/).
Expand Down
12 changes: 6 additions & 6 deletions apps/app/app/_layout.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import { Stack } from 'expo-router'
import { StatusBar } from 'expo-status-bar'
import 'react-native-reanimated'
import { SafeAreaView } from 'react-native-safe-area-context'
import { Stack } from 'expo-router';
import { StatusBar } from 'expo-status-bar';
import 'react-native-reanimated';
import { SafeAreaView } from 'react-native-safe-area-context';

export const unstable_settings = {
anchor: '(tabs)',
}
};

export default function RootLayout() {
return (
<SafeAreaView style={{ flex: 1 }}>
<StatusBar style="auto" />
<Stack screenOptions={{ headerShown: false }} />
</SafeAreaView>
)
);
}
6 changes: 3 additions & 3 deletions apps/app/app/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { KeyboardAvoidingView, Platform } from 'react-native'
import Webview from 'react-native-webview'
import { KeyboardAvoidingView, Platform } from 'react-native';
import Webview from 'react-native-webview';

export default function Page() {
return (
Expand All @@ -22,5 +22,5 @@ export default function Page() {
startInLoadingState
/>
</KeyboardAvoidingView>
)
);
}
8 changes: 4 additions & 4 deletions apps/app/app/modal.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Link } from 'expo-router'
import { StyleSheet, Text, View } from 'react-native'
import { Link } from 'expo-router';
import { StyleSheet, Text, View } from 'react-native';

export default function ModalScreen() {
return (
Expand All @@ -9,7 +9,7 @@ export default function ModalScreen() {
<Text>Go to home screen</Text>
</Link>
</View>
)
);
}

const styles = StyleSheet.create({
Expand All @@ -23,4 +23,4 @@ const styles = StyleSheet.create({
marginTop: 15,
paddingVertical: 15,
},
})
});
6 changes: 3 additions & 3 deletions apps/app/components/ExternalLink.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Href, Link } from 'expo-router';
import { openBrowserAsync, WebBrowserPresentationStyle } from 'expo-web-browser';
import { type Href, Link } from 'expo-router';
import { WebBrowserPresentationStyle, openBrowserAsync } from 'expo-web-browser';
import { type ComponentProps } from 'react';

type Props = Omit<ComponentProps<typeof Link>, 'href'> & { href: Href & string };
Expand All @@ -10,8 +10,8 @@
target="_blank"
{...rest}
href={href}
onPress={async (event) => {
onPress={async event => {
if (process.env.EXPO_OS !== 'web') {

Check warning on line 14 in apps/app/components/ExternalLink.tsx

View workflow job for this annotation

GitHub Actions / Lint, Type Check, Build

EXPO_OS is not listed as a dependency in turbo.json

Check warning on line 14 in apps/app/components/ExternalLink.tsx

View workflow job for this annotation

GitHub Actions / Lint, Type Check, Build

EXPO_OS is not listed as a dependency in turbo.json

Check warning on line 14 in apps/app/components/ExternalLink.tsx

View workflow job for this annotation

GitHub Actions / Lint, Type Check, Build

EXPO_OS is not listed as a dependency in turbo.json

Check warning on line 14 in apps/app/components/ExternalLink.tsx

View workflow job for this annotation

GitHub Actions / Lint, Type Check, Build

EXPO_OS is not listed as a dependency in turbo.json
// Prevent the default behavior of linking to the default browser on native.
event.preventDefault();
// Open the link in an in-app browser.
Expand Down
4 changes: 2 additions & 2 deletions apps/app/components/HapticTab.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { BottomTabBarButtonProps } from '@react-navigation/bottom-tabs';
import type { BottomTabBarButtonProps } from '@react-navigation/bottom-tabs';
import { PlatformPressable } from '@react-navigation/elements';
import * as Haptics from 'expo-haptics';

export function HapticTab(props: BottomTabBarButtonProps) {
return (
<PlatformPressable
{...props}
onPressIn={(ev) => {
onPressIn={ev => {
if (process.env.EXPO_OS === 'ios') {

Check warning on line 10 in apps/app/components/HapticTab.tsx

View workflow job for this annotation

GitHub Actions / Lint, Type Check, Build

EXPO_OS is not listed as a dependency in turbo.json

Check warning on line 10 in apps/app/components/HapticTab.tsx

View workflow job for this annotation

GitHub Actions / Lint, Type Check, Build

EXPO_OS is not listed as a dependency in turbo.json

Check warning on line 10 in apps/app/components/HapticTab.tsx

View workflow job for this annotation

GitHub Actions / Lint, Type Check, Build

EXPO_OS is not listed as a dependency in turbo.json

Check warning on line 10 in apps/app/components/HapticTab.tsx

View workflow job for this annotation

GitHub Actions / Lint, Type Check, Build

EXPO_OS is not listed as a dependency in turbo.json
// Add a soft haptic feedback when pressing down on the tabs.
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
}
Expand Down
10 changes: 0 additions & 10 deletions apps/app/eslint.config.js

This file was deleted.

12 changes: 12 additions & 0 deletions apps/app/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import expoConfig from 'eslint-config-expo/flat.js';
import { defineConfig } from 'eslint/config';

import baseConfig from '../../eslint.config.mjs';

export default defineConfig([
...baseConfig,
expoConfig,
{
ignores: ['dist/**'],
},
]);
91 changes: 48 additions & 43 deletions apps/app/scripts/reset-project.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@
* You can remove the `reset-project` script from package.json and safely delete this file after running it.
*/

const fs = require('fs')
const path = require('path')
const readline = require('readline')
const fs = require('fs');
const path = require('path');
const readline = require('readline');

const root = process.cwd()
const oldDirs = ['app', 'components', 'hooks', 'constants', 'scripts']
const exampleDir = 'app-example'
const newAppDir = 'app'
const exampleDirPath = path.join(root, exampleDir)
const root = process.cwd();
const oldDirs = ['app', 'components', 'hooks', 'constants', 'scripts'];
const exampleDir = 'app-example';
const newAppDir = 'app';
const exampleDirPath = path.join(root, exampleDir);

const indexContent = `import { Text, View } from "react-native";

Expand All @@ -31,77 +31,82 @@ export default function Index() {
</View>
);
}
`
`;

const layoutContent = `import { Stack } from "expo-router";

export default function RootLayout() {
return <Stack />;
}
`
`;

const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
})
});

const moveDirectories = async (userInput) => {
const moveDirectories = async userInput => {
try {
if (userInput === 'y') {
// Create the app-example directory
await fs.promises.mkdir(exampleDirPath, { recursive: true })
console.log(`📁 /${exampleDir} directory created.`)
await fs.promises.mkdir(exampleDirPath, { recursive: true });
console.log(`📁 /${exampleDir} directory created.`);
}

// Move old directories to new app-example directory or delete them
for (const dir of oldDirs) {
const oldDirPath = path.join(root, dir)
const oldDirPath = path.join(root, dir);
if (fs.existsSync(oldDirPath)) {
if (userInput === 'y') {
const newDirPath = path.join(root, exampleDir, dir)
await fs.promises.rename(oldDirPath, newDirPath)
console.log(`➡️ /${dir} moved to /${exampleDir}/${dir}.`)
const newDirPath = path.join(root, exampleDir, dir);
await fs.promises.rename(oldDirPath, newDirPath);
console.log(`➡️ /${dir} moved to /${exampleDir}/${dir}.`);
} else {
await fs.promises.rm(oldDirPath, { recursive: true, force: true })
console.log(`❌ /${dir} deleted.`)
await fs.promises.rm(oldDirPath, { recursive: true, force: true });
console.log(`❌ /${dir} deleted.`);
}
} else {
console.log(`➡️ /${dir} does not exist, skipping.`)
console.log(`➡️ /${dir} does not exist, skipping.`);
}
}

// Create new /app directory
const newAppDirPath = path.join(root, newAppDir)
await fs.promises.mkdir(newAppDirPath, { recursive: true })
console.log('\n📁 New /app directory created.')
const newAppDirPath = path.join(root, newAppDir);
await fs.promises.mkdir(newAppDirPath, { recursive: true });
console.log('\n📁 New /app directory created.');

// Create index.tsx
const indexPath = path.join(newAppDirPath, 'index.tsx')
await fs.promises.writeFile(indexPath, indexContent)
console.log('📄 app/index.tsx created.')
const indexPath = path.join(newAppDirPath, 'index.tsx');
await fs.promises.writeFile(indexPath, indexContent);
console.log('📄 app/index.tsx created.');

// Create _layout.tsx
const layoutPath = path.join(newAppDirPath, '_layout.tsx')
await fs.promises.writeFile(layoutPath, layoutContent)
console.log('📄 app/_layout.tsx created.')
const layoutPath = path.join(newAppDirPath, '_layout.tsx');
await fs.promises.writeFile(layoutPath, layoutContent);
console.log('📄 app/_layout.tsx created.');

console.log('\n✅ Project reset complete. Next steps:')
console.log('\n✅ Project reset complete. Next steps:');
console.log(
`1. Run \`npx expo start\` to start a development server.\n2. Edit app/index.tsx to edit the main screen.${
userInput === 'y' ? `\n3. Delete the /${exampleDir} directory when you're done referencing it.` : ''
userInput === 'y'
? `\n3. Delete the /${exampleDir} directory when you're done referencing it.`
: ''
}`
)
);
} catch (error) {
console.error(`❌ Error during script execution: ${error.message}`)
console.error(`❌ Error during script execution: ${error.message}`);
}
}
};

rl.question('Do you want to move existing files to /app-example instead of deleting them? (Y/n): ', (answer) => {
const userInput = answer.trim().toLowerCase() || 'y'
if (userInput === 'y' || userInput === 'n') {
moveDirectories(userInput).finally(() => rl.close())
} else {
console.log("❌ Invalid input. Please enter 'Y' or 'N'.")
rl.close()
rl.question(
'Do you want to move existing files to /app-example instead of deleting them? (Y/n): ',
answer => {
const userInput = answer.trim().toLowerCase() || 'y';
if (userInput === 'y' || userInput === 'n') {
moveDirectories(userInput).finally(() => rl.close());
} else {
console.log("❌ Invalid input. Please enter 'Y' or 'N'.");
rl.close();
}
}
})
);
53 changes: 4 additions & 49 deletions apps/web/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -1,57 +1,12 @@
import js from '@eslint/js';
import nextVitals from 'eslint-config-next/core-web-vitals';
import nextTs from 'eslint-config-next/typescript';
import eslintConfigPrettier from 'eslint-config-prettier';
import unusedImports from 'eslint-plugin-unused-imports';
import { defineConfig, globalIgnores } from 'eslint/config';
import globals from 'globals';

const eslintConfig = defineConfig([
import baseConfig from '../../eslint.config.mjs';

export default defineConfig([
...baseConfig,
...nextVitals,
...nextTs,
globalIgnores(['.next/**', 'out/**', 'build/**', 'next-env.d.ts']),

/** 모든 파일 공통 규칙 */
js.configs.recommended,
{
files: ['**/*.{js,jsx,ts,tsx}'],
plugins: { 'unused-imports': unusedImports },
rules: {
'no-console': ['warn', { allow: ['warn', 'error'] }],
'no-nested-ternary': 'error',
'no-unused-vars': 'off',
'unused-imports/no-unused-imports': 'error',
},
},

/** TS 전용 설정 + 규칙 */
{
files: ['**/*.{ts,tsx}'],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
parserOptions: {
projectService: true,
tsconfigRootDir: process.cwd(),
},
},
rules: {
'no-undef': 'off',
'@typescript-eslint/consistent-type-imports': 'error',
'@typescript-eslint/no-explicit-any': 'error',
'@typescript-eslint/no-unused-vars': [
'error',
{
vars: 'all',
varsIgnorePattern: '^_',
args: 'after-used',
argsIgnorePattern: '^_',
},
],
},
},

eslintConfigPrettier,
]);

export default eslintConfig;
31 changes: 13 additions & 18 deletions apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,27 @@
"lint": "eslint --max-warnings 0",
"check-types": "next typegen && tsc --noEmit"
},
"dependencies": {
"@repo/core": "workspace:*",
"@tanstack/react-query": "^5.96.2",
"@tanstack/react-query-devtools": "^5.96.2",
"next": "16.2.0",
"react": "^19.2.0",
"react-dom": "^19.2.0",
"zod": "^4.3.6",
"zustand": "^5.0.12"
},
"dependencies": {
"@repo/core": "workspace:*",
"@tanstack/react-query": "^5.96.2",
"@tanstack/react-query-devtools": "^5.96.2",
"clsx": "^2.1.1",
"next": "16.2.0",
"react": "^19.2.0",
"react-dom": "^19.2.0",
"tailwind-merge": "^3.5.0",
"zod": "^4.3.6",
"zustand": "^5.0.12"
},
"devDependencies": {
"@eslint/js": "^9.39.1",
"@repo/eslint-config": "workspace:*",
"@repo/typescript-config": "workspace:*",
"@tailwindcss/postcss": "^4.2.2",
"@types/node": "^22.15.3",
"@types/react": "19.2.2",
"@types/react-dom": "19.2.2",
"eslint": "^9.39.1",
"eslint-config-next": "^16.2.2",
"eslint-config-prettier": "^10.1.1",
"eslint-plugin-unused-imports": "^4.4.1",
"globals": "^16.5.0",
"postcss": "^8.5.8",
"tailwindcss": "^4.2.2",
"typescript": "5.9.2",
"typescript-eslint": "^8.50.0"
"typescript": "5.9.2"
}
}
File renamed without changes.
Loading
Loading