Clean repo
This commit is contained in:
165
CLAUDE.md
Normal file
165
CLAUDE.md
Normal file
@@ -0,0 +1,165 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Common Development Commands
|
||||
|
||||
### Backend (.NET)
|
||||
```bash
|
||||
# Build entire solution
|
||||
dotnet build src/Managing.sln
|
||||
|
||||
# Run main API (port 80/443)
|
||||
dotnet run --project src/Managing.Api/Managing.Api.csproj
|
||||
|
||||
# Run worker API (port 81/444)
|
||||
dotnet run --project src/Managing.Api.Workers/Managing.Api.Workers.csproj
|
||||
|
||||
# Run tests
|
||||
dotnet test src/Managing.Application.Tests/
|
||||
dotnet test src/Managing.Infrastructure.Tests/
|
||||
|
||||
# Run specific test
|
||||
dotnet test --filter "TestMethodName"
|
||||
|
||||
# Database migrations
|
||||
dotnet ef database update --project src/Managing.Infrastructure.Database/Managing.Infrastructure.Databases.csproj --context ManagingDbContext
|
||||
dotnet ef migrations add <MigrationName> --project src/Managing.Infrastructure.Database/Managing.Infrastructure.Databases.csproj --context ManagingDbContext
|
||||
|
||||
# Regenerate API client (after API changes)
|
||||
cd src/Managing.Nswag && dotnet build
|
||||
```
|
||||
|
||||
### Frontend (React/TypeScript)
|
||||
```bash
|
||||
cd src/Managing.WebApp
|
||||
|
||||
# Install dependencies
|
||||
npm install
|
||||
|
||||
# Development server
|
||||
npm run dev
|
||||
|
||||
# Build for production
|
||||
npm run build
|
||||
|
||||
# Linting and type checking
|
||||
npm run lint
|
||||
npm run typecheck
|
||||
|
||||
# Tests
|
||||
npm run test
|
||||
```
|
||||
|
||||
### Full Stack Development
|
||||
```bash
|
||||
# Quick start with Docker
|
||||
./scripts/build_and_run.sh
|
||||
|
||||
# Alternative using Aspire
|
||||
cd src && ./run-aspire.sh
|
||||
```
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
### Clean Architecture Pattern
|
||||
The codebase follows Clean Architecture with clear layer separation:
|
||||
- **Domain** (`Managing.Domain`): Business entities and core rules
|
||||
- **Application** (`Managing.Application*`): Use cases, commands, and business orchestration
|
||||
- **Infrastructure** (`Managing.Infrastructure.*`): External integrations (databases, Web3, messaging)
|
||||
- **Presentation** (`Managing.Api*`): REST APIs and controllers
|
||||
|
||||
### Service Architecture
|
||||
Multiple coordinated services handle different concerns:
|
||||
- **Managing.Api**: Main trading operations, bot management, backtesting
|
||||
- **Managing.Api.Workers**: Background workers for price data, genetic algorithms, statistics
|
||||
- **Managing.Web3Proxy**: Node.js service for Web3/GMX blockchain interactions
|
||||
- **Managing.WebApp**: React frontend with real-time SignalR updates
|
||||
|
||||
### Data Storage Strategy (Polyglot Persistence)
|
||||
- **PostgreSQL**: Transactional data (users, bots, positions, scenarios, backtests)
|
||||
- **InfluxDB**: Time-series data (OHLCV candles, agent balances, performance metrics)
|
||||
- **MongoDB**: Document storage for certain data types
|
||||
|
||||
### Key Domain Concepts
|
||||
- **Bot**: Abstract base with lifecycle management for trading automation
|
||||
- **Position**: Trading positions with PnL tracking and trade history
|
||||
- **Scenario**: Collections of technical indicators defining trading strategies
|
||||
- **Indicator**: Technical analysis tools (RSI, MACD, EMA, SuperTrend, etc.)
|
||||
- **MoneyManagement**: Risk parameters (stop loss, take profit, position sizing)
|
||||
- **Account**: Multi-exchange trading accounts (CEX, GMX V2, Privy wallets)
|
||||
|
||||
## Development Patterns
|
||||
|
||||
### Adding New Features
|
||||
1. **Domain First**: Create entities in `Managing.Domain`
|
||||
2. **Application Layer**: Add services/command handlers in `Managing.Application`
|
||||
3. **Infrastructure**: Implement repositories and external integrations
|
||||
4. **API Layer**: Add controllers and endpoints
|
||||
5. **Frontend**: Update React components and API client
|
||||
|
||||
### Bot Development
|
||||
- Inherit from `Bot` base class in `Managing.Domain/Bots/`
|
||||
- Implement `SaveBackup()` and `LoadBackup()` for persistence
|
||||
- Use dependency injection pattern for services
|
||||
- Follow worker pattern for background execution
|
||||
|
||||
### Adding Technical Indicators
|
||||
1. Create indicator class implementing `IIndicator`
|
||||
2. Add to `IndicatorType` enum in `Managing.Common`
|
||||
3. Register in DI container via `ApiBootstrap`
|
||||
4. Implement calculation logic in `TradingService`
|
||||
|
||||
### Database Changes
|
||||
1. Update entities in domain layer
|
||||
2. Modify `ManagingDbContext` with new DbSets
|
||||
3. Generate EF Core migration
|
||||
4. Update repository interfaces and implementations
|
||||
5. Consider InfluxDB for time-series data
|
||||
|
||||
### Web3 Integration
|
||||
- GMX V2 interactions go through `Managing.Web3Proxy` Node.js service
|
||||
- Use `Managing.Infrastructure.Web3` for .NET integration
|
||||
- Privy handles wallet management and authentication
|
||||
|
||||
## Configuration & Environment
|
||||
|
||||
### Key Configuration Files
|
||||
- `src/Managing.Api/appsettings.*.json`: Main API configuration
|
||||
- `src/Managing.Api.Workers/appsettings.*.json`: Worker configuration
|
||||
- `src/Managing.WebApp/.env`: Frontend environment variables
|
||||
|
||||
### Environment-Specific Deployments
|
||||
- Development: `appsettings.Development.json`
|
||||
- Sandbox: `appsettings.Sandbox.json`
|
||||
- Production: `appsettings.Production.json`
|
||||
- Docker: `appsettings.Oda-docker.json`
|
||||
|
||||
## Important Development Guidelines
|
||||
|
||||
### Quantitative Finance Principles
|
||||
- Use `decimal` for all monetary calculations (never `float` or `double`)
|
||||
- Implement proper audit trails for financial operations
|
||||
- Validate trading strategies with historical backtesting
|
||||
- Optimize time-series processing for performance
|
||||
|
||||
### Code Architecture Rules
|
||||
- Follow Controller → Application → Repository pattern (never inject repositories directly into controllers)
|
||||
- Use CQRS pattern with command handlers for complex operations
|
||||
- Implement proper error handling with user-friendly messages
|
||||
- Maintain separation between domain logic and infrastructure concerns
|
||||
|
||||
### API Development
|
||||
- Follow RESTful conventions
|
||||
- Use attribute routing in controllers
|
||||
- Return appropriate HTTP status codes
|
||||
- Implement proper validation using Data Annotations
|
||||
|
||||
### Testing Strategy
|
||||
- Unit tests focus on domain logic and indicators
|
||||
- Integration tests for external service interactions
|
||||
- Use data-driven testing with JSON fixtures for backtesting scenarios
|
||||
|
||||
## Real-time Features
|
||||
- SignalR hubs provide live updates for trading data, bot status, and market information
|
||||
- Frontend uses reactive patterns with real-time price feeds and position updates
|
||||
18
package-lock.json
generated
18
package-lock.json
generated
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"name": "managing-apps",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"genetic-js": "^0.1.14"
|
||||
}
|
||||
},
|
||||
"node_modules/genetic-js": {
|
||||
"version": "0.1.14",
|
||||
"resolved": "https://registry.npmjs.org/genetic-js/-/genetic-js-0.1.14.tgz",
|
||||
"integrity": "sha512-HHm21naCEF1EVKTWPFzKX4ENB7Nn/my4kTy2POi4u/2gB0XPUOh8oDlhhESVCZVBge3b7nuLrZNZNAt4ObH19Q==",
|
||||
"license": "BSD"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"genetic-js": "^0.1.14"
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
VITE_API_URL_LOCAL=http://localhost:5000
|
||||
VITE_API_URL_SERVER=https://dev-managing-api.apps.managing.live
|
||||
VITE_WORKER_URL_LOCAL=https://localhost:5002
|
||||
VITE_WORKER_URL_SERVER=https://dev-managing-worker.apps.managing.live
|
||||
ALCHEMY_ID=Bao7OirVe4bmYiDbPh0l8cs5gYb5D4_9
|
||||
WALLET_CONNECT_PROJECT_ID=363bf09c10fec2293b21ee199b2ce8d5
|
||||
VITE_PRIVY_APP_ID=cm7u09v0u002zrkuf2yjjr58p
|
||||
@@ -1,2 +0,0 @@
|
||||
node_modules
|
||||
dist
|
||||
@@ -1,98 +0,0 @@
|
||||
{
|
||||
"root": true,
|
||||
"extends": [
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:jsx-a11y/recommended"
|
||||
],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"plugins": [
|
||||
"jsx-a11y",
|
||||
"import",
|
||||
"sort-keys-fix",
|
||||
"react-hooks",
|
||||
"@typescript-eslint",
|
||||
"prettier"
|
||||
],
|
||||
"env": {
|
||||
"browser": true,
|
||||
"node": true,
|
||||
"es6": true,
|
||||
"jest": true
|
||||
},
|
||||
"globals": {
|
||||
"JSX": "readonly"
|
||||
},
|
||||
"settings": {
|
||||
"react": {
|
||||
"version": "detect"
|
||||
},
|
||||
"import/parsers": {
|
||||
"@typescript-eslint/parser": [".ts", ".tsx"]
|
||||
},
|
||||
"import/resolver": {
|
||||
"node": {
|
||||
"extensions": [".js", ".jsx", ".ts", ".tsx"]
|
||||
},
|
||||
"typescript": {
|
||||
"alwaysTryTypes": true,
|
||||
// always try to resolve types under `<root>@types` directory even it doesn't contain any source code, like `@types/unist`
|
||||
"project": ["tsconfig.json"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"rules": {
|
||||
"no-alert": "error",
|
||||
"no-console": "error",
|
||||
"react-hooks/rules-of-hooks": "error",
|
||||
"prettier/prettier": [
|
||||
"warn",
|
||||
{},
|
||||
{
|
||||
"properties": {
|
||||
"usePrettierrc": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"import/order": [
|
||||
"warn",
|
||||
{
|
||||
"groups": [
|
||||
"builtin",
|
||||
"external",
|
||||
"internal",
|
||||
"parent",
|
||||
"sibling",
|
||||
"index",
|
||||
"object"
|
||||
],
|
||||
"newlines-between": "always",
|
||||
"alphabetize": {
|
||||
"order": "asc",
|
||||
"caseInsensitive": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"import/named": "error",
|
||||
"import/default": "error",
|
||||
"import/export": "error",
|
||||
"import/no-named-as-default": "warn",
|
||||
"import/no-duplicates": "error",
|
||||
"sort-keys-fix/sort-keys-fix": "warn",
|
||||
"@import/no-named-as-default-member": "off",
|
||||
"@typescript-eslint/consistent-type-imports": "warn",
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/ban-types": "off",
|
||||
"@typescript-eslint/ban-ts-comment": "off",
|
||||
"@typescript-eslint/no-empty-function": "off"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.js"],
|
||||
"rules": {
|
||||
"@typescript-eslint/explicit-module-boundary-types": ["off"],
|
||||
"@typescript-eslint/no-var-requires": ["off"]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
3
src/Managing.Pinky/.gitattributes
vendored
3
src/Managing.Pinky/.gitattributes
vendored
@@ -1,3 +0,0 @@
|
||||
.jest/* linguist-vendored
|
||||
mocks/* linguist-vendored
|
||||
mockServiceWorker.js linguist-vendored
|
||||
18
src/Managing.Pinky/.github/workflows/build.yml
vendored
18
src/Managing.Pinky/.github/workflows/build.yml
vendored
@@ -1,18 +0,0 @@
|
||||
name: Build
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2-beta
|
||||
with:
|
||||
node-version: '18.1.0'
|
||||
- run: yarn install
|
||||
- run: yarn build
|
||||
18
src/Managing.Pinky/.github/workflows/lint.yml
vendored
18
src/Managing.Pinky/.github/workflows/lint.yml
vendored
@@ -1,18 +0,0 @@
|
||||
name: Lint
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2-beta
|
||||
with:
|
||||
node-version: '18.1.0'
|
||||
- run: yarn install
|
||||
- run: yarn lint
|
||||
18
src/Managing.Pinky/.github/workflows/test.yml
vendored
18
src/Managing.Pinky/.github/workflows/test.yml
vendored
@@ -1,18 +0,0 @@
|
||||
name: Test
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2-beta
|
||||
with:
|
||||
node-version: '18.1.0'
|
||||
- run: yarn install
|
||||
- run: yarn test
|
||||
@@ -1,18 +0,0 @@
|
||||
name: Typecheck
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
jobs:
|
||||
typecheck:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2-beta
|
||||
with:
|
||||
node-version: '18.1.0'
|
||||
- run: yarn install
|
||||
- run: yarn typecheck
|
||||
5
src/Managing.Pinky/.gitignore
vendored
5
src/Managing.Pinky/.gitignore
vendored
@@ -1,5 +0,0 @@
|
||||
node_modules
|
||||
.DS_Store
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
@@ -1,5 +0,0 @@
|
||||
.git
|
||||
node_modules
|
||||
.eslintignore
|
||||
.gitignore
|
||||
LICENSE
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"singleQuote": true,
|
||||
"semi": false
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
# Use an official Node.js image as the base
|
||||
FROM node:18-alpine
|
||||
|
||||
# Set the working directory in the container
|
||||
WORKDIR /app
|
||||
|
||||
# Set environment variable to skip Chromium download
|
||||
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
|
||||
|
||||
# Install git and Python
|
||||
RUN apk update && apk add --no-cache git python3 make g++
|
||||
|
||||
# Create a symlink for python3 as python
|
||||
RUN ln -sf /usr/bin/python3 /usr/bin/python
|
||||
|
||||
# Copy package.json and package-lock.json to the container
|
||||
# COPY package*.json ./
|
||||
COPY /src/Managing.WebApp/package.json ./
|
||||
|
||||
# Install dependencies with the --legacy-peer-deps flag to bypass peer dependency conflicts
|
||||
RUN npm install --legacy-peer-deps
|
||||
RUN npm install -g tailwindcss postcss autoprefixer @tailwindcss/typography
|
||||
|
||||
# Copy the rest of the app's source code to the container
|
||||
# COPY . .
|
||||
COPY src/Managing.WebApp/ /app/
|
||||
RUN node --max-old-space-size=8192 ./node_modules/.bin/vite build
|
||||
|
||||
# Build the app
|
||||
RUN npm run build
|
||||
|
||||
# Use NGINX as the web server
|
||||
FROM nginx:alpine
|
||||
|
||||
# Copy the built app to the NGINX web server directory
|
||||
COPY --from=0 /app/build /usr/share/nginx/html
|
||||
|
||||
# Expose port 80 for the NGINX web server
|
||||
EXPOSE 80
|
||||
|
||||
# Start the NGINX web server
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
@@ -1,44 +0,0 @@
|
||||
# Use an official Node.js image as the base
|
||||
FROM node:18-alpine
|
||||
|
||||
# Set the working directory in the container
|
||||
WORKDIR /app
|
||||
|
||||
# Set environment variable to skip Chromium download
|
||||
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
|
||||
|
||||
# Install git and Python
|
||||
RUN apk update && apk add --no-cache git python3 make g++
|
||||
|
||||
# Create a symlink for python3 as python
|
||||
RUN ln -sf /usr/bin/python3 /usr/bin/python
|
||||
|
||||
# Copy package.json and package-lock.json to the container
|
||||
# COPY package*.json ./
|
||||
COPY /src/Managing.Pinky/package.json ./
|
||||
|
||||
# Install dependencies with the --legacy-peer-deps flag to bypass peer dependency conflicts
|
||||
RUN npm install --legacy-peer-deps
|
||||
RUN npm install -g tailwindcss postcss autoprefixer @tailwindcss/typography
|
||||
|
||||
# Copy the rest of the app's source code to the container
|
||||
# COPY . .
|
||||
RUN ls -la
|
||||
COPY src/Managing.Pinky/ .
|
||||
RUN node --max-old-space-size=8192 ./node_modules/.bin/vite build
|
||||
|
||||
# Build the app
|
||||
RUN npm run build
|
||||
|
||||
# Use NGINX as the web server
|
||||
FROM nginx:alpine
|
||||
|
||||
# Copy the built app to the NGINX web server directory
|
||||
# COPY --from=0 /app/build /usr/share/nginx/html
|
||||
COPY --from=0 /app/dist /usr/share/nginx/html
|
||||
|
||||
# Expose port 80 for the NGINX web server
|
||||
EXPOSE 80
|
||||
|
||||
# Start the NGINX web server
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) Managing
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,94 +0,0 @@
|
||||
# vite-react-ts-extended [](https://github.com/laststance/vite-react-ts-extended/actions/workflows/typecheck.yml) [](https://github.com/laststance/vite-react-ts-extended/actions/workflows/test.yml) [](https://github.com/laststance/vite-react-ts-extended/actions/workflows/build.yml) [](https://github.com/laststance/vite-react-ts-extended/actions/workflows/lint.yml) [](https://depfu.com/github/laststance/vite-react-ts-extended?project_id=32682)
|
||||
|
||||
> My CRA alternative.
|
||||
> Create plain and lightweight React+TS programming environment with familiar pre-setup tooling
|
||||
> eslint/prettier, jest/TS/react-testing-library/msw, tailwindcss, CI.
|
||||
|
||||
## [Trying this Online!](https://codesandbox.io/s/vite-react-ts-extended-cbgyfz?file=/src/App.tsx)
|
||||
|
||||
<img src="https://digital3.nyc3.cdn.digitaloceanspaces.com/ext.png" />
|
||||
|
||||
This is the official [Vite](https://vitejs.dev/) template(`npm init vite@latest myapp -- --template react-ts`) and some extended setup.
|
||||
|
||||
- [eslint-typescript](https://github.com/typescript-eslint/typescript-eslint) and [Prettier](https://prettier.io/) integration. Rules are 100% my personal setup 💅
|
||||
- [jest](https://jestjs.io/), [React Testing Library](https://testing-library.com/docs/react-testing-library/intro/), [react-hooks-testing-library](https://github.com/testing-library/react-hooks-testing-library), [MSW](https://mswjs.io/)
|
||||
- [tailwindcss](https://tailwindcss.com/)
|
||||
- [Github Actions](https://github.com/features/actions)
|
||||
|
||||
All npm package are keeping least release version powered by [Depfu](https://depfu.com/).
|
||||
|
||||
# Installation
|
||||
|
||||
```
|
||||
npx degit laststance/vite-react-ts-extended myapp
|
||||
```
|
||||
|
||||
### yarn
|
||||
|
||||
```sh
|
||||
cd myapp
|
||||
yarn install
|
||||
yarn validate # The installation was successful if no error occurs after running 'validate'.
|
||||
yarn dev
|
||||
```
|
||||
|
||||
### npm
|
||||
|
||||
```sh
|
||||
cd myapp
|
||||
npm install
|
||||
npm run validate # The installation was successful if no error occurs after running 'validate'.
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### Commands
|
||||
|
||||
```sh
|
||||
yarn dev # start development server
|
||||
yarn validate # run test,lint,build,typecheck concurrently
|
||||
yarn test # run jest
|
||||
yarn lint # run eslint
|
||||
yarn lint:fix # run eslint with --fix option
|
||||
yarn typecheck # run TypeScript compiler check
|
||||
yarn build # build production bundle to 'dist' directly
|
||||
yarn prettier # run prettier for json|yml|css|md|mdx files
|
||||
yarn clean # remove 'node_modules' 'yarn.lock' 'dist' completely
|
||||
yarn serve # launch server for production bundle in local
|
||||
```
|
||||
|
||||
# Background
|
||||
|
||||
The evolution of the React framework is accelerating more than ever before.
|
||||
[Next.js](https://nextjs.org/), [Remix](https://remix.run/), [RedwoodJS](https://redwoodjs.com/), [Gatsby](https://www.gatsbyjs.com/), [Blitz](https://blitzjs.com/) etc...
|
||||
|
||||
Ahthough I still need plain React programming starter some reason. (.e.g Demo, Experiment like Deep Dive React Core.)
|
||||
So far, [create-react-app](https://github.com/facebook/create-react-app) **was** it.
|
||||
In short, [create-react-app](https://github.com/facebook/create-react-app) development couldn't say active. Please read the [Issue](https://github.com/facebook/create-react-app/issues/11180) in details.
|
||||
|
||||
So I created an alternative to [create-react-app](https://github.com/facebook/create-react-app) for myself, based on [Vite](https://github.com/facebook/create-react-app).
|
||||
This project contains my very opinionted setup,
|
||||
but I hope it will be a useful tool for people who have similar needs to mine! 😀
|
||||
|
||||
# License
|
||||
|
||||
MIT
|
||||
|
||||
## Contributors ✨
|
||||
|
||||
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
|
||||
|
||||
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
||||
<!-- prettier-ignore-start -->
|
||||
<!-- markdownlint-disable -->
|
||||
<table>
|
||||
<tr>
|
||||
<td align="center"><a href="http://ryota-murakami.github.io/"><img src="https://avatars1.githubusercontent.com/u/5501268?s=400&u=7bf6b1580b95930980af2588ef0057f3e9ec1ff8&v=4?s=100" width="100px;" alt=""/><br /><sub><b>ryota-murakami</b></sub></a><br /><a href="https://github.com/laststance/vite-react-ts-extended/laststance/vite-react-ts-extended/commits?author=ryota-murakami" title="Code">💻</a> <a href="https://github.com/laststance/vite-react-ts-extended/laststance/vite-react-ts-extended/commits?author=ryota-murakami" title="Documentation">📖</a> <a href="https://github.com/laststance/vite-react-ts-extended/laststance/vite-react-ts-extended/commits?author=ryota-murakami" title="Tests">⚠️</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||
|
||||
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
|
||||
@@ -1,493 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<title>Happy Birthday My Love</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap');
|
||||
|
||||
body {
|
||||
font-family: 'Press Start 2P', cursive;
|
||||
background-color: #f5e6ff;
|
||||
color: #5a3d7a;
|
||||
overflow-x: hidden;
|
||||
touch-action: manipulation;
|
||||
}
|
||||
|
||||
.pixel-box {
|
||||
border: 4px solid #5a3d7a;
|
||||
box-shadow: 8px 8px 0 rgba(90, 61, 122, 0.2);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.pixel-box::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: 2px;
|
||||
right: 2px;
|
||||
bottom: 2px;
|
||||
border: 2px solid #d9b3ff;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.pixel-btn {
|
||||
border: 3px solid #5a3d7a;
|
||||
box-shadow: 4px 4px 0 rgba(90, 61, 122, 0.2);
|
||||
transition: all 0.1s;
|
||||
}
|
||||
|
||||
.pixel-btn:active {
|
||||
transform: translate(2px, 2px);
|
||||
box-shadow: 2px 2px 0 rgba(90, 61, 122, 0.2);
|
||||
}
|
||||
|
||||
.pixel-divider {
|
||||
height: 4px;
|
||||
background-color: #5a3d7a;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.pixel-divider::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 2px;
|
||||
background-color: #d9b3ff;
|
||||
}
|
||||
|
||||
.pixel-avatar {
|
||||
border: 3px solid #5a3d7a;
|
||||
}
|
||||
|
||||
.section {
|
||||
min-height: 100vh;
|
||||
padding: 2rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.pixel-text {
|
||||
text-shadow: 2px 2px 0 rgba(90, 61, 122, 0.2);
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.pixel-scene {
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
/* Hide audio controls */
|
||||
#bgMusic {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Pixel heart animation */
|
||||
@keyframes pulse {
|
||||
0% { transform: scale(1); }
|
||||
50% { transform: scale(1.1); }
|
||||
100% { transform: scale(1); }
|
||||
}
|
||||
|
||||
.pixel-heart {
|
||||
animation: pulse 1.5s infinite;
|
||||
image-rendering: pixelated;
|
||||
}
|
||||
|
||||
/* Password modal styles */
|
||||
.modal-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background-color: #fff;
|
||||
padding: 2rem;
|
||||
border-radius: 8px;
|
||||
text-align: center;
|
||||
animation: fadeIn 0.3s ease-out;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; transform: scale(0.8); }
|
||||
to { opacity: 1; transform: scale(1); }
|
||||
}
|
||||
|
||||
.content-hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.shake {
|
||||
animation: shake 0.5s ease-in-out;
|
||||
}
|
||||
|
||||
@keyframes shake {
|
||||
0%, 100% { transform: translateX(0); }
|
||||
25% { transform: translateX(-10px); }
|
||||
75% { transform: translateX(10px); }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="relative">
|
||||
<!-- Password Modal -->
|
||||
<div id="passwordModal" class="modal-overlay">
|
||||
<div class="modal-content pixel-box">
|
||||
<h2 class="text-xl mb-6 text-purple-800 pixel-text">Enter Password</h2>
|
||||
<div class="mb-4">
|
||||
<input type="password" id="passwordInput"
|
||||
class="w-full px-4 py-2 border-2 border-purple-300 rounded focus:outline-none focus:border-purple-500"
|
||||
placeholder="Password">
|
||||
</div>
|
||||
<button id="submitPassword"
|
||||
class="pixel-btn bg-purple-500 text-white px-6 py-2 rounded hover:bg-purple-600 transition-colors">
|
||||
Enter
|
||||
</button>
|
||||
<p id="errorMessage" class="mt-4 text-red-500 text-sm hidden pixel-text">Incorrect password. Try again!</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Main Content -->
|
||||
<div id="mainContent" class="content-hidden">
|
||||
<!-- Background Music -->
|
||||
<audio id="bgMusic" loop>
|
||||
<source src="sound.mp3" type="audio/mpeg" autoplay>
|
||||
</audio>
|
||||
|
||||
<!-- Music Toggle Button -->
|
||||
<button id="musicToggle" class="fixed bottom-4 right-4 z-50 w-12 h-12 bg-purple-300 pixel-btn rounded-full flex items-center justify-center">
|
||||
<svg id="musicIcon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#5a3d7a">
|
||||
<path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z"/>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<!-- Navigation Dots -->
|
||||
<div class="fixed right-4 top-1/2 transform -translate-y-1/2 z-40 flex flex-col space-y-3">
|
||||
<a href="#section1" class="w-3 h-3 rounded-full bg-purple-300 border-2 border-purple-700 dot"></a>
|
||||
<a href="#section2" class="w-3 h-3 rounded-full bg-purple-300 border-2 border-purple-700 dot"></a>
|
||||
<a href="#section3" class="w-3 h-3 rounded-full bg-purple-300 border-2 border-purple-700 dot"></a>
|
||||
<a href="#section4" class="w-3 h-3 rounded-full bg-purple-300 border-2 border-purple-700 dot"></a>
|
||||
<a href="#section5" class="w-3 h-3 rounded-full bg-purple-300 border-2 border-purple-700 dot"></a>
|
||||
<a href="#section6" class="w-3 h-3 rounded-full bg-purple-300 border-2 border-purple-700 dot"></a>
|
||||
<a href="#section7" class="w-3 h-3 rounded-full bg-purple-300 border-2 border-purple-700 dot"></a>
|
||||
<a href="#section8" class="w-3 h-3 rounded-full bg-purple-300 border-2 border-purple-700 dot"></a>
|
||||
<a href="#section9" class="w-3 h-3 rounded-full bg-purple-300 border-2 border-purple-700 dot"></a>
|
||||
</div>
|
||||
|
||||
<!-- Sections -->
|
||||
<div id="section1" class="section bg-pink-100">
|
||||
<div class="pixel-box bg-white p-6 mx-auto max-w-md">
|
||||
<div class="flex justify-center mb-6">
|
||||
<img src="https://img.freepik.com/premium-photo/high-rise-buildings-downtown-bangkok-night_5219-2322.jpg?w=996" alt="Rooftop pixel art" class="w-64 h-64 pixel-avatar">
|
||||
</div>
|
||||
<h1 class="text-xl md:text-2xl text-center mb-6 text-purple-800 pixel-text">Happy Birthday My Love!</h1>
|
||||
<p class="text-xs md:text-sm mb-4 pixel-text">Our journey together began on a rooftop...</p>
|
||||
<p class="text-xs md:text-sm pixel-text">Where we first met under the stars ✨</p>
|
||||
<div class="flex justify-center mt-8">
|
||||
<img src="https://cdn.pixabay.com/photo/2017/09/23/16/33/pixel-heart-2779422_1280.png" alt="Pixel heart" class="w-10 h-10 pixel-heart">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="section2" class="section bg-purple-100">
|
||||
<div class="pixel-box bg-white p-6 mx-auto max-w-md">
|
||||
<div class="flex justify-center mb-6">
|
||||
<img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQcLaTSzF2i_kDkosNQgoW8bgqg4rq-568TXw&s" alt="Park pixel art" class="w-64 h-64 pixel-avatar">
|
||||
</div>
|
||||
<h2 class="text-lg md:text-xl text-center mb-6 text-purple-800 pixel-text">Our First Date</h2>
|
||||
<p class="text-xs md:text-sm mb-4 pixel-text">Walking in the park together</p>
|
||||
<p class="text-xs md:text-sm pixel-text">I knew then you were special 💕</p>
|
||||
<div class="flex justify-between mt-8">
|
||||
<img src="pics/khaosok.JPG" alt="You" class="w-16 h-16 pixel-avatar">
|
||||
<img src="pics/temple.jpg" alt="Her" class="w-16 h-16 pixel-avatar">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="section3" class="section bg-pink-100">
|
||||
<div class="pixel-box bg-white p-6 mx-auto max-w-md">
|
||||
<div class="flex justify-center mb-6">
|
||||
<img src="pics/cook.jpg" alt="Kitchen pixel art" class="w-64 h-64 pixel-avatar">
|
||||
</div>
|
||||
<h2 class="text-lg md:text-xl text-center mb-6 text-purple-800 pixel-text">Our First Cooking Night</h2>
|
||||
<p class="text-xs md:text-sm mb-4 pixel-text">Making dinner together in your kitchen</p>
|
||||
<p class="text-xs md:text-sm pixel-text">Simple moments that mean everything 🍳</p>
|
||||
<div class="flex justify-center mt-8">
|
||||
<img src="https://cdn.pixabay.com/photo/2017/09/23/16/33/pixel-heart-2779422_1280.png" alt="Pixel heart" class="w-10 h-10 pixel-heart">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="section4" class="section bg-purple-100">
|
||||
<div class="pixel-box bg-white p-6 mx-auto max-w-md">
|
||||
<div class="flex justify-center mb-6">
|
||||
<img src="https://www.airportels.asia/wp-content/uploads/2023/12/Shopping-Spots-in-Chinatown-scaled.webp" alt="Chinese restaurant pixel art" class="w-64 h-64 pixel-avatar">
|
||||
</div>
|
||||
<h2 class="text-lg md:text-xl text-center mb-6 text-purple-800 pixel-text">Chinese Restaurant</h2>
|
||||
<p class="text-xs md:text-sm mb-4 pixel-text">"I like to try things"</p>
|
||||
<p class="text-xs md:text-sm pixel-text">And trying life with you has been the best adventure 🥢</p>
|
||||
<div class="flex justify-center mt-8">
|
||||
<img src="https://cdn.pixabay.com/photo/2017/09/23/16/33/pixel-heart-2779422_1280.png" alt="Pixel heart" class="w-10 h-10 pixel-heart">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="section5" class="section bg-pink-100">
|
||||
<div class="pixel-box bg-white p-6 mx-auto max-w-md">
|
||||
<div class="flex justify-center mb-6">
|
||||
<img src="https://media-cdn.tripadvisor.com/media/attractions-splice-spp-674x446/07/00/a4/db.jpg" alt="Kao Sok pixel art" class="w-64 h-64 pixel-avatar">
|
||||
</div>
|
||||
<h2 class="text-lg md:text-xl text-center mb-6 text-purple-800 pixel-text">Kao Sok Adventure</h2>
|
||||
<p class="text-xs md:text-sm mb-4 pixel-text">Our trip to Kao Sok with my best friend</p>
|
||||
<p class="text-xs md:text-sm pixel-text">Sharing my world with you 🌿</p>
|
||||
<div class="flex justify-center mt-8">
|
||||
<img src="https://cdn.pixabay.com/photo/2017/09/23/16/33/pixel-heart-2779422_1280.png" alt="Pixel jungle" class="w-24 h-24">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="section6" class="section bg-purple-100">
|
||||
<div class="pixel-box bg-white p-6 mx-auto max-w-md">
|
||||
<div class="flex justify-center mb-6">
|
||||
<img src="https://dynamic-media-cdn.tripadvisor.com/media/photo-o/07/b9/58/b4/photo0jpg.jpg?w=1200&h=-1&s=1&cx=1000&cy=543&chk=v1_d6044045ef865bfe074a" alt="Kuala Lumpur pixel art" class="w-64 h-64 pixel-avatar">
|
||||
</div>
|
||||
<h2 class="text-lg md:text-xl text-center mb-6 text-purple-800 pixel-text">Kuala Lumpur</h2>
|
||||
<p class="text-xs md:text-sm mb-4 pixel-text">Joining you during your work trip</p>
|
||||
<p class="text-xs md:text-sm pixel-text">Because every moment with you is precious 🌆</p>
|
||||
<div class="flex justify-center mt-8">
|
||||
<img src="https://cdn.pixabay.com/photo/2017/09/23/16/33/pixel-heart-2779422_1280.png" alt="Pixel heart" class="w-10 h-10 pixel-heart">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="section7" class="section bg-pink-100">
|
||||
<div class="pixel-box bg-white p-6 mx-auto max-w-md">
|
||||
<div class="flex justify-center mb-6">
|
||||
<img src="https://img.static-af.com/transform/45cb9a13-b167-4842-8ea8-05d0cc7a4d04/" alt="France pixel art" class="w-64 h-64 pixel-avatar">
|
||||
</div>
|
||||
<h2 class="text-lg md:text-xl text-center mb-6 text-purple-800 pixel-text">Time Apart</h2>
|
||||
<p class="text-xs md:text-sm mb-4 pixel-text">Me leaving for France</p>
|
||||
<p class="text-xs md:text-sm mb-4 pixel-text">You facing work difficulties</p>
|
||||
<p class="text-xs md:text-sm text-purple-600 pixel-text">Remember to take time for yourself</p>
|
||||
<p class="text-xs md:text-sm text-purple-600 pixel-text">Your health and happiness matter most 💖</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="section8" class="section bg-gradient-to-b from-purple-200 to-pink-200">
|
||||
<div class="pixel-box bg-white p-6 mx-auto max-w-md">
|
||||
<div class="flex justify-center mb-6">
|
||||
<img src="pics/boat.jpg" alt="Birthday kiss pixel art" class="w-64 h-64 pixel-avatar">
|
||||
</div>
|
||||
<h2 class="text-lg md:text-xl text-center mb-6 text-purple-800 pixel-text">Happy Birthday!</h2>
|
||||
<p class="text-xs md:text-sm mb-4 pixel-text">Back together in Bangkok</p>
|
||||
<p class="text-xs md:text-sm mb-6 pixel-text">Celebrating you on your special day 🎂</p>
|
||||
<div class="flex justify-center mb-6">
|
||||
<img src="https://cdn.pixabay.com/photo/2017/09/23/16/33/pixel-heart-2779422_1280.png" alt="Pixel heart" class="w-16 h-16 pixel-heart">
|
||||
</div>
|
||||
<p class="text-xs md:text-sm text-center pixel-text">I love you more than words can say</p>
|
||||
<p class="text-xs md:text-sm text-center text-purple-600 pixel-text mt-4">(Tap the heart below)</p>
|
||||
<div class="flex justify-center mt-6">
|
||||
<button id="finalHeart" class="pixel-btn bg-pink-200 p-4 rounded-full">
|
||||
<img src="https://cdn.pixabay.com/photo/2017/09/23/16/33/pixel-heart-2779422_1280.png" alt="Pixel heart" class="w-12 h-12 pixel-heart">
|
||||
</button>
|
||||
</div>
|
||||
<div id="kissAnimation" class="hidden mt-6 flex justify-center">
|
||||
<img src="https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/f/e7781e25-3bf5-4185-aad7-ec93d0b5e1b0/d7fa2wq-cf60174b-9a41-44de-bb2f-605cde85dad5.gif?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1cm46YXBwOjdlMGQxODg5ODIyNjQzNzNhNWYwZDQxNWVhMGQyNmUwIiwiaXNzIjoidXJuOmFwcDo3ZTBkMTg4OTgyMjY0MzczYTVmMGQ0MTVlYTBkMjZlMCIsIm9iaiI6W1t7InBhdGgiOiJcL2ZcL2U3NzgxZTI1LTNiZjUtNDE4NS1hYWQ3LWVjOTNkMGI1ZTFiMFwvZDdmYTJ3cS1jZjYwMTc0Yi05YTQxLTQ0ZGUtYmIyZi02MDVjZGU4NWRhZDUuZ2lmIn1dXSwiYXVkIjpbInVybjpzZXJ2aWNlOmZpbGUuZG93bmxvYWQiXX0.vX_oTdMeJ4D5xWpqNQV4NOjiJW4ahpQWZ4Fyp4xX8x8" alt="Pixel kiss" class="w-32 h-32">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Music toggle functionality
|
||||
const musicToggle = document.getElementById('musicToggle');
|
||||
const musicIcon = document.getElementById('musicIcon');
|
||||
const bgMusic = document.getElementById('bgMusic');
|
||||
let musicPlaying = true;
|
||||
|
||||
// Attempt to autoplay music (may be blocked by browser)
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const playPromise = bgMusic.play();
|
||||
|
||||
if (playPromise !== undefined) {
|
||||
playPromise.then(_ => {
|
||||
musicPlaying = true;
|
||||
musicIcon.innerHTML = '<path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z"/>';
|
||||
})
|
||||
.catch(error => {
|
||||
musicPlaying = false;
|
||||
musicIcon.innerHTML = '<path d="M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z"/>';
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
musicToggle.addEventListener('click', function() {
|
||||
if (musicPlaying) {
|
||||
bgMusic.pause();
|
||||
musicIcon.innerHTML = '<path d="M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z"/>';
|
||||
musicPlaying = false;
|
||||
} else {
|
||||
bgMusic.play();
|
||||
musicIcon.innerHTML = '<path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z"/>';
|
||||
musicPlaying = true;
|
||||
}
|
||||
});
|
||||
|
||||
// Final heart click animation
|
||||
const finalHeart = document.getElementById('finalHeart');
|
||||
const kissAnimation = document.getElementById('kissAnimation');
|
||||
|
||||
finalHeart.addEventListener('click', function() {
|
||||
kissAnimation.classList.remove('hidden');
|
||||
finalHeart.classList.add('hidden');
|
||||
|
||||
// Create floating hearts
|
||||
for (let i = 0; i < 10; i++) {
|
||||
createFloatingHeart();
|
||||
}
|
||||
});
|
||||
|
||||
function createFloatingHeart() {
|
||||
const heart = document.createElement('div');
|
||||
heart.innerHTML = '❤️';
|
||||
heart.className = 'absolute text-xl animate-float';
|
||||
heart.style.left = Math.random() * 100 + 'vw';
|
||||
heart.style.top = '100vh';
|
||||
heart.style.animationDuration = (Math.random() * 3 + 2) + 's';
|
||||
document.body.appendChild(heart);
|
||||
|
||||
// Remove heart after animation
|
||||
setTimeout(() => {
|
||||
heart.remove();
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
// Add animation style
|
||||
const style = document.createElement('style');
|
||||
style.innerHTML = `
|
||||
@keyframes float {
|
||||
0% {
|
||||
transform: translateY(0) rotate(0deg);
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
transform: translateY(-100vh) rotate(360deg);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
.animate-float {
|
||||
animation: float linear forwards;
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
|
||||
// Update navigation dots based on scroll position
|
||||
const dots = document.querySelectorAll('.dot');
|
||||
const sections = document.querySelectorAll('.section');
|
||||
|
||||
function updateActiveDot() {
|
||||
const scrollPosition = window.scrollY;
|
||||
|
||||
sections.forEach((section, index) => {
|
||||
const sectionTop = section.offsetTop;
|
||||
const sectionHeight = section.offsetHeight;
|
||||
|
||||
if (scrollPosition >= sectionTop - 50 && scrollPosition < sectionTop + sectionHeight - 50) {
|
||||
dots.forEach(dot => dot.classList.remove('bg-purple-700'));
|
||||
dots[index].classList.add('bg-purple-700');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
window.addEventListener('scroll', updateActiveDot);
|
||||
updateActiveDot(); // Initialize
|
||||
|
||||
// Password protection
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const passwordModal = document.getElementById('passwordModal');
|
||||
const mainContent = document.getElementById('mainContent');
|
||||
const passwordInput = document.getElementById('passwordInput');
|
||||
const submitButton = document.getElementById('submitPassword');
|
||||
const errorMessage = document.getElementById('errorMessage');
|
||||
const correctPassword = 'iloveyou';
|
||||
const bgMusic = document.getElementById('bgMusic');
|
||||
const musicToggle = document.getElementById('musicToggle');
|
||||
const musicIcon = document.getElementById('musicIcon');
|
||||
|
||||
// Check if already authenticated
|
||||
if (sessionStorage.getItem('authenticated') === 'true') {
|
||||
passwordModal.style.display = 'none';
|
||||
mainContent.classList.remove('content-hidden');
|
||||
// Start playing music
|
||||
bgMusic.play().catch(error => {
|
||||
console.log('Auto-play prevented by browser');
|
||||
musicPlaying = false;
|
||||
updateMusicIcon(false);
|
||||
});
|
||||
}
|
||||
|
||||
function checkPassword() {
|
||||
if (passwordInput.value === correctPassword) {
|
||||
passwordModal.style.display = 'none';
|
||||
mainContent.classList.remove('content-hidden');
|
||||
sessionStorage.setItem('authenticated', 'true');
|
||||
|
||||
// Start playing music after password entry
|
||||
bgMusic.play().catch(error => {
|
||||
console.log('Auto-play prevented by browser');
|
||||
musicPlaying = false;
|
||||
updateMusicIcon(false);
|
||||
});
|
||||
} else {
|
||||
errorMessage.classList.remove('hidden');
|
||||
passwordInput.value = '';
|
||||
passwordModal.querySelector('.modal-content').classList.add('shake');
|
||||
setTimeout(() => {
|
||||
passwordModal.querySelector('.modal-content').classList.remove('shake');
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
|
||||
function updateMusicIcon(playing) {
|
||||
if (playing) {
|
||||
musicIcon.innerHTML = '<path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z"/>';
|
||||
} else {
|
||||
musicIcon.innerHTML = '<path d="M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z"/>';
|
||||
}
|
||||
}
|
||||
|
||||
// Music toggle functionality
|
||||
musicToggle.addEventListener('click', function() {
|
||||
if (musicPlaying) {
|
||||
bgMusic.pause();
|
||||
musicPlaying = false;
|
||||
} else {
|
||||
bgMusic.play();
|
||||
musicPlaying = true;
|
||||
}
|
||||
updateMusicIcon(musicPlaying);
|
||||
});
|
||||
|
||||
submitButton.addEventListener('click', checkPassword);
|
||||
passwordInput.addEventListener('keypress', function(e) {
|
||||
if (e.key === 'Enter') {
|
||||
checkPassword();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,32 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Array of known potentially hanging packages
|
||||
hanging_packages=("xmlhttprequest-ssl@latest" "engine.io-parser@latest")
|
||||
|
||||
# Timeout in seconds for each package installation attempt
|
||||
|
||||
|
||||
install_with_timeout() {
|
||||
package=$1
|
||||
echo "Attempting to install $package with a timeout of $timeout_duration seconds."
|
||||
# Start npm install in the background
|
||||
npm install $package --verbose &> $package.log &
|
||||
|
||||
# Get PID of the npm process
|
||||
pid=$!
|
||||
|
||||
# Wait for the npm process to finish or timeout
|
||||
(sleep $timeout_duration && kill -0 $pid 2>/dev/null && kill -9 $pid && echo "Timeout reached for $package, process killed." && echo $package >> exclude.log) &
|
||||
waiter_pid=$!
|
||||
|
||||
# Wait for the npm process to complete
|
||||
wait $pid
|
||||
|
||||
# Kill the waiter process in case npm finished before the timeout
|
||||
kill -0 $waiter_pid 2>/dev/null && kill -9 $waiter_pid
|
||||
}
|
||||
|
||||
# Install potentially hanging packages first with a timeout
|
||||
for package in "${hanging_packages[@]}"; do
|
||||
install_with_timeout $package
|
||||
done
|
||||
@@ -1,35 +0,0 @@
|
||||
const config = {
|
||||
collectCoverageFrom: ['<rootDir>/src/**/*.{js,jsx,ts,tsx}', '!src/**/*.d.ts'],
|
||||
moduleDirectories: ['node_modules'],
|
||||
moduleFileExtensions: ['js', 'mjs', 'jsx', 'ts', 'tsx', 'json'],
|
||||
moduleNameMapper: {
|
||||
'^.+\\.module\\.(css|sass|scss)$': 'identity-obj-proxy',
|
||||
},
|
||||
notify: true,
|
||||
notifyMode: 'success-change',
|
||||
resetMocks: true,
|
||||
roots: ['<rootDir>'],
|
||||
setupFilesAfterEnv: ['<rootDir>/jest/setupTests.ts'],
|
||||
testEnvironment: 'jsdom',
|
||||
testMatch: [
|
||||
'<rootDir>/src/**/*.{spec,test}.{js,jsx,ts,tsx}',
|
||||
'<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}',
|
||||
],
|
||||
transform: {
|
||||
'^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)':
|
||||
'<rootDir>/jest/fileTransform.js',
|
||||
'^.+\\.[jt]sx?$': 'esbuild-jest',
|
||||
'^.+\\.css$': '<rootDir>/jest/cssTransform.js',
|
||||
},
|
||||
transformIgnorePatterns: [
|
||||
'[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs|cjs|ts|tsx)$',
|
||||
'^.+\\.module\\.(css|sass|scss)$',
|
||||
],
|
||||
verbose: true,
|
||||
watchPlugins: [
|
||||
'jest-watch-typeahead/filename',
|
||||
'jest-watch-typeahead/testname',
|
||||
],
|
||||
}
|
||||
|
||||
module.exports = config
|
||||
3400
src/Managing.Pinky/package-lock.json
generated
3400
src/Managing.Pinky/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,48 +0,0 @@
|
||||
{
|
||||
"name": "managing",
|
||||
"version": "2.0.0",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"serve": "serve -s dist -p 3000",
|
||||
"test": "jest",
|
||||
"lint": "eslint . --ext .ts,.tsx,.js,jsx",
|
||||
"lint:fix": "eslint . --ext .ts,.tsx,.js,jsx --fix",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"prettier": "prettier --write \"**/*.+(json|yml|css|md|mdx)\"",
|
||||
"clean": "rimraf node_modules yarn.lock dist",
|
||||
"validate": "./scripts/validate"
|
||||
},
|
||||
"dependencies": {
|
||||
"@heroicons/react": "^1.0.6",
|
||||
"@tailwindcss/typography": "^0.5.0",
|
||||
"@tanstack/react-query": "^5.67.1",
|
||||
"autoprefixer": "^10.4.7",
|
||||
"classnames": "^2.3.1",
|
||||
"jotai": "^1.6.7",
|
||||
"latest-version": "^9.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/elliptic": "^6.4.18",
|
||||
"@types/react": "^18.0.9",
|
||||
"@types/react-dom": "^18.0.4",
|
||||
"@types/react-grid-layout": "^1.3.2",
|
||||
"@types/react-plotly.js": "^2.6.0",
|
||||
"@types/react-slider": "^1.3.1",
|
||||
"@types/react-table": "^7.7.12",
|
||||
"@vitejs/plugin-react": "^1.3.2",
|
||||
"autoprefixer": "^10.4.7",
|
||||
"daisyui": "^3.5.1",
|
||||
"postcss": "^8.4.13",
|
||||
"prettier": "^2.6.1",
|
||||
"prettier-plugin-tailwind-css": "^1.5.0",
|
||||
"tailwindcss": "^3.0.23",
|
||||
"typescript": "^5.7.3",
|
||||
"vite": "^6.0.11"
|
||||
},
|
||||
"msw": {
|
||||
"workerDirectory": ""
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 475 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 3.2 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 3.6 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 850 KiB |
@@ -1,6 +0,0 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
autoprefixer: {},
|
||||
tailwindcss: {},
|
||||
},
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
module.exports = {
|
||||
plugins: [require('prettier-plugin-tailwindcss')],
|
||||
tailwindConfig: './tailwind.config.js',
|
||||
}
|
||||
Binary file not shown.
@@ -1,12 +0,0 @@
|
||||
module.exports = {
|
||||
content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
|
||||
daisyui: {
|
||||
themes: ['black', 'coffee', 'cyberpunk', 'lofi', 'retro', 'kaigen'],
|
||||
},
|
||||
plugins: [require('@tailwindcss/typography'), require('daisyui')],
|
||||
theme: {
|
||||
container: {
|
||||
center: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx"
|
||||
},
|
||||
"include": ["./src", "hardhat.config.js"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import react from '@vitejs/plugin-react'
|
||||
import { defineConfig } from 'vite'
|
||||
|
||||
export default defineConfig({
|
||||
build: {
|
||||
minify: false,
|
||||
sourcemap: false,
|
||||
target: 'es2022',
|
||||
},
|
||||
optimizeDeps: {
|
||||
esbuildOptions: {
|
||||
target: 'es2022',
|
||||
},
|
||||
},
|
||||
plugins: [react()],
|
||||
publicDir: 'assets',
|
||||
server: {
|
||||
host: true,
|
||||
open: true,
|
||||
},
|
||||
})
|
||||
@@ -1,37 +0,0 @@
|
||||
{
|
||||
"ManagingDatabase": {
|
||||
"ConnectionString": "mongodb://managingdb:27017",
|
||||
"DatabaseName": "ManagingDb"
|
||||
},
|
||||
"InfluxDb": {
|
||||
"Url": "http://influxdb:8086/",
|
||||
"Organization": "",
|
||||
"Token": ""
|
||||
},
|
||||
"Serilog": {
|
||||
"MinimumLevel": {
|
||||
"Default": "Information",
|
||||
"Override": {
|
||||
"Microsoft": "Information",
|
||||
"System": "Warning"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ElasticConfiguration": {
|
||||
"Uri": "http://elasticsearch:9200"
|
||||
},
|
||||
"Discord": {
|
||||
"BotActivity": "trading strategies",
|
||||
"HandleUserAction": true,
|
||||
"ApplicationId": "",
|
||||
"PublicKey": "",
|
||||
"TokenId": "",
|
||||
"SignalChannelId": 966080506473099314,
|
||||
"TradesChannelId": 998374177763491851,
|
||||
"TroublesChannelId": 1015761955321040917,
|
||||
"CopyTradingChannelId": 1132022887012909126,
|
||||
"RequestsChannelId": 1018589494968078356,
|
||||
"ButtonExpirationMinutes": 10
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
{
|
||||
"ManagingDatabase": {
|
||||
"ConnectionString": "srv-captain--mongo-db",
|
||||
"DatabaseName": "ManagingDb"
|
||||
},
|
||||
"InfluxDb": {
|
||||
"Url": "https://influx-db.apps.managing.live",
|
||||
"Token": "gzE8KEmIfBaZYkcEMwaZyY7byO3rVwVsIeAd3UPrmi1xTajQoGWktFQjoQ3Y8D6hCbdIK7l5zVqNYox3wGilrA==",
|
||||
"Organization": "managing-org"
|
||||
},
|
||||
"Serilog": {
|
||||
"MinimumLevel": {
|
||||
"Default": "Information",
|
||||
"Override": {
|
||||
"Microsoft": "Information",
|
||||
"System": "Warning"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ElasticConfiguration": {
|
||||
"Uri": "https://elastic-search.apps.managing.live"
|
||||
},
|
||||
"Discord": {
|
||||
"ApplicationId": "1134966063075971144",
|
||||
"PublicKey": "55bc79e483ffa203a1da1e49588c86cf1345dd66d676ab52c73dbf09cc1b4800",
|
||||
"TokenId": "MTEzNDk2NjA2MzA3NTk3MTE0NA.GWHiDf.2s2qq3XCI2bftfnqm_0ndcou5LQwZPdsCZ9nQc",
|
||||
"SignalChannelId": 1134858150667898910,
|
||||
"TradesChannelId": 1134858092530634864,
|
||||
"TroublesChannelId": 1134858233031446671,
|
||||
"CopyTradingChannelId": 1134857874896588881,
|
||||
"RequestsChannelId": 1018589494968078356,
|
||||
"LeaderboardChannelId": 1133169725237633095,
|
||||
"NoobiesboardChannelId": 1133504653485690940,
|
||||
"ButtonExpirationMinutes": 10
|
||||
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
GatewayExceptionResponse
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user