diff --git a/.github/workflows/static-checks.yml b/.github/workflows/static-checks.yml index 204c2d4..6ac1d4c 100644 --- a/.github/workflows/static-checks.yml +++ b/.github/workflows/static-checks.yml @@ -1,29 +1,31 @@ -name: Static Checks - -on: - push: - branches: - - main - - staging - pull_request: {} - workflow_dispatch: {} - -jobs: - test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: '20' - - uses: actions/cache@v3 - id: cache - with: - path: '**/node_modules' - key: ${{ runner.os }}-npm-${{ hashFiles('**/yarn.lock') }} - restore-keys: ${{ runner.os }}-npm- - - name: Install project dependencies - if: steps.cache.outputs.cache-hit != 'true' - run: yarn install --frozen-lockfile - - name: Testing - run: yarn tsc --noEmit && yarn lint && yarn build +name: Static Checks + +on: + push: + branches: + - main + - dev + pull_request: + +permissions: + actions: read + contents: read + +jobs: + main: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: actions/setup-node@v4 + with: + node-version: 22 + - name: Enable Corepack + run: corepack enable + - name: Prepare Yarn + run: corepack prepare yarn@4.6.0 --activate + - name: Install dependencies + run: yarn install --frozen-lockfile + - name: Testing + run: yarn tsc --noEmit && yarn lint && yarn build diff --git a/.gitignore b/.gitignore index 1cac559..8a66ef3 100644 --- a/.gitignore +++ b/.gitignore @@ -22,4 +22,5 @@ dist-ssr *.njsproj *.sln *.sw? -.env \ No newline at end of file +.env +.yarn diff --git a/.prettierrc.cjs b/.prettierrc.cjs index e643a35..d5b76de 100644 --- a/.prettierrc.cjs +++ b/.prettierrc.cjs @@ -1,7 +1,7 @@ -module.exports = { - singleQuote: true, - trailingComma: "all", - printWidth: 120, - semi: true, - plugins: ["prettier-plugin-tailwindcss"], -}; +module.exports = { + singleQuote: true, + trailingComma: 'all', + printWidth: 120, + semi: true, + plugins: ['prettier-plugin-tailwindcss'], +}; diff --git a/.yarn/install-state.gz b/.yarn/install-state.gz deleted file mode 100644 index 23143fb..0000000 Binary files a/.yarn/install-state.gz and /dev/null differ diff --git a/.yarnrc.yml b/.yarnrc.yml index 0acb263..3186f3f 100644 --- a/.yarnrc.yml +++ b/.yarnrc.yml @@ -1 +1 @@ -nodeLinker: node-modules +nodeLinker: node-modules diff --git a/README.md b/README.md index 74872fd..7e0a07f 100644 --- a/README.md +++ b/README.md @@ -1,50 +1,9 @@ -# React + TypeScript + Vite +# Tarotsol AI -This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. +## Blowfish ticket number: 5948 -Currently, two official plugins are available: +## Domain -- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh -- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh +[https://tarotsol.ai/](https://tarotsol.ai/) -## Expanding the ESLint configuration - -If you are developing a production application, we recommend updating the configuration to enable type aware lint rules: - -- Configure the top-level `parserOptions` property like this: - -```js -export default tseslint.config({ - languageOptions: { - // other options... - parserOptions: { - project: ['./tsconfig.node.json', './tsconfig.app.json'], - tsconfigRootDir: import.meta.dirname, - }, - }, -}) -``` - -- Replace `tseslint.configs.recommended` to `tseslint.configs.recommendedTypeChecked` or `tseslint.configs.strictTypeChecked` -- Optionally add `...tseslint.configs.stylisticTypeChecked` -- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and update the config: - -```js -// eslint.config.js -import react from 'eslint-plugin-react' - -export default tseslint.config({ - // Set the react version - settings: { react: { version: '18.3' } }, - plugins: { - // Add the react plugin - react, - }, - rules: { - // other rules... - // Enable its recommended rules - ...react.configs.recommended.rules, - ...react.configs['jsx-runtime'].rules, - }, -}) -``` +[https://regal-moonbeam-3e1c0e.netlify.app/game](https://regal-moonbeam-3e1c0e.netlify.app/game) diff --git a/components.json b/components.json index fc152dc..159c778 100644 --- a/components.json +++ b/components.json @@ -18,4 +18,4 @@ "hooks": "@/hooks" }, "iconLibrary": "lucide" -} \ No newline at end of file +} diff --git a/eslint.config.js b/eslint.config.js index 5d4362f..e0cafa3 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -59,6 +59,7 @@ export default tseslint.config( '@typescript-eslint/no-unsafe-call': 'off', '@typescript-eslint/no-unsafe-assignment': 'off', '@typescript-eslint/restrict-template-expressions': 'off', + '@typescript-eslint/consistent-type-definitions': ['error', 'type'], }, }, ); diff --git a/index.html b/index.html index 27abc50..9dd6a80 100644 --- a/index.html +++ b/index.html @@ -2,15 +2,19 @@ - + - Vite + React + TS + Tarotsol AI +
diff --git a/package.json b/package.json index 3aedf0e..854e5b5 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,9 @@ "@radix-ui/react-accordion": "^1.2.2", "@radix-ui/react-dialog": "^1.1.4", "@radix-ui/react-popover": "^1.1.4", + "@radix-ui/react-select": "^2.1.4", "@radix-ui/react-slot": "^1.1.1", + "@radix-ui/react-tooltip": "^1.1.6", "@solana/spl-token": "^0.4.9", "@solana/wallet-adapter-react": "^0.15.35", "@solana/wallet-adapter-wallets": "^0.19.32", @@ -29,6 +31,7 @@ "lucide-react": "^0.469.0", "react": "^18.3.1", "react-dom": "^18.3.1", + "react-fast-marquee": "^1.6.5", "react-hook-form": "^7.54.2", "react-router": "^7.1.1", "react-toastify": "^11.0.2", diff --git a/postcss.config.js b/postcss.config.js index 2e7af2b..2aa7205 100644 --- a/postcss.config.js +++ b/postcss.config.js @@ -3,4 +3,4 @@ export default { tailwindcss: {}, autoprefixer: {}, }, -} +}; diff --git a/public/favicon.svg b/public/favicon.svg new file mode 100644 index 0000000..9315549 --- /dev/null +++ b/public/favicon.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/public/icons/currencies/usdcMint.svg b/public/icons/currencies/usdcMint.svg new file mode 100644 index 0000000..10cdb67 --- /dev/null +++ b/public/icons/currencies/usdcMint.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/public/icons/currencies/usdtMint.svg b/public/icons/currencies/usdtMint.svg new file mode 100644 index 0000000..328392a --- /dev/null +++ b/public/icons/currencies/usdtMint.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/public/icons/currencies/wSolMint.svg b/public/icons/currencies/wSolMint.svg new file mode 100644 index 0000000..919c2bc --- /dev/null +++ b/public/icons/currencies/wSolMint.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/public/icons/dot.svg b/public/icons/dot.svg new file mode 100644 index 0000000..25c38a9 --- /dev/null +++ b/public/icons/dot.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/icons/modals/failed.svg b/public/icons/modals/failed.svg new file mode 100644 index 0000000..1e0b405 --- /dev/null +++ b/public/icons/modals/failed.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/icons/modals/funds.svg b/public/icons/modals/funds.svg new file mode 100644 index 0000000..7049eb3 --- /dev/null +++ b/public/icons/modals/funds.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/icons/modals/scissors.svg b/public/icons/modals/scissors.svg new file mode 100644 index 0000000..a4a52ea --- /dev/null +++ b/public/icons/modals/scissors.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/public/icons/modals/successful.svg b/public/icons/modals/successful.svg new file mode 100644 index 0000000..a83a0cb --- /dev/null +++ b/public/icons/modals/successful.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/icons/socials/twitter.svg b/public/icons/socials/twitter.svg new file mode 100644 index 0000000..ae9b6fd --- /dev/null +++ b/public/icons/socials/twitter.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/public/icons/star.svg b/public/icons/star.svg new file mode 100644 index 0000000..9c54f1a --- /dev/null +++ b/public/icons/star.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/icons/sunburst.svg b/public/icons/sunburst.svg new file mode 100644 index 0000000..ed84061 --- /dev/null +++ b/public/icons/sunburst.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/images/cards/0.jpg b/public/images/cards/0.jpg new file mode 100644 index 0000000..b02fb71 Binary files /dev/null and b/public/images/cards/0.jpg differ diff --git a/public/images/cards/1.jpg b/public/images/cards/1.jpg new file mode 100644 index 0000000..caa418b Binary files /dev/null and b/public/images/cards/1.jpg differ diff --git a/public/images/cards/10.jpg b/public/images/cards/10.jpg new file mode 100644 index 0000000..f4ffb28 Binary files /dev/null and b/public/images/cards/10.jpg differ diff --git a/public/images/cards/11.jpg b/public/images/cards/11.jpg new file mode 100644 index 0000000..ed335d6 Binary files /dev/null and b/public/images/cards/11.jpg differ diff --git a/public/images/cards/12.jpg b/public/images/cards/12.jpg new file mode 100644 index 0000000..5b60412 Binary files /dev/null and b/public/images/cards/12.jpg differ diff --git a/public/images/cards/13.jpg b/public/images/cards/13.jpg new file mode 100644 index 0000000..dad7676 Binary files /dev/null and b/public/images/cards/13.jpg differ diff --git a/public/images/cards/14.jpg b/public/images/cards/14.jpg new file mode 100644 index 0000000..68e60b6 Binary files /dev/null and b/public/images/cards/14.jpg differ diff --git a/public/images/cards/15.jpg b/public/images/cards/15.jpg new file mode 100644 index 0000000..6b88784 Binary files /dev/null and b/public/images/cards/15.jpg differ diff --git a/public/images/cards/16.jpg b/public/images/cards/16.jpg new file mode 100644 index 0000000..bbf55d3 Binary files /dev/null and b/public/images/cards/16.jpg differ diff --git a/public/images/cards/17.jpg b/public/images/cards/17.jpg new file mode 100644 index 0000000..8c427f4 Binary files /dev/null and b/public/images/cards/17.jpg differ diff --git a/public/images/cards/18.jpg b/public/images/cards/18.jpg new file mode 100644 index 0000000..e770430 Binary files /dev/null and b/public/images/cards/18.jpg differ diff --git a/public/images/cards/19.jpg b/public/images/cards/19.jpg new file mode 100644 index 0000000..d0d0689 Binary files /dev/null and b/public/images/cards/19.jpg differ diff --git a/public/images/cards/2.jpg b/public/images/cards/2.jpg new file mode 100644 index 0000000..f4d79c6 Binary files /dev/null and b/public/images/cards/2.jpg differ diff --git a/public/images/cards/20.jpg b/public/images/cards/20.jpg new file mode 100644 index 0000000..7c9d015 Binary files /dev/null and b/public/images/cards/20.jpg differ diff --git a/public/images/cards/21.jpg b/public/images/cards/21.jpg new file mode 100644 index 0000000..c0faae4 Binary files /dev/null and b/public/images/cards/21.jpg differ diff --git a/public/images/cards/22.jpg b/public/images/cards/22.jpg new file mode 100644 index 0000000..30bd466 Binary files /dev/null and b/public/images/cards/22.jpg differ diff --git a/public/images/cards/23.jpg b/public/images/cards/23.jpg new file mode 100644 index 0000000..3cbf51c Binary files /dev/null and b/public/images/cards/23.jpg differ diff --git a/public/images/cards/24.jpg b/public/images/cards/24.jpg new file mode 100644 index 0000000..b43784d Binary files /dev/null and b/public/images/cards/24.jpg differ diff --git a/public/images/cards/25.jpg b/public/images/cards/25.jpg new file mode 100644 index 0000000..c66e982 Binary files /dev/null and b/public/images/cards/25.jpg differ diff --git a/public/images/cards/26.jpg b/public/images/cards/26.jpg new file mode 100644 index 0000000..acc0337 Binary files /dev/null and b/public/images/cards/26.jpg differ diff --git a/public/images/cards/27.jpg b/public/images/cards/27.jpg new file mode 100644 index 0000000..62ab5c7 Binary files /dev/null and b/public/images/cards/27.jpg differ diff --git a/public/images/cards/28.jpg b/public/images/cards/28.jpg new file mode 100644 index 0000000..2e6e400 Binary files /dev/null and b/public/images/cards/28.jpg differ diff --git a/public/images/cards/29.jpg b/public/images/cards/29.jpg new file mode 100644 index 0000000..d0cd286 Binary files /dev/null and b/public/images/cards/29.jpg differ diff --git a/public/images/cards/3.jpg b/public/images/cards/3.jpg new file mode 100644 index 0000000..834312a Binary files /dev/null and b/public/images/cards/3.jpg differ diff --git a/public/images/cards/30.jpg b/public/images/cards/30.jpg new file mode 100644 index 0000000..910c56c Binary files /dev/null and b/public/images/cards/30.jpg differ diff --git a/public/images/cards/31.jpg b/public/images/cards/31.jpg new file mode 100644 index 0000000..45f8d09 Binary files /dev/null and b/public/images/cards/31.jpg differ diff --git a/public/images/cards/32.jpg b/public/images/cards/32.jpg new file mode 100644 index 0000000..5912b41 Binary files /dev/null and b/public/images/cards/32.jpg differ diff --git a/public/images/cards/33.jpg b/public/images/cards/33.jpg new file mode 100644 index 0000000..a274ff4 Binary files /dev/null and b/public/images/cards/33.jpg differ diff --git a/public/images/cards/34.jpg b/public/images/cards/34.jpg new file mode 100644 index 0000000..87f0905 Binary files /dev/null and b/public/images/cards/34.jpg differ diff --git a/public/images/cards/35.jpg b/public/images/cards/35.jpg new file mode 100644 index 0000000..653036d Binary files /dev/null and b/public/images/cards/35.jpg differ diff --git a/public/images/cards/36.jpg b/public/images/cards/36.jpg new file mode 100644 index 0000000..a15e74f Binary files /dev/null and b/public/images/cards/36.jpg differ diff --git a/public/images/cards/37.jpg b/public/images/cards/37.jpg new file mode 100644 index 0000000..cfcd85d Binary files /dev/null and b/public/images/cards/37.jpg differ diff --git a/public/images/cards/38.jpg b/public/images/cards/38.jpg new file mode 100644 index 0000000..734f316 Binary files /dev/null and b/public/images/cards/38.jpg differ diff --git a/public/images/cards/39.jpg b/public/images/cards/39.jpg new file mode 100644 index 0000000..d77d2ea Binary files /dev/null and b/public/images/cards/39.jpg differ diff --git a/public/images/cards/4.jpg b/public/images/cards/4.jpg new file mode 100644 index 0000000..dcf4567 Binary files /dev/null and b/public/images/cards/4.jpg differ diff --git a/public/images/cards/40.jpg b/public/images/cards/40.jpg new file mode 100644 index 0000000..44846bf Binary files /dev/null and b/public/images/cards/40.jpg differ diff --git a/public/images/cards/41.jpg b/public/images/cards/41.jpg new file mode 100644 index 0000000..f0b7fb1 Binary files /dev/null and b/public/images/cards/41.jpg differ diff --git a/public/images/cards/42.jpg b/public/images/cards/42.jpg new file mode 100644 index 0000000..73f8028 Binary files /dev/null and b/public/images/cards/42.jpg differ diff --git a/public/images/cards/43.jpg b/public/images/cards/43.jpg new file mode 100644 index 0000000..e91efa1 Binary files /dev/null and b/public/images/cards/43.jpg differ diff --git a/public/images/cards/44.jpg b/public/images/cards/44.jpg new file mode 100644 index 0000000..8e2d4f4 Binary files /dev/null and b/public/images/cards/44.jpg differ diff --git a/public/images/cards/45.jpg b/public/images/cards/45.jpg new file mode 100644 index 0000000..12d29ae Binary files /dev/null and b/public/images/cards/45.jpg differ diff --git a/public/images/cards/46.jpg b/public/images/cards/46.jpg new file mode 100644 index 0000000..45d9585 Binary files /dev/null and b/public/images/cards/46.jpg differ diff --git a/public/images/cards/47.jpg b/public/images/cards/47.jpg new file mode 100644 index 0000000..f9d4917 Binary files /dev/null and b/public/images/cards/47.jpg differ diff --git a/public/images/cards/48.jpg b/public/images/cards/48.jpg new file mode 100644 index 0000000..ed9f7e6 Binary files /dev/null and b/public/images/cards/48.jpg differ diff --git a/public/images/cards/49.jpg b/public/images/cards/49.jpg new file mode 100644 index 0000000..9b80c2a Binary files /dev/null and b/public/images/cards/49.jpg differ diff --git a/public/images/cards/5.jpg b/public/images/cards/5.jpg new file mode 100644 index 0000000..e62940a Binary files /dev/null and b/public/images/cards/5.jpg differ diff --git a/public/images/cards/50.jpg b/public/images/cards/50.jpg new file mode 100644 index 0000000..84d6312 Binary files /dev/null and b/public/images/cards/50.jpg differ diff --git a/public/images/cards/51.jpg b/public/images/cards/51.jpg new file mode 100644 index 0000000..d4b5d04 Binary files /dev/null and b/public/images/cards/51.jpg differ diff --git a/public/images/cards/52.jpg b/public/images/cards/52.jpg new file mode 100644 index 0000000..fb6ea1a Binary files /dev/null and b/public/images/cards/52.jpg differ diff --git a/public/images/cards/53.jpg b/public/images/cards/53.jpg new file mode 100644 index 0000000..ca36bf0 Binary files /dev/null and b/public/images/cards/53.jpg differ diff --git a/public/images/cards/54.jpg b/public/images/cards/54.jpg new file mode 100644 index 0000000..8de3d59 Binary files /dev/null and b/public/images/cards/54.jpg differ diff --git a/public/images/cards/55.jpg b/public/images/cards/55.jpg new file mode 100644 index 0000000..babc829 Binary files /dev/null and b/public/images/cards/55.jpg differ diff --git a/public/images/cards/56.jpg b/public/images/cards/56.jpg new file mode 100644 index 0000000..1dd633b Binary files /dev/null and b/public/images/cards/56.jpg differ diff --git a/public/images/cards/57.jpg b/public/images/cards/57.jpg new file mode 100644 index 0000000..6f03c70 Binary files /dev/null and b/public/images/cards/57.jpg differ diff --git a/public/images/cards/58.jpg b/public/images/cards/58.jpg new file mode 100644 index 0000000..f02fa8e Binary files /dev/null and b/public/images/cards/58.jpg differ diff --git a/public/images/cards/59.jpg b/public/images/cards/59.jpg new file mode 100644 index 0000000..a71a0c7 Binary files /dev/null and b/public/images/cards/59.jpg differ diff --git a/public/images/cards/6.jpg b/public/images/cards/6.jpg new file mode 100644 index 0000000..3a4ba21 Binary files /dev/null and b/public/images/cards/6.jpg differ diff --git a/public/images/cards/60.jpg b/public/images/cards/60.jpg new file mode 100644 index 0000000..fc4541e Binary files /dev/null and b/public/images/cards/60.jpg differ diff --git a/public/images/cards/61.jpg b/public/images/cards/61.jpg new file mode 100644 index 0000000..28326f2 Binary files /dev/null and b/public/images/cards/61.jpg differ diff --git a/public/images/cards/62.jpg b/public/images/cards/62.jpg new file mode 100644 index 0000000..09e8624 Binary files /dev/null and b/public/images/cards/62.jpg differ diff --git a/public/images/cards/63.jpg b/public/images/cards/63.jpg new file mode 100644 index 0000000..e47587a Binary files /dev/null and b/public/images/cards/63.jpg differ diff --git a/public/images/cards/64.jpg b/public/images/cards/64.jpg new file mode 100644 index 0000000..60e6572 Binary files /dev/null and b/public/images/cards/64.jpg differ diff --git a/public/images/cards/65.jpg b/public/images/cards/65.jpg new file mode 100644 index 0000000..3d4bc91 Binary files /dev/null and b/public/images/cards/65.jpg differ diff --git a/public/images/cards/66.jpg b/public/images/cards/66.jpg new file mode 100644 index 0000000..60092ee Binary files /dev/null and b/public/images/cards/66.jpg differ diff --git a/public/images/cards/67.jpg b/public/images/cards/67.jpg new file mode 100644 index 0000000..7bd6c1b Binary files /dev/null and b/public/images/cards/67.jpg differ diff --git a/public/images/cards/68.jpg b/public/images/cards/68.jpg new file mode 100644 index 0000000..cfd9561 Binary files /dev/null and b/public/images/cards/68.jpg differ diff --git a/public/images/cards/69.jpg b/public/images/cards/69.jpg new file mode 100644 index 0000000..6cbc269 Binary files /dev/null and b/public/images/cards/69.jpg differ diff --git a/public/images/cards/7.jpg b/public/images/cards/7.jpg new file mode 100644 index 0000000..4b187a7 Binary files /dev/null and b/public/images/cards/7.jpg differ diff --git a/public/images/cards/70.jpg b/public/images/cards/70.jpg new file mode 100644 index 0000000..5e72cf2 Binary files /dev/null and b/public/images/cards/70.jpg differ diff --git a/public/images/cards/71.jpg b/public/images/cards/71.jpg new file mode 100644 index 0000000..7e56642 Binary files /dev/null and b/public/images/cards/71.jpg differ diff --git a/public/images/cards/72.jpg b/public/images/cards/72.jpg new file mode 100644 index 0000000..8cf2a8f Binary files /dev/null and b/public/images/cards/72.jpg differ diff --git a/public/images/cards/73.jpg b/public/images/cards/73.jpg new file mode 100644 index 0000000..83746d7 Binary files /dev/null and b/public/images/cards/73.jpg differ diff --git a/public/images/cards/74.jpg b/public/images/cards/74.jpg new file mode 100644 index 0000000..cdfe678 Binary files /dev/null and b/public/images/cards/74.jpg differ diff --git a/public/images/cards/75.jpg b/public/images/cards/75.jpg new file mode 100644 index 0000000..7ce9bc9 Binary files /dev/null and b/public/images/cards/75.jpg differ diff --git a/public/images/cards/76.jpg b/public/images/cards/76.jpg new file mode 100644 index 0000000..8a1db13 Binary files /dev/null and b/public/images/cards/76.jpg differ diff --git a/public/images/cards/77.jpg b/public/images/cards/77.jpg new file mode 100644 index 0000000..6c8f195 Binary files /dev/null and b/public/images/cards/77.jpg differ diff --git a/public/images/cards/8.jpg b/public/images/cards/8.jpg new file mode 100644 index 0000000..6479ac8 Binary files /dev/null and b/public/images/cards/8.jpg differ diff --git a/public/images/cards/9.jpg b/public/images/cards/9.jpg new file mode 100644 index 0000000..0f01a59 Binary files /dev/null and b/public/images/cards/9.jpg differ diff --git a/public/images/hand.png b/public/images/hand.png new file mode 100644 index 0000000..61da0d2 Binary files /dev/null and b/public/images/hand.png differ diff --git a/public/images/horoscope.png b/public/images/horoscope.png new file mode 100644 index 0000000..2580166 Binary files /dev/null and b/public/images/horoscope.png differ diff --git a/public/images/landing/clouds.png b/public/images/landing/clouds.png new file mode 100644 index 0000000..71e5144 Binary files /dev/null and b/public/images/landing/clouds.png differ diff --git a/public/images/landing/hero-bg.webp b/public/images/landing/hero-bg.webp new file mode 100644 index 0000000..3e1ee83 Binary files /dev/null and b/public/images/landing/hero-bg.webp differ diff --git a/public/images/libra-card.png b/public/images/libra-card.png deleted file mode 100644 index f50cc83..0000000 Binary files a/public/images/libra-card.png and /dev/null differ diff --git a/public/images/moon-card.png b/public/images/moon-card.png new file mode 100644 index 0000000..f1f43ca Binary files /dev/null and b/public/images/moon-card.png differ diff --git a/public/images/star-card.png b/public/images/star-card.png new file mode 100644 index 0000000..28174fe Binary files /dev/null and b/public/images/star-card.png differ diff --git a/public/images/sun-card.png b/public/images/sun-card.png new file mode 100644 index 0000000..a2c714a Binary files /dev/null and b/public/images/sun-card.png differ diff --git a/public/images/tarot-game/bord.png b/public/images/tarot-game/bord.png index 7da1d32..10000fc 100644 Binary files a/public/images/tarot-game/bord.png and b/public/images/tarot-game/bord.png differ diff --git a/public/images/tarot-game/oracle-needs-time.png b/public/images/tarot-game/oracle-needs-time.png new file mode 100644 index 0000000..0bd0880 Binary files /dev/null and b/public/images/tarot-game/oracle-needs-time.png differ diff --git a/public/images/tarot-game/shuffle-deck.png b/public/images/tarot-game/shuffle-deck.png new file mode 100644 index 0000000..b01e325 Binary files /dev/null and b/public/images/tarot-game/shuffle-deck.png differ diff --git a/public/images/tarot-game/shutdown.png b/public/images/tarot-game/shutdown.png new file mode 100644 index 0000000..b9d5704 Binary files /dev/null and b/public/images/tarot-game/shutdown.png differ diff --git a/public/images/tarot-game/thanks-oracle.png b/public/images/tarot-game/thanks-oracle.png new file mode 100644 index 0000000..1278566 Binary files /dev/null and b/public/images/tarot-game/thanks-oracle.png differ diff --git a/public/images/textures/light-yellow.png b/public/images/textures/light-yellow.png new file mode 100644 index 0000000..867f927 Binary files /dev/null and b/public/images/textures/light-yellow.png differ diff --git a/public/images/textures/sand.png b/public/images/textures/sand.png new file mode 100644 index 0000000..81d07e2 Binary files /dev/null and b/public/images/textures/sand.png differ diff --git a/public/images/textures/sand.webp b/public/images/textures/sand.webp new file mode 100644 index 0000000..9382a4f Binary files /dev/null and b/public/images/textures/sand.webp differ diff --git a/public/vite.svg b/public/vite.svg deleted file mode 100644 index e7b8dfb..0000000 --- a/public/vite.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/App.tsx b/src/app.tsx similarity index 56% rename from src/App.tsx rename to src/app.tsx index 46daa90..5cf4ff3 100644 --- a/src/App.tsx +++ b/src/app.tsx @@ -1,26 +1,24 @@ import { Suspense } from 'react'; import { ToastContainer } from 'react-toastify'; -import { Loader } from '@/components/common/Loader'; -import { QueryProvider } from '@/providers/query-provider'; -import { RouterProvider } from '@/providers/router-provider'; -import { SolanaProvider } from '@/providers/solana-provider'; +import { FullPageLoader } from './components/common/loaders'; +import { QueryProvider } from './providers/query-provider'; +import { RouterProvider } from './providers/router-provider'; +import { SolanaProvider } from './providers/solana-provider'; import '@fontsource/bona-nova-sc/400.css'; import '@fontsource/bona-nova-sc/700.css'; import '@fontsource/poppins/400.css'; -function App() { +export const App = () => { return ( - }> + }> ); -} - -export default App; +}; diff --git a/src/assets/react.svg b/src/assets/react.svg deleted file mode 100644 index 6c87de9..0000000 --- a/src/assets/react.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/components/common/About/index.tsx b/src/components/common/About/index.tsx deleted file mode 100644 index b7453b9..0000000 --- a/src/components/common/About/index.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion'; - -export const AboutSection = () => { - return ( -
-
-
-

About Tarot

-

- Lorem ipsum dolor sit amet consectetur. Posuere auctor vivamus sed leo non pellentesque. Massa sed eget est - porta facilisis rhoncus mauris. Pellentesque malesuada morbi volutpat dictum. Sollicitudin suspendisse - aliquam imperdiet rutrum interdum. Dignissim in diam vestibulum sodales nibh nec scelerisque id. Sit - facilisi vestibulum etiam nunc a. Ullamcorper amet sed etiam ac adipiscing mauris cursus blandit vitae. - Lacus eget gravida morbi condimentum lobortis a. Blandit gravida dictum mollis scelerisque feugiat dis. -

-
- - tarot1 -
- -
-

Rules

- -
- tarot1 - tarot2 - tarot3 -
- - - {new Array(6).fill(0).map((_, i) => ( - - Is it accessible? - Yes. It adheres to the WAI-ARIA design pattern. - - ))} - -
-
- ); -}; diff --git a/src/components/common/Footer/index.tsx b/src/components/common/Footer/index.tsx deleted file mode 100644 index 9b7f4f5..0000000 --- a/src/components/common/Footer/index.tsx +++ /dev/null @@ -1,10 +0,0 @@ -export const Footer = () => { - return ( -
-

- @{new Date().getFullYear()}. All rights reserved. - Powered by TarotSol AI -

-
- ); -}; diff --git a/src/components/common/Header/connect-wallet-button.tsx b/src/components/common/Header/connect-wallet-button.tsx deleted file mode 100644 index 31b4879..0000000 --- a/src/components/common/Header/connect-wallet-button.tsx +++ /dev/null @@ -1,143 +0,0 @@ -import { WalletReadyState } from '@solana/wallet-adapter-base'; -import { useWallet } from '@solana/wallet-adapter-react'; -import { PhantomWalletName, SolflareWalletName } from '@solana/wallet-adapter-wallets'; -import { useCallback, useEffect, useRef, useState } from 'react'; - -import { SvgComponent } from './progress-bar'; - -import { Button } from '@/components/ui/button'; -import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog'; -import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; -import { shortenAddress } from '@/lib/utils'; -import { useWalletModalStore } from '@/store/wallet-modal'; - -export const ConnectWalletButton = () => { - const { isOpen, setIsOpen } = useWalletModalStore(); - - const { select, wallets, publicKey, disconnect, connecting, wallet } = useWallet(); - - const filteredWallets = wallets.filter( - (wallet) => wallet.adapter.name == SolflareWalletName || wallet.adapter.name == PhantomWalletName, - ); - - const onOpenChange = useCallback( - (open: boolean) => { - setIsOpen(open); - }, - [setIsOpen], - ); - - const buttonRef = useRef(null); - - const [popoverWidth, setPopoverWidth] = useState(); - - const handleDisconnect = async () => { - await disconnect(); - setIsOpen(false); - }; - - useEffect(() => { - if (buttonRef.current?.clientWidth) { - setPopoverWidth(buttonRef.current.clientWidth); - } - }, [buttonRef.current?.clientWidth]); - - useEffect(() => { - if (publicKey) { - setIsOpen(false); - } - }, [publicKey]); - - if (publicKey) { - return ( - - - - - - - - - ); - } - - return ( - - - - - - {!!wallet && connecting ? ( -
- {wallet.adapter.name} -
-
Awaiting Connect Confirmation
- -
-
- ) : ( - <> - - -

Connect Wallet

-
-
-
- {filteredWallets.map((wallet) => ( - - ))} -
- - )} -
-
- ); -}; diff --git a/src/components/common/Loader/index.tsx b/src/components/common/Loader/index.tsx deleted file mode 100644 index 8d650c2..0000000 --- a/src/components/common/Loader/index.tsx +++ /dev/null @@ -1,7 +0,0 @@ -export const Loader = () => { - return ( -
-

Loading...

-
- ); -}; diff --git a/src/components/common/base-tooltip/index.tsx b/src/components/common/base-tooltip/index.tsx new file mode 100644 index 0000000..b1ac315 --- /dev/null +++ b/src/components/common/base-tooltip/index.tsx @@ -0,0 +1,67 @@ +/* eslint-disable @typescript-eslint/no-unused-expressions */ +import { ReactNode, useState } from 'react'; + +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'; +import { cn } from '@/lib/utils'; + +type BaseTooltipProps = { + content: ReactNode; + children: ReactNode; + className?: string; + contentClassName?: string; + as?: 'div' | 'span'; + ignoreOnKeyDown?: boolean; + forceOpen?: boolean; +}; + +export const BaseTooltip = ({ + children, + content, + className, + contentClassName, + as, + ignoreOnKeyDown, + forceOpen, +}: BaseTooltipProps) => { + const [open, setOpen] = useState(false); + + const Slot = as ?? 'div'; + + return ( + + + + { + setOpen(!open); + }} + onMouseEnter={() => { + setOpen(true); + }} + onMouseLeave={() => { + setOpen(false); + }} + onTouchStart={() => { + setOpen(!open); + }} + onKeyDown={(e) => { + if (ignoreOnKeyDown) { + return; + } + + e.preventDefault(); + e.key === 'Enter' && setOpen(!open); + }} + > + {children} + + + + {content} + + + + ); +}; diff --git a/src/components/common/buttons/admin.tsx b/src/components/common/buttons/admin.tsx new file mode 100644 index 0000000..ddfbe83 --- /dev/null +++ b/src/components/common/buttons/admin.tsx @@ -0,0 +1,17 @@ +import { Link } from 'react-router'; + +import { Button } from '@/components/ui/button'; +import { routes } from '@/constants/router'; + +export const AdminBtn = () => { + return ( + + + + ); +}; diff --git a/src/components/common/buttons/go-to-twitter.tsx b/src/components/common/buttons/go-to-twitter.tsx new file mode 100644 index 0000000..ab6a01e --- /dev/null +++ b/src/components/common/buttons/go-to-twitter.tsx @@ -0,0 +1,12 @@ +import { Button } from '@/components/ui/button'; +import { env } from '@/env'; + +export const GoToTwitterBtn = () => { + return ( + + + + ); +}; diff --git a/src/components/common/buttons/predict-future.tsx b/src/components/common/buttons/predict-future.tsx new file mode 100644 index 0000000..8e5a17f --- /dev/null +++ b/src/components/common/buttons/predict-future.tsx @@ -0,0 +1,17 @@ +import { Link } from 'react-router'; + +import { Button } from '@/components/ui/button'; +import { routes } from '@/constants/router'; + +export const PredictFutureBtn = () => { + return ( + + + + ); +}; diff --git a/src/components/common/currency-select/index.tsx b/src/components/common/currency-select/index.tsx new file mode 100644 index 0000000..236a5d8 --- /dev/null +++ b/src/components/common/currency-select/index.tsx @@ -0,0 +1,29 @@ +import { Select, SelectTrigger, SelectItem, SelectValue, SelectContent } from '@/components/ui/select.tsx'; +import { currencies, Currencies } from '@/constants/addresses'; + +type CurrencySelect = { + value: string; + onValueChange: (value: Currencies) => void; +}; + +export const CurrencySelect = ({ value, onValueChange }: CurrencySelect) => { + return ( + + ); +}; diff --git a/src/components/common/footer/index.tsx b/src/components/common/footer/index.tsx new file mode 100644 index 0000000..5845a01 --- /dev/null +++ b/src/components/common/footer/index.tsx @@ -0,0 +1,10 @@ +export const Footer = () => { + return ( +
+

+ @{new Date().getFullYear()}. All rights reserved. + Powered by TarotSol AI +

+
+ ); +}; diff --git a/src/components/common/header/connect-wallet-button.tsx b/src/components/common/header/connect-wallet-button.tsx new file mode 100644 index 0000000..7bf73af --- /dev/null +++ b/src/components/common/header/connect-wallet-button.tsx @@ -0,0 +1,168 @@ +import { WalletReadyState } from '@solana/wallet-adapter-base'; +import { useWallet } from '@solana/wallet-adapter-react'; +import { PhantomWalletName, SolflareWalletName } from '@solana/wallet-adapter-wallets'; +import { Dot } from 'lucide-react'; +import { useCallback, useEffect, useRef, useState } from 'react'; + +import { BaseErrorModal } from './modals/base-error'; +import { CanceledModal } from './modals/cancelled'; +import { InsufficientFundsModal } from './modals/insufficient-funds'; +import { SuccessfulModal } from './modals/successful'; +import { SvgComponent } from './progress-bar'; + +import { Button } from '@/components/ui/button'; +import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog'; +import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; +import { shortenAddress } from '@/lib/utils'; +import { Status, useStatusModalStore } from '@/store/status-modal'; +import { useWalletModalStore } from '@/store/wallet-modal'; + +export const ConnectWalletButton = () => { + const { isOpen, setIsOpen } = useWalletModalStore(); + const { status } = useStatusModalStore(); + + const { select, wallets, publicKey, disconnect, connecting, wallet } = useWallet(); + + const filteredWallets = wallets.filter( + (wallet) => wallet.adapter.name == SolflareWalletName || wallet.adapter.name == PhantomWalletName, + ); + + const onOpenChange = useCallback( + (open: boolean) => { + setIsOpen(open); + }, + [setIsOpen], + ); + + const buttonRef = useRef(null); + + const [popoverWidth, setPopoverWidth] = useState(); + + const handleDisconnect = async () => { + await disconnect(); + setIsOpen(false); + }; + + useEffect(() => { + if (buttonRef.current?.clientWidth) { + setPopoverWidth(buttonRef.current.clientWidth); + } + }, [buttonRef.current?.clientWidth]); + + useEffect(() => { + if (publicKey) { + setIsOpen(false); + } + }, [publicKey]); + + if (publicKey) { + return ( + <> + + + + + + + + + + + + + + {status === Status.Success && } + {status === Status.Failed && } + {status === Status.InsufficientFunds && } + {status === Status.Canceled && } + + + + ); + } + + return ( + + + + + + + {!!wallet && connecting ? ( +
+ {wallet.adapter.name} + +
+
Awaiting Connect Confirmation
+ +
+
+ ) : ( + <> + + +

+ Connect Wallet +

+
+
+ +
+ {filteredWallets.map((wallet) => ( + + ))} +
+ + )} +
+
+ ); +}; diff --git a/src/components/common/header/index.tsx b/src/components/common/header/index.tsx new file mode 100644 index 0000000..8750ab9 --- /dev/null +++ b/src/components/common/header/index.tsx @@ -0,0 +1,59 @@ +import { Menu, X } from 'lucide-react'; +import { useState } from 'react'; +import { Link } from 'react-router'; + +import { NavMenu } from './nav-menu'; + +import { Button } from '@/components/ui/button'; +import { routes } from '@/constants/router'; +import { useBreakpoint } from '@/hooks/use-breakpoint'; +import { cn } from '@/lib/utils'; + +export const Header = () => { + const isMd = useBreakpoint('md'); + const [isMenuOpen, setIsMenuOpen] = useState(false); + + const handleModalOpen = () => { + document.body.classList.toggle('overflow-y-hidden'); + setIsMenuOpen((prev) => !prev); + }; + + return ( +
+
+ { + if (isMenuOpen) { + handleModalOpen(); + } + }} + > + Tarotsol AI + + + +
+ + {!isMd && ( +
+ +
+ )} +
+ ); +}; diff --git a/src/components/common/header/modals/base-error.tsx b/src/components/common/header/modals/base-error.tsx new file mode 100644 index 0000000..079e3e9 --- /dev/null +++ b/src/components/common/header/modals/base-error.tsx @@ -0,0 +1,28 @@ +import { Button } from '@/components/ui/button'; +import { useStatusModalStore } from '@/store/status-modal'; + +export const BaseErrorModal = () => { + const { setStatus } = useStatusModalStore(); + + return ( +
+ failed + +

Oracle Response Failed

+

+ The Oracle couldn’t provide an answer at this time.
Please try again. +

+ + +
+ ); +}; diff --git a/src/components/common/header/modals/cancelled.tsx b/src/components/common/header/modals/cancelled.tsx new file mode 100644 index 0000000..34d8f75 --- /dev/null +++ b/src/components/common/header/modals/cancelled.tsx @@ -0,0 +1,28 @@ +import { Button } from '@/components/ui/button'; +import { useStatusModalStore } from '@/store/status-modal'; + +export const CanceledModal = () => { + const { setStatus } = useStatusModalStore(); + + return ( +
+ failed + +

Transaction Cancelled

+

+ Your transaction has been cancelled. To receive a response from the Oracle, please complete the transaction. +

+ + +
+ ); +}; diff --git a/src/components/common/header/modals/insufficient-funds.tsx b/src/components/common/header/modals/insufficient-funds.tsx new file mode 100644 index 0000000..8cd7d03 --- /dev/null +++ b/src/components/common/header/modals/insufficient-funds.tsx @@ -0,0 +1,29 @@ +import { Button } from '@/components/ui/button'; +import { useStatusModalStore } from '@/store/status-modal'; + +export const InsufficientFundsModal = () => { + const { setStatus } = useStatusModalStore(); + + return ( +
+ failed + +

Insufficient Funds

+

+ Unfortunately, you don’t have enough funds to complete the payment. Please top up your wallet or choose another + payment method. +

+ + +
+ ); +}; diff --git a/src/components/common/header/modals/successful.tsx b/src/components/common/header/modals/successful.tsx new file mode 100644 index 0000000..1adf3da --- /dev/null +++ b/src/components/common/header/modals/successful.tsx @@ -0,0 +1,25 @@ +import { Button } from '@/components/ui/button'; +import { useStatusModalStore } from '@/store/status-modal'; + +export const SuccessfulModal = () => { + const { setStatus } = useStatusModalStore(); + + return ( +
+ success + +

Payment Successful

+ + +
+ ); +}; diff --git a/src/components/common/header/nav-menu.tsx b/src/components/common/header/nav-menu.tsx new file mode 100644 index 0000000..7d7d734 --- /dev/null +++ b/src/components/common/header/nav-menu.tsx @@ -0,0 +1,21 @@ +import { ConnectWalletButton } from './connect-wallet-button'; + +import { env } from '@/env'; +import { cn } from '@/lib/utils'; +import { BaseComponentProps } from '@/types'; + +export const NavMenu = ({ className }: BaseComponentProps) => { + return ( + + ); +}; diff --git a/src/components/common/Header/progress-bar.tsx b/src/components/common/header/progress-bar.tsx similarity index 100% rename from src/components/common/Header/progress-bar.tsx rename to src/components/common/header/progress-bar.tsx diff --git a/src/layouts/default-layout.tsx b/src/components/common/layouts/default-layout.tsx similarity index 100% rename from src/layouts/default-layout.tsx rename to src/components/common/layouts/default-layout.tsx diff --git a/src/components/common/layouts/main-layout.tsx b/src/components/common/layouts/main-layout.tsx new file mode 100644 index 0000000..6ff66ae --- /dev/null +++ b/src/components/common/layouts/main-layout.tsx @@ -0,0 +1,12 @@ +import { Outlet } from 'react-router'; + +import { Footer } from '@/components/common/footer'; + +export function MainLayout() { + return ( +
+ +
+
+ ); +} diff --git a/src/components/common/loaders/index.tsx b/src/components/common/loaders/index.tsx new file mode 100644 index 0000000..19f2d75 --- /dev/null +++ b/src/components/common/loaders/index.tsx @@ -0,0 +1,21 @@ +const BigSpinner = () => { + return ( +
+
+
+ ); +}; + +export const FullPageLoader = () => { + return ( +
+ +
+ ); +}; diff --git a/src/components/common/section/index.tsx b/src/components/common/section/index.tsx new file mode 100644 index 0000000..12d957d --- /dev/null +++ b/src/components/common/section/index.tsx @@ -0,0 +1,269 @@ +import { useLocation } from 'react-router'; + +import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion'; +import { routes } from '@/constants/router'; + +const routesWhereAvoidAbout: string[] = [routes.GAME]; + +const INSTRUCTIONS = [ + { + subtitle: 'Connect your wallet:', + description: 'Use a Solana-compatible wallet, Phantom or Solflare, to connect to the platform', + }, + { + subtitle: 'Enter your question:', + description: 'Type in the question you want guidance on', + }, + { + subtitle: 'Confirm and Sign:', + description: 'Review your details, confirm the transaction, and sign it in your wallet', + }, + { + subtitle: 'Wait for results:', + description: ( + <> + Once the payment is complete, the page will load your results
+

+ IMPORTANT: DO NOT refresh the page if you’ve made a payment but haven’t + received the result yet. Wait until the process is complete +

+ + ), + }, + { + subtitle: 'View your results:', + description: 'Your personalized Tarot reading will appear on the page', + }, + { + subtitle: 'Ask another question:', + description: ( +

+ To start a new session, click " + Make a New Forecast" or refresh the page +

+ ), + }, +]; + +const rules = [ + { + name: 'Avoid asking the same question repeatedly', + description: + 'Tarot cards "sense" when a question is repeated too often. If you ask the same question more than four or five times in a day, the cards may start providing distorted answers, creating confusion. Some Tarot readers believe that the cards might even begin to "joke" or deliberately mislead. Limit yourself to one question on a topic every few days or weeks to ensure the answers remain clear and accurate. Be patient and trust the first result.\n', + }, + { + name: 'Formulate questions properly', + description: + 'The way you phrase your question is critical to successful readings. Avoid overly specific or closed questions, for example:\n' + + 'Incorrect: “When will I die?”\n' + + 'Correct: “What changes are ahead in my life?”\n' + + '\n' + + '\n' + + 'Incorrect: “How many points will I score on my exam?”\n' + + 'Correct: “How can I prepare effectively to pass my exam?”\n' + + '\n' + + '\n' + + 'Incorrect: “When will the war end?”\n' + + 'Correct: “What developments might occur in the current situation soon?”\n' + + 'Cards respond better to open-ended questions focused on predictions or processes.\n', + }, + { + name: 'Ask one question at a time', + description: + 'Avoid double-barreled questions. For example:\n' + + 'Incorrect: “Does my boss admire me, and will I get a raise?”\n' + + 'Correct: First, ask: “Does my boss admire me?” Then: “Will I get a raise?”\n', + }, + { + name: 'Avoid questions containing "Or"', + description: + 'Tarot struggles to provide clear answers to questions with alternatives. Break them into separate inquiries:\n' + + 'Incorrect: “Does she like me or hate me?”\n' + + 'Correct: First, ask: “How does she feel about me?” Then: “Does she hate me?”\n', + }, + { + name: 'Avoid using “Should I”\n', + description: + 'The phrase “should I” makes the question too dependent on subjective interpretation. Reframe the question:\n' + + 'Incorrect: “Should I buy an apartment this month?”\n' + + 'Correct: “What will happen if I buy an apartment this month?”\n' + + 'This approach allows the cards to describe the potential outcomes of your decision.\n', + }, + { + name: 'The closer the timeframe, the more accurate the answer\n', + description: + 'Predictions for the near future (e.g., a day or a week) are more precise than for distant timelines. For instance:\n' + + 'A forecast for tomorrow will yield clearer, actionable advice.\n' + + 'A prediction for the second Monday of 2030 will be vague and uncertain.\n', + }, + { + name: 'Avoid reading for deceased people', + description: + 'Questions about the deceased are considered taboo in Tarot readings. If you have concerns about departed loved ones, it’s better to seek answers through other practices or methods. Tarot focuses on living, current energy.\n', + }, + { + name: 'Avoid reading for military personnel', + description: + 'Questions about military matters are complex and unpredictable. The cards may not provide accurate information or could be misleading. Such inquiries are believed to disrupt the energetic balance.\n', + }, + { + name: 'Account for reversed cards', + description: + 'When working with Tarot, remember that each card can appear in a reversed position. This completely changes its meaning or adds important nuances:\n' + + 'An upright card often indicates active actions or clear events.\n' + + 'A reversed card points to obstacles, hidden influences, or internal struggles.\n', + }, + { + name: 'Respect the Tarot reader and their time', + description: + 'Reading Tarot requires concentration and energy. Be polite, ask clear questions, and avoid trying to "test" the reader with tricky or skeptical inquiries. This creates a negative atmosphere and may influence the results.\n', + }, + { + name: 'Don’t expect absolute accuracy\n', + description: + 'Tarot is a tool for guidance and forecasting, not a definitive roadmap. The cards do not provide 100% accurate predictions but rather describe probabilities and trends that can change based on your actions.\n', + }, + { + name: 'Avoid readings when you are emotionally overwhelmed\n', + description: + 'Strong emotions like anger, fear, or despair can distort the reading. Try to calm yourself and approach the session with a clear mind for the most accurate insights.', + }, + { + name: 'Phrase questions neutrally without expecting a specific answer\n', + description: + 'Avoid leading the cards toward a particular response. For example:\n' + + 'Incorrect: "Why is he such a terrible person?"\n' + + 'Correct: "What are the prospects of our relationship?"\n' + + 'This allows for an unbiased and objective reading.\n', + }, + { + name: 'Consider the context of your question', + description: + 'If you want to understand how to improve a situation, ask open-ended questions instead of seeking simple yes/no answers:\n' + + 'Instead of "Will I get a job?" ask, "What do I need to do to find a job?"\n', + }, + { + name: 'Avoid questions about others’ health or lives', + description: + "Tarot is not a medical tool or a way to control someone else's life. Avoid asking questions like:\n" + + '"How much longer will I live?"\n' + + '"Will my neighbor get sick?"\n' + + 'For such concerns, it’s better to consult doctors or therapists.\n', + }, + { + name: 'The cards do not take responsibility for your decisions', + description: + 'Remember, you are responsible for your actions. Tarot provides guidance, but the final decisions are yours. Do not shift responsibility for your choices onto the cards or the reader.\n', + }, + { + name: 'Don’t confuse Tarot with magic or “love spells”\n', + description: + 'Tarot is a tool for analysis and predictions, not a way to manipulate others. If you want to resolve an issue, focus on yourself rather than trying to control other people.\n', + }, + { + name: 'Avoid asking out of idle curiosity', + description: + 'The cards respond better to serious and mindful questions. If you ask something just for fun or out of boredom, the answers may be vague or unhelpful.\n', + }, + { + name: 'Prepare in Advance', + description: + 'Before the session, think carefully about what you want to know. Prepare specific questions to make the reading more meaningful and productive.', + }, +]; + +export const AboutSection = () => { + const { pathname } = useLocation(); + + return ( +
+
+ {routesWhereAvoidAbout.includes(pathname) ? : } + + tarot1 +
+ +
+

Rules

+ +

+ By following these recommendations, you’ll be able to receive accurate and insightful answers from Tarot cards + while maintaining their sincerity and objectivity. +

+ +
+ tarot1 + tarot2 + tarot3 +
+ + + {rules.map((e, i) => ( + + {e.name} + +
{e.description}
+
+
+ ))} +
+
+
+ ); +}; + +const AboutBlock = () => ( +
+

About Tarot

+

+ The standard Tarot deck consists of 78 cards divided into two main categories: +

+
    +
  • Major Arcana (22 cards) — representing major life lessons, significant events, and profound questions.
  • +
    +
  • + Minor Arcana (56 cards) — reflecting everyday situations, emotions, and actions, divided into four suits: Wands, + Cups, Swords, and Pentacles. +
  • +
+ +

+ Each card has an upright and reversed meaning. A reversed card can dramatically change the interpretation or offer + additional nuances.{' '} +

+ +

+ TarotSol AI combines traditional Tarot reading techniques with artificial intelligence and blockchain to provide + personalized insights based on your questions. +

+ +

+ We blend the ancient art of numerology with modern AI and blockchain technologies to provide personalized Tarot + reading, using your unique transaction ID and wallet address to generate a one-of-a-kind numerological signature + that selects your cards, while our AI Oracle interprets them to provide clear and insightful guidance. +

+ +

+ The card selection process within TarotSol is not just random generation like in other products but carries a kind + of "fateful" significance. The transaction hash is assigned to you by the blockchain itself, as is your + wallet's public address — making the outcome entirely beyond anyone's influence. The blockchain weaves the + threads of fate. +

+
+); + +const HowToUseBlock = () => ( +
+

How to Use

+ + {INSTRUCTIONS.map((e, idx) => ( +

+ {e.subtitle} {e.description} +

+ ))} +
+); diff --git a/src/components/common/Svg/Solana.tsx b/src/components/common/svgs/solana.tsx similarity index 100% rename from src/components/common/Svg/Solana.tsx rename to src/components/common/svgs/solana.tsx diff --git a/src/components/common/tarot-line/index.tsx b/src/components/common/tarot-line/index.tsx new file mode 100644 index 0000000..56591c5 --- /dev/null +++ b/src/components/common/tarot-line/index.tsx @@ -0,0 +1,42 @@ +import { useBreakpoint } from '@/hooks/use-breakpoint'; +import { cn } from '@/lib/utils'; +import { BaseComponentProps } from '@/types'; + +export const TarotLine = ({ className, words }: BaseComponentProps<{ words: string[] }>) => { + const isMd = useBreakpoint('lg'); + const wordsArr = isMd ? words : words.slice(0, 2); + + return ( +
+
+
+ {wordsArr.map((word, index) => ( +
+

{word}

+ {index !== wordsArr.length - 1 && ( + + + + )} +
+ ))} +
+
+
+ ); +}; diff --git a/src/components/pages/game/game.tsx b/src/components/pages/game/game.tsx index 7ff8b0d..52f6264 100644 --- a/src/components/pages/game/game.tsx +++ b/src/components/pages/game/game.tsx @@ -1,87 +1,294 @@ import { zodResolver } from '@hookform/resolvers/zod'; import { useWallet } from '@solana/wallet-adapter-react'; -import { useEffect } from 'react'; +import { useEffect, useState } from 'react'; import { SubmitHandler, useForm } from 'react-hook-form'; - +import { toast } from 'react-toastify'; import { z } from 'zod'; +import { BaseTooltip } from '@/components/common/base-tooltip'; +import { CurrencySelect } from '@/components/common/currency-select'; +import { Button } from '@/components/ui/button.tsx'; +import { currencies, Currencies } from '@/constants/addresses'; +import useStatus from '@/hooks/api/use-status'; import useMakePrediction from '@/hooks/contracts/write/use-make-prediction'; -import Solana from '@/components/common/Svg/Solana.tsx'; +import useSend from '@/hooks/contracts/write/use-send'; +import { cn, showTxToast } from '@/lib/utils'; import { useWalletModalStore } from '@/store/wallet-modal.tsx'; const TarotRequestSchema = z.object({ question: z .string() - .min(3) - .max(1000) - .regex(/^[a-zA-Z0-9.,!? ]+$/, 'Only English letters and numbers are allowed') - .refine((value) => value.trim() !== '', { message: 'String cannot consist of only spaces' }), + .min(3, 'Min 3 symbols') + .max(1000, 'Max 1000 symbols') + // .regex(/^[a-zA-Z0-9.,!?-\s]+$/, 'Only English letters and numbers are allowed') + .refine((value) => value.trim() !== '', { + message: 'String cannot consist of only spaces', + }), }); +const DEFAULT_IMAGE = 'images/tarot-game/bord.png'; +const SHUFFLE_DECK = 'images/tarot-game/shuffle-deck.png'; +const ORACLE_NEEDS_TIME = 'images/tarot-game/oracle-needs-time.png'; +const THANKS_ORACLE = 'images/tarot-game/thanks-oracle.png'; +const SHUTDOWN = 'images/tarot-game/shutdown.png'; + +const LOADING_IMAGES = [SHUFFLE_DECK, ORACLE_NEEDS_TIME] as const; +const CARD_ANIMATIONS = [ + 'firstCardAppearance 1s linear forwards', + 'secondCardAppearance 2s linear forwards', + 'thirdCardAppearance 3s linear forwards', +] as const; + type TarotRequestSchemaType = z.infer; export const GameSection = () => { const { publicKey } = useWallet(); + const { setIsOpen } = useWalletModalStore(); const { mutateAsync: transfer, isSuccess, isPending, data: predictionAnswer } = useMakePrediction(); + const { mutateAsync: transferCurrency, isPending: isSolPending, isSuccess: isTipSuccess } = useSend(); + const { data: status } = useStatus(); + + const [selectedTip, setSelectedTip] = useState(0); + const [currentMainImage, setCurrentMainImage] = useState(DEFAULT_IMAGE); + const [currentPendingImage, setCurrentPendingImage] = useState(0); + const [isFadingOut, setIsFadingOut] = useState(false); + const [showTip, setShowTip] = useState(false); + const [isRetry, setRetry] = useState(false); + const [dontReload, setDontReload] = useState(false); + const [currencyName, setCurrencyName] = useState(Object.keys(currencies)[0] as Currencies); - const { register, handleSubmit, watch, setValue } = useForm({ + const { + register, + handleSubmit, + watch, + setValue, + formState: { errors }, + } = useForm({ resolver: zodResolver(TarotRequestSchema), }); const onSubmit: SubmitHandler = async (data, e) => { e?.preventDefault(); - console.log('SubmitHandler data', data); - await transfer(watch('question').trim()); + await transfer({ question: data.question.trim(), tokenName: currencyName }); + }; + + const handleTip = async () => { + if (!publicKey) { + toast.error('Connect wallet first'); + return; + } + + if (!selectedTip) { + toast.error('Select tip first'); + return; + } + + await showTxToast('Tipping the Oracle', async () => { + await transferCurrency({ amount: selectedTip, tokenName: currencyName }); + }); }; useEffect(() => { if (predictionAnswer) { - setValue('question', predictionAnswer + '\n' + watch('question')); + const timer = setTimeout(() => { + const formatted = predictionAnswer.answer.replaceAll('*', ''); + + setValue('question', formatted); + setShowTip(true); + setRetry(true); + }, 3200); + + return () => { + clearTimeout(timer); + }; } }, [isSuccess, predictionAnswer, setValue, watch]); + useEffect(() => { + if (isTipSuccess) { + setCurrentMainImage(THANKS_ORACLE); + + const timer = setTimeout(() => { + setCurrentMainImage(DEFAULT_IMAGE); + }, 5000); + + return () => { + clearTimeout(timer); + }; + } + }, [isTipSuccess]); + + useEffect(() => { + let interval: NodeJS.Timeout | null = null; + + if (isPending) { + interval = setInterval(() => { + setIsFadingOut(true); + + setTimeout(() => { + setCurrentPendingImage((prevIndex) => (prevIndex + 1) % LOADING_IMAGES.length); + setIsFadingOut(false); + }, 500); + }, 5000); + setCurrentMainImage(LOADING_IMAGES[currentPendingImage]); + } else { + setCurrentMainImage(DEFAULT_IMAGE); + } + + return () => { + if (interval) clearInterval(interval); + }; + }, [isPending, currentPendingImage]); + + useEffect(() => { + if (!showTip) { + return; + } + + const handler = (event: BeforeUnloadEvent) => { + event.preventDefault(); + }; + + if (dontReload) { + window.removeEventListener('beforeunload', handler); + return; + } + + window.addEventListener('beforeunload', handler); + + return () => { + window.removeEventListener('beforeunload', handler); + }; + }, [showTip, dontReload]); + return ( -
-
Your Future In One Bet
-
- bord +
+
Your Future In One Forecast
+ +
+
+ {predictionAnswer && currentMainImage === DEFAULT_IMAGE && ( +
+ {predictionAnswer.tarots.map((e, idx) => { + return ( + card + ); + })} +
+ )} + bord +
-
-
Type your question and ask the cards
- + +
+
Type your question and ask the cards
+ + +
-