diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..9216d95 Binary files /dev/null and b/.DS_Store differ diff --git a/.eslintrc.base.json b/.eslintrc.base.json new file mode 100644 index 0000000..4f292a2 --- /dev/null +++ b/.eslintrc.base.json @@ -0,0 +1,89 @@ +{ + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:prettier/recommended", + "plugin:import/recommended", + "plugin:import/typescript" + ], + "plugins": [ + "@typescript-eslint", + "prettier", + "import" + ], + "rules": { + "prettier/prettier": [ + "error", + { + "useTabs": true + } + ], + "quotes": [ + "error", + "single" + ], + "jsx-quotes": [ + "error", + "prefer-single" + ], + "@typescript-eslint/no-unused-vars": "error", + "@typescript-eslint/no-explicit-any": "warn", + "no-console": [ + "warn", + { + "allow": [ + "warn", + "error" + ] + } + ], + "import/order": [ + "error", + { + "groups": [ + "builtin", + "external", + "internal", + [ + "sibling", + "parent" + ], + "index", + "type" + ], + "pathGroups": [ + { + "pattern": "@/**", + "group": "internal", + "position": "after" + } + ], + "newlines-between": "always", + "alphabetize": { + "order": "asc", + "caseInsensitive": true + } + } + ], + "import/no-duplicates": "warn", + "no-multiple-empty-lines": [ + "error", + { + "max": 1, + "maxBOF": 0, + "maxEOF": 0 + } + ], + "import/newline-after-import": [ + "error", + { + "count": 1 + } + ] + }, + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": 2020, + "sourceType": "module" + } +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index c6bba59..5f31252 100644 --- a/.gitignore +++ b/.gitignore @@ -122,9 +122,17 @@ dist # Stores VSCode versions used for testing VSCode extensions .vscode-test -# yarn v2 -.yarn/cache -.yarn/unplugged -.yarn/build-state.yml -.yarn/install-state.gz +# Yarn +.yarn/* .pnp.* + +# pnpm +.pnpm-store/ +pnpm-lock.yaml + +# Turbo +.turbo + +# DS_Store files +**/.DS_Store +.DS_Store \ No newline at end of file diff --git a/.prettierrc.base.json b/.prettierrc.base.json new file mode 100644 index 0000000..a315ece --- /dev/null +++ b/.prettierrc.base.json @@ -0,0 +1,10 @@ +{ + "singleQuote": false, + "jsxSingleQuote": true, + "trailingComma": "es5", + "tabWidth": 2, + "useTabs": true, + "semi": true, + "printWidth": 100, + "bracketSpacing": true +} \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..c99c624 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,6 @@ +{ + "recommendations": [ + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode" + ] +} \ No newline at end of file diff --git a/.vscode/setting.json b/.vscode/setting.json new file mode 100644 index 0000000..1e2ae19 --- /dev/null +++ b/.vscode/setting.json @@ -0,0 +1,22 @@ +{ + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit" + }, + "editor.defaultFormatter": "esbenp.prettier-vscode", + "[typescript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[javascript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[json]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[html]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[css]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + } +} \ No newline at end of file diff --git a/README.md b/README.md index 1878f3d..09e56ad 100644 --- a/README.md +++ b/README.md @@ -1,59 +1,130 @@ -# Freedivah -**Freedivah** is a global community platform where freedivers from around the world come together to connect, share their passion, and inspire each other. The name **Freedivah** blends 'freediving' with the name of the developer, a devoted freediving enthusiast, capturing her deep love for the sport in every detail. -## MVP FEATURES -### TRACK & ANALYZE +# Freedivah: Project Overview +**“From Dive Tracking to Social Sharing”** +Freedivah is an interactive platform that allows freedivers to mark and share their dive locations on a global map using national flag icons. + +The name 'Freedivah' combines 'freediving' with my identity as a developer, reflecting both my passion for underwater exploration and my journey. + +## Key Features + +- **Personalized Dive Map**: Pin and save your dive locations on a global map. +- **Sharing and Connecting**: Share your dive experiences and connect with divers worldwide. +- **Tracking and Documentation**: Log and track your dives across different countries to monitor your progress. + +## Documentation +For more detailed information, refer to the following: +- [Technology Choices Rationale, API Specification, Functional Specification, Route Design etc](https://jiah827.notion.site/Project-Freedivah-10f4ef50e633807387d4c9307d622bdb?pvs=74) +- [Optimizing Freedivah’s Architecture with Feature-Sliced Design(FSD)](https://www.notion.so/jiah827/Optimizing-Freedivah-s-Architecture-with-Feature-Sliced-Design-1134ef50e63380b1b47bea0cc16f5f64) +- [Managing Shared Libraries: API Strategy with Exports and Aliases](https://www.notion.so/jiah827/exports-alias-API-1434ef50e63380a3aacad6eb9b7fec3b) +- [Why Vanilla Extract CSS?](https://www.notion.so/jiah827/CSS-1424ef50e633802ab39cec3730fe2d74) + +## Development Considerations + +### Flexible and Scalable Architecture + - Single-direction dependencies and modularity. + - Loosely coupled systems through separation and abstraction of business logic, UI, and side effects. + +## Architecture +### System Overview +```mermaid +graph TB +subgraph "Frontend (Next.js)" +Web[Web Application] +subgraph "FSD Architecture" +App[Application Layer] +Pages[Pages Layer] +Widgets[Widgets Layer] +Entities[Entities Layer] +Shared_FE[Shared Layer] +end +end +subgraph "Backend (Express.js)" +API[API Server] +subgraph "API Layers" +Routes[Routes] +Controllers[Controllers] +Services[Services] +Models[Models] +end +end +subgraph "Shared Package" +Types[Types] +Utils[Utils] +end +Web --> Types +Web --> Utils +API --> Types +API --> Utils +subgraph "External Services" +Supabase[(Supabase)] +end +API --> Supabase +``` +### Package Dependencies +```mermaid +graph TD +A[packages/web] +B[packages/api] +C[packages/shared] +A --> C +B --> C +style A fill:#eb6b56,stroke:#333,stroke-width:2px +style B fill:#2196F3,stroke:#333,stroke-width:2px +style C fill:#47b39d,stroke:#333,stroke-width:2px +``` +### Build Flow +```mermaid +graph LR +A[Build Shared] --> B[Build Web & API] +B --> C[Run Services] +style A fill:#47b39d,stroke:#333,stroke-width:2px +style B fill:#2196F3,stroke:#333,stroke-width:2px +style C fill:#eb6b56,stroke:#333,stroke-width:2px +``` +### Package Overview +- `@freedivah/shared`: Core utilities and types +- `@freedivah/web`: Next.js frontend application +- `@freedivah/api`: Express backend server + +## Technologies Used + - **Frontend**: Next.js, TypeScript, Vanilla Extract + - **Backend**: Node.js, Express.js, Supabase + - **Testing**: Jest + - **DevOps**: Github Actions, Docker, AWS + +## How to Run +### Prerequisites +- Node.js 18+ +- PNPM 9.14.1+ + +### Installation & Development +1. Clone the repository + ``` + git clone https://github.com/f-lab-edu/Freedivah.git + cd Freedivah + ``` +2. Install dependencies + ``` + pnpm install + ``` +3. Start development + ``` + pnpm dev + ``` +### Testing + ``` + yarn test + ``` +### Build + ``` + yarn build + ``` + +## Design +Freedivah Design -- **My Dive Map**: Mark your dive locations on a global map with flag badges. Input methods include GPS, device integration, and direct entry. -### SHARE & CONNECT -- **Profile**: Earn and showcase freediving certification badges. -- **Export & Share**: Export and share your dive map files. -- **Feed**: - - Upload and comment on photos and videos. - - Share your current location with a map image featuring a flag badge. - - Posts are automatically translated into English. -## TECH STACKS -#### Mono Repo / PNPM -- **Mono Repo**: Manages multiple packages within a single repository, streamlining development and version control. -- **PNPM**: Provides efficient package management with fast installation and reduced disk space usage. Chosen for its superior compatibility with widely used tools, despite Yarn Berry’s Zero-install advantages. -#### Front-End Technologies -- **Vanilla JavaScript** and **TypeScript**: Core languages selected to deepen our understanding of fundamental JavaScript principles. -- **Vanilla Extract**: Used for styling and UI development. Preferred over TailwindCSS and Styled Components for its static CSS extraction, type safety, and lack of runtime overhead, enhancing performance and maintainability. - -#### Backend Framework - -- **Node.js** with **Express.js**: Manages server-side logic and API endpoints. - -#### Data Storage - -- **Firebase Realtime Database**: Handles and stores dive data and user profiles. - -#### Authentication - -- **Firebase Authentication**: Manages user authentication and profiles, seamlessly integrating with Google Authentication. -- **Google Authentication**: Enabled through Firebase Authentication, offering a smooth and effortless login experience with Google accounts. - - -## EXTERNAL APIS - -#### Map Integration & Visualization - -- **Google Maps JavaScript API**: Displays dive locations with flag badges on a map. - -#### Location Services - -- **Geolocation API**: Retrieves the user's current location for precise dive tracking. -- **OpenCage Geocoding API**: Converts coordinates into country information. Selected for its cost-effectiveness and broad coverage compared to Google Maps Geocoding API. - -#### Data Export - -- **JSZip**: Exports dive maps and data as downloadable files. - -#### Flag Icons - -- **FlagsAPI**: Provides high-quality flag icons in SVG format with various sizes and styles. diff --git a/docs/images/Freedivah_Design.webp b/docs/images/Freedivah_Design.webp new file mode 100644 index 0000000..7e4be00 Binary files /dev/null and b/docs/images/Freedivah_Design.webp differ diff --git a/jest.config.base.js b/jest.config.base.js new file mode 100644 index 0000000..f31782c --- /dev/null +++ b/jest.config.base.js @@ -0,0 +1,14 @@ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', + moduleNameMapper: { + '^@/(.*)$': '/src/$1', + }, + setupFilesAfterEnv: ['/jest.setup.ts'], + testMatch: ['**/__tests__/**/*.test.ts?(x)'], + collectCoverageFrom: [ + 'src/**/*.{ts,tsx}', + '!src/**/*.d.ts', + '!src/**/*.stories.{ts,tsx}', + ], +}; diff --git a/package.json b/package.json new file mode 100644 index 0000000..7b7f79d --- /dev/null +++ b/package.json @@ -0,0 +1,37 @@ +{ + "name": "freedivah", + "version": "1.0.0", + "main": "index.js", + "repository": "https://github.com/f-lab-edu/Freedivah.git", + "author": "jiaah <25231717+jiaah@users.noreply.github.com>", + "license": "MIT", + "packageManager": "pnpm@9.14.1", + "workspaces": [ + "packages/*" + ], + "scripts": { + "build": "turbo run build", + "dev": "turbo run dev", + "test": "turbo run test", + "test:watch:filter": "turbo run test:watch --filter=@freedivah/*#", + "clean": "turbo run clean && rm -rf node_modules", + "lint": "turbo run lint", + "format": "prettier --write \"**/*.{ts,tsx,md}\"" + }, + "devDependencies": { + "@testing-library/jest-dom": "^6.6.3", + "@types/jest": "^29.5.14", + "@types/node": "^20", + "@typescript-eslint/eslint-plugin": "^8.14.0", + "@typescript-eslint/parser": "^8.14.0", + "eslint": "^9.15.0", + "eslint-config-prettier": "^9.1.0", + "eslint-import-resolver-typescript": "^3.6.1", + "eslint-plugin-import": "^2.29.1", + "eslint-plugin-prettier": "^5.2.1", + "jest": "^29.7.0", + "prettier": "^3.3.3", + "turbo": "^2.3.0", + "typescript": "^5" + } +} \ No newline at end of file diff --git a/packages/api/.eslintrc.json b/packages/api/.eslintrc.json new file mode 100644 index 0000000..3056c8c --- /dev/null +++ b/packages/api/.eslintrc.json @@ -0,0 +1,8 @@ +{ + "extends": [ + "../../.eslintrc.base.json" + ], + "env": { + "node": true + } +} \ No newline at end of file diff --git a/packages/api/.prettierrc.json b/packages/api/.prettierrc.json new file mode 100644 index 0000000..32e9d12 --- /dev/null +++ b/packages/api/.prettierrc.json @@ -0,0 +1,5 @@ +{ + "extends": [ + "../../.prettierrc.base.json" + ] +} \ No newline at end of file diff --git a/packages/api/jest.config.js b/packages/api/jest.config.js new file mode 100644 index 0000000..c4661a2 --- /dev/null +++ b/packages/api/jest.config.js @@ -0,0 +1,4 @@ +module.exports = { + ...require('../../jest.config.base'), + testEnvironment: 'node', +}; \ No newline at end of file diff --git a/packages/api/jest.setup.ts b/packages/api/jest.setup.ts new file mode 100644 index 0000000..5cd4fbd --- /dev/null +++ b/packages/api/jest.setup.ts @@ -0,0 +1,3 @@ +import '@testing-library/jest-dom'; + +// 전역 설정이나 모킹이 필요한 경우 여기에 추가 diff --git a/packages/api/nodemon.json b/packages/api/nodemon.json new file mode 100644 index 0000000..a075834 --- /dev/null +++ b/packages/api/nodemon.json @@ -0,0 +1,6 @@ +{ + "watch": ["src"], + "ext": ".ts,.js", + "ignore": [], + "exec": "ts-node -r tsconfig-paths/register ./src/index.ts" +} \ No newline at end of file diff --git a/packages/api/package.json b/packages/api/package.json new file mode 100644 index 0000000..d38bfbb --- /dev/null +++ b/packages/api/package.json @@ -0,0 +1,25 @@ +{ + "name": "@freedivah/api", + "version": "0.1.0", + "private": true, + "scripts": { + "build": "tsc", + "dev": "nodemon", + "start": "node dist/index.js", + "test": "jest", + "test:watch": "jest --watch", + "test:coverage": "jest --coverage" + }, + "dependencies": { + "@freedivah/shared": "workspace:*", + "@supabase/supabase-js": "^2.39.0", + "dotenv": "^16.3.1", + "express": "^4.18.2" + }, + "devDependencies": { + "@types/express": "^4.17.21", + "nodemon": "^3.0.1", + "ts-node": "^10.9.1", + "tsconfig-paths": "^4.2.0" + } +} \ No newline at end of file diff --git a/packages/api/src/index.ts b/packages/api/src/index.ts new file mode 100644 index 0000000..d2b8dbe --- /dev/null +++ b/packages/api/src/index.ts @@ -0,0 +1,5 @@ +import { logger } from '@shared/utils'; + +logger('Shared is connected', { + state: 'ON', +}); \ No newline at end of file diff --git a/packages/api/tsconfig.json b/packages/api/tsconfig.json new file mode 100644 index 0000000..1bfb308 --- /dev/null +++ b/packages/api/tsconfig.json @@ -0,0 +1,22 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src", + "module": "commonjs", + "noEmit": false, + "baseUrl": ".", + "paths": { + "@shared/*": [ + "../../node_modules/@freedivah/shared/*" + ] + }, + }, + "include": [ + "src/**/*.ts" + ], + "exclude": [ + "node_modules", + "dist" + ] +} \ No newline at end of file diff --git a/packages/shared/.eslintrc.json b/packages/shared/.eslintrc.json new file mode 100644 index 0000000..e376f66 --- /dev/null +++ b/packages/shared/.eslintrc.json @@ -0,0 +1,5 @@ +{ + "extends": [ + "../../.eslintrc.base.json" + ] +} \ No newline at end of file diff --git a/packages/shared/.prettierrc.json b/packages/shared/.prettierrc.json new file mode 100644 index 0000000..32e9d12 --- /dev/null +++ b/packages/shared/.prettierrc.json @@ -0,0 +1,5 @@ +{ + "extends": [ + "../../.prettierrc.base.json" + ] +} \ No newline at end of file diff --git a/packages/shared/jest.config.js b/packages/shared/jest.config.js new file mode 100644 index 0000000..80e81b1 --- /dev/null +++ b/packages/shared/jest.config.js @@ -0,0 +1,3 @@ +module.exports = { + ...require('../../jest.config.base'), +}; diff --git a/packages/shared/jest.setup.ts b/packages/shared/jest.setup.ts new file mode 100644 index 0000000..1fdec5d --- /dev/null +++ b/packages/shared/jest.setup.ts @@ -0,0 +1,3 @@ +import '@testing-library/jest-dom'; + +// 전역 설정이나 모킹이 필요한 경우 여기에 추가 \ No newline at end of file diff --git a/packages/shared/package.json b/packages/shared/package.json new file mode 100644 index 0000000..44d6d06 --- /dev/null +++ b/packages/shared/package.json @@ -0,0 +1,23 @@ +{ + "name": "@freedivah/shared", + "version": "0.0.0", + "private": true, + "scripts": { + "build": "tsc", + "dev": "tsc --watch", + "test": "jest", + "test:watch": "jest --watch", + "test:coverage": "jest --coverage" + }, + "exports": { + "./utils": { + "default": "./dist/utils/index.js" + }, + "./types": { + "default": "./dist/types/index.js" + } + }, + "devDependencies": { + "ts-jest": "^29.2.5" + } +} \ No newline at end of file diff --git a/packages/shared/tsconfig.json b/packages/shared/tsconfig.json new file mode 100644 index 0000000..dabeeb1 --- /dev/null +++ b/packages/shared/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "composite": true, + "outDir": "./dist", + "rootDir": ".", + "baseUrl": ".", + }, + "include": [ + "**/*.ts", + "utils/index.ts" + ], + "exclude": [ + "node_modules", + "dist" + ] +} \ No newline at end of file diff --git a/packages/shared/utils/__tests__/index.test.ts b/packages/shared/utils/__tests__/index.test.ts new file mode 100644 index 0000000..f3cbe49 --- /dev/null +++ b/packages/shared/utils/__tests__/index.test.ts @@ -0,0 +1,40 @@ +import { logger } from '../index'; + +describe('logger', () => { + let consoleLogSpy: jest.SpyInstance; + + beforeEach(() => { + // console.log를 모킹하여 실제 콘솔 출력을 방지 + consoleLogSpy = jest.spyOn(console, 'log').mockImplementation(); + }); + + afterEach(() => { + // 각 테스트 후 모킹 초기화 + consoleLogSpy.mockRestore(); + }); + + it('should log message with correct format', () => { + logger('Test message'); + expect(consoleLogSpy).toHaveBeenCalledWith('[Logger] Test message', ''); + }); + + it('should log message with data when provided', () => { + const testData = { count: 1, text: 'hello' }; + logger('Test message', testData); + expect(consoleLogSpy).toHaveBeenCalledWith('[Logger] Test message', testData); + }); + + it('should handle undefined data correctly', () => { + logger('Test message', undefined); + expect(consoleLogSpy).toHaveBeenCalledWith('[Logger] Test message', ''); + }); + + it('should handle multiple calls correctly', () => { + logger('First message'); + logger('Second message', { value: 123 }); + + expect(consoleLogSpy).toHaveBeenCalledTimes(2); + expect(consoleLogSpy).toHaveBeenNthCalledWith(1, '[Logger] First message', ''); + expect(consoleLogSpy).toHaveBeenNthCalledWith(2, '[Logger] Second message', { value: 123 }); + }); +}); \ No newline at end of file diff --git a/packages/shared/utils/index.ts b/packages/shared/utils/index.ts new file mode 100644 index 0000000..7cb7308 --- /dev/null +++ b/packages/shared/utils/index.ts @@ -0,0 +1,10 @@ +interface LogData { + [key: string]: any; +} + +const logger = (message: string, data?: LogData) => { + const logMessage = `[Logger] ${message}`; + console.log(logMessage, data || ''); +}; + +export { logger }; diff --git a/packages/web/.eslintrc.json b/packages/web/.eslintrc.json new file mode 100644 index 0000000..601292a --- /dev/null +++ b/packages/web/.eslintrc.json @@ -0,0 +1,39 @@ +{ + "extends": [ + "../../.eslintrc.base.json", + "next/core-web-vitals" + ], + "parserOptions": { + "ecmaFeatures": { + "jsx": true + } + }, + "rules": { + "import/order": [ + "error", + { + "pathGroups": [ + { + "pattern": "react", + "group": "external", + "position": "before" + }, + { + "pattern": "next/**", + "group": "external", + "position": "after" + }, + { + "pattern": "@/**", + "group": "internal", + "position": "after" + } + ], + "pathGroupsExcludedImportTypes": [ + "react", + "next" + ], + } + ], + } +} \ No newline at end of file diff --git a/packages/web/.gitignore b/packages/web/.gitignore new file mode 100644 index 0000000..d32cc78 --- /dev/null +++ b/packages/web/.gitignore @@ -0,0 +1,40 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# env files (can opt-in for committing if needed) +.env* + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/packages/web/.prettierrc.json b/packages/web/.prettierrc.json new file mode 100644 index 0000000..32e9d12 --- /dev/null +++ b/packages/web/.prettierrc.json @@ -0,0 +1,5 @@ +{ + "extends": [ + "../../.prettierrc.base.json" + ] +} \ No newline at end of file diff --git a/packages/web/README.md b/packages/web/README.md new file mode 100644 index 0000000..e215bc4 --- /dev/null +++ b/packages/web/README.md @@ -0,0 +1,36 @@ +This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). + +## Getting Started + +First, run the development server: + +```bash +npm run dev +# or +yarn dev +# or +pnpm dev +# or +bun dev +``` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. + +This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. + +## Learn More + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. + +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! + +## Deploy on Vercel + +The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. + +Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. diff --git a/packages/web/app/(routes)/login/page.tsx b/packages/web/app/(routes)/login/page.tsx new file mode 100644 index 0000000..867dde3 --- /dev/null +++ b/packages/web/app/(routes)/login/page.tsx @@ -0,0 +1,7 @@ +export default function LoginPage() { + return ( +
+

Login Page

+
+ ) +} \ No newline at end of file diff --git a/packages/web/app/(routes)/map/page.tsx b/packages/web/app/(routes)/map/page.tsx new file mode 100644 index 0000000..db1f749 --- /dev/null +++ b/packages/web/app/(routes)/map/page.tsx @@ -0,0 +1,7 @@ +export default function MapPage() { + return ( +
+

Map Page

+
+ ) +} \ No newline at end of file diff --git a/packages/web/app/layout.tsx b/packages/web/app/layout.tsx new file mode 100644 index 0000000..4108414 --- /dev/null +++ b/packages/web/app/layout.tsx @@ -0,0 +1,33 @@ + +import type { Metadata } from 'next'; +import localFont from 'next/font/local'; + +const geistSans = localFont({ + src: "../public/assets/fonts/GeistVF.woff", + variable: "--font-geist-sans", + weight: "100 900", +}); +const geistMono = localFont({ + src: "../public/assets/fonts/GeistMonoVF.woff", + variable: "--font-geist-mono", + weight: "100 900", +}); + +export const metadata: Metadata = { + title: "Create Next App", + description: "Generated by create next app", +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + + {children} + + + ); +} diff --git a/packages/web/app/page.tsx b/packages/web/app/page.tsx new file mode 100644 index 0000000..e80f736 --- /dev/null +++ b/packages/web/app/page.tsx @@ -0,0 +1,13 @@ +import { logger } from "@shared/utils"; + +logger('Shared is connected', { + state: 'ON', +}); + +export default function Home() { + return ( +
+

Hello Freedivah

+
+ ); +} diff --git a/packages/web/next.config.ts b/packages/web/next.config.ts new file mode 100644 index 0000000..94a0639 --- /dev/null +++ b/packages/web/next.config.ts @@ -0,0 +1,16 @@ +import { createVanillaExtractPlugin } from '@vanilla-extract/next-plugin'; +import type { NextConfig } from 'next'; + +const withVanillaExtract = createVanillaExtractPlugin(); + +const nextConfig: NextConfig = { + webpack: (config, { isServer }) => { + config.resolve.alias = { + ...config.resolve.alias, + '@shared': '@freedivah/shared' + }; + return config; + } +}; + +module.exports = withVanillaExtract(nextConfig); diff --git a/packages/web/package.json b/packages/web/package.json new file mode 100644 index 0000000..72ba32e --- /dev/null +++ b/packages/web/package.json @@ -0,0 +1,28 @@ +{ + "name": "@freedivah/web", + "version": "0.1.0", + "private": true, + "scripts": { + "build": "next build", + "dev": "next dev", + "start": "next start", + "test": "jest", + "test:watch": "jest --watch", + "test:coverage": "jest --coverage" + }, + "dependencies": { + "@freedivah/shared": "workspace:*", + "@vanilla-extract/css": "^1.16.0", + "next": "15.0.3", + "react": "19.0.0-rc-66855b96-20241106", + "react-dom": "19.0.0-rc-66855b96-20241106" + }, + "devDependencies": { + "@testing-library/react": "^16.0.1", + "@types/react": "^18", + "@types/react-dom": "^18", + "@vanilla-extract/next-plugin": "^2.4.6", + "eslint-config-next": "15.0.3", + "jest-environment-jsdom": "^29.7.0" + } +} \ No newline at end of file diff --git a/packages/web/public/assets/fonts/GeistMonoVF.woff b/packages/web/public/assets/fonts/GeistMonoVF.woff new file mode 100644 index 0000000..f2ae185 Binary files /dev/null and b/packages/web/public/assets/fonts/GeistMonoVF.woff differ diff --git a/packages/web/public/assets/fonts/GeistVF.woff b/packages/web/public/assets/fonts/GeistVF.woff new file mode 100644 index 0000000..1b62daa Binary files /dev/null and b/packages/web/public/assets/fonts/GeistVF.woff differ diff --git a/packages/web/public/assets/images/favicon.ico b/packages/web/public/assets/images/favicon.ico new file mode 100644 index 0000000..718d6fe Binary files /dev/null and b/packages/web/public/assets/images/favicon.ico differ diff --git a/packages/web/src/application/styles/global.css.ts b/packages/web/src/application/styles/global.css.ts new file mode 100644 index 0000000..5f6a72b --- /dev/null +++ b/packages/web/src/application/styles/global.css.ts @@ -0,0 +1,26 @@ +import { globalStyle } from '@vanilla-extract/css'; +import { colors } from './theme/colors.css'; + +globalStyle('html, body', { + maxWidth: '100vw', + overflowX: 'hidden' +}); + +globalStyle('body', { + color: colors.foreground, + background: colors.background, + fontFamily: 'Arial, Helvetica, sans-serif', + WebkitFontSmoothing: 'antialiased', + MozOsxFontSmoothing: 'grayscale' +}); + +globalStyle('*', { + boxSizing: 'border-box', + padding: 0, + margin: 0 +}); + +globalStyle('a', { + color: 'inherit', + textDecoration: 'none' +}); \ No newline at end of file diff --git a/packages/web/src/application/styles/index.ts b/packages/web/src/application/styles/index.ts new file mode 100644 index 0000000..232feb8 --- /dev/null +++ b/packages/web/src/application/styles/index.ts @@ -0,0 +1,4 @@ +import './global.css'; +import { colors } from './theme/colors.css'; + +export { colors }; diff --git a/packages/web/src/application/styles/theme/colors.css.ts b/packages/web/src/application/styles/theme/colors.css.ts new file mode 100644 index 0000000..99e5841 --- /dev/null +++ b/packages/web/src/application/styles/theme/colors.css.ts @@ -0,0 +1,8 @@ +import { createGlobalTheme } from '@vanilla-extract/css'; + +export const colors = createGlobalTheme(':root', { + background: '#ffffff', + foreground: '#171717', + backgroundDark: '#0a0a0a', + foregroundDark: '#ededed', +}); diff --git a/packages/web/src/application/styles/theme/index.ts b/packages/web/src/application/styles/theme/index.ts new file mode 100644 index 0000000..899aa90 --- /dev/null +++ b/packages/web/src/application/styles/theme/index.ts @@ -0,0 +1,3 @@ +import { colors } from './colors.css'; + +export { colors }; diff --git a/packages/web/tsconfig.json b/packages/web/tsconfig.json new file mode 100644 index 0000000..e8927b4 --- /dev/null +++ b/packages/web/tsconfig.json @@ -0,0 +1,40 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": [ + "./src/*" + ], + "@shared/*": [ + "../../node_modules/@freedivah/shared/*" + ], + "@styles/*": [ + "./src/styles/*" + ], + "@assets/*": [ + "./public/assets/*" + ] + }, + "plugins": [ + { + "name": "next" // Next.js 플러그인 활성화 + } + ], + "noEmit": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true + }, + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts", + ".next/types/app/(routes)/page.tsx", + ".next/types/app/(routes)/layout.tsx" + ], + "exclude": [ + "node_modules" + ] +} \ No newline at end of file diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..dee51e9 --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +packages: + - "packages/*" diff --git a/tsconfig.base.json b/tsconfig.base.json new file mode 100644 index 0000000..b186fec --- /dev/null +++ b/tsconfig.base.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "es2020", + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "esModuleInterop": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + }, + "exclude": [ + "node_modules" + ] +} \ No newline at end of file diff --git a/turbo.json b/turbo.json new file mode 100644 index 0000000..e6d2cc0 --- /dev/null +++ b/turbo.json @@ -0,0 +1,34 @@ +{ + "$schema": "https://turbo.build/schema.json", + "globalDependencies": [ + "**/.env.*local" + ], + "tasks": { + "build": { + "dependsOn": [ + "^build" + ], + "outputs": [ + ".next/**", + "!.next/cache/**", + "dist/**" + ] + }, + "lint": {}, + "dev": { + "cache": false, + "persistent": true + }, + "test": { + "dependsOn": [ + "build" + ], + "outputs": [ + "coverage/**" + ] + }, + "clean": { + "cache": false + } + } +} \ No newline at end of file