├── .env.example
├── .eslintrc.cjs
├── .gitignore
├── README.md
├── index.html
├── package-lock.json
├── package.json
├── public
├── dashboard
│ └── hero.jpg
└── vite.svg
├── src
├── App.tsx
├── assets
│ └── svg
│ │ ├── Ellipse-usage.svg
│ │ ├── Ellipse.svg
│ │ ├── alram.svg
│ │ ├── apple.svg
│ │ ├── auth0.svg
│ │ ├── backspace.svg
│ │ ├── calendar.svg
│ │ ├── chevron-left.svg
│ │ ├── coffee.svg
│ │ ├── creditCard.svg
│ │ ├── dashboard.svg
│ │ ├── database.svg
│ │ ├── document-report.svg
│ │ ├── dotsHorizontal.svg
│ │ ├── emojiHappy.svg
│ │ ├── external-link.svg
│ │ ├── eye.svg
│ │ ├── google.svg
│ │ ├── graphql.svg
│ │ ├── key.svg
│ │ ├── lock.svg
│ │ ├── logo-no-background.svg
│ │ ├── logo.svg
│ │ ├── logs.svg
│ │ ├── microsoft.svg
│ │ ├── moon.svg
│ │ ├── office-building.svg
│ │ ├── paperAirplane.svg
│ │ ├── pencil.svg
│ │ ├── playground.svg
│ │ ├── progressbar.svg
│ │ ├── question.svg
│ │ ├── search.svg
│ │ ├── sidebar.svg
│ │ ├── subscription.svg
│ │ ├── template.svg
│ │ ├── tick.svg
│ │ ├── trash.svg
│ │ ├── user-circle.svg
│ │ ├── users.svg
│ │ └── visa.svg
├── hooks
│ └── index.ts
├── main.tsx
├── pages
│ ├── buttonSpinner
│ │ └── index.tsx
│ ├── playground
│ │ ├── index.module.scss
│ │ └── index.tsx
│ └── spinner
│ │ ├── index.module.scss
│ │ └── index.tsx
├── styles
│ ├── globalStyles.scss
│ ├── globalStyles.ts
│ └── resource.scss
├── utils
│ └── routerUtils.tsx
└── vite-env.d.ts
├── tsconfig.json
├── vercel.json
├── vite.config.ts
└── yarn.lock
/.env.example:
--------------------------------------------------------------------------------
1 | VITE_CHAINLIT_SERVER = http://localhost:8000/
2 | VITE_RPC_ENDPOINT = https://rpc.shyft.to/?api_key=xxx
3 | VITE_RPC_WEBSOCKET_ENDPOINT = wss://rpc.shyft.to?api_key=xxx
4 |
--------------------------------------------------------------------------------
/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: { browser: true, es2020: true },
4 | extends: [
5 | 'eslint:recommended',
6 | 'plugin:@typescript-eslint/recommended',
7 | 'plugin:react-hooks/recommended',
8 | ],
9 | ignorePatterns: ['dist', '.eslintrc.cjs'],
10 | parser: '@typescript-eslint/parser',
11 | plugins: ['react-refresh'],
12 | rules: {
13 | 'react-refresh/only-export-components': [
14 | 'warn',
15 | { allowConstantExport: true },
16 | ],
17 | },
18 | }
19 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 | .env
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | **Blockchain AI Agent**
2 | =====================================
3 |
4 | Onchain AI Agent! Cutting-edge solution is designed to leverage the power of artificial intelligence and blockchain technology, providing users with a comprehensive toolkit for market analysis, trading insights, and decision-making.
5 |
6 | ## System Overview
7 |
8 | ## Support
9 | This has backend repo more and that is private for now.
10 | For support and further inquiries, please connect here:
11 |
12 | [Telegram: 0xTan1319](https://t.me/shiny0103)
13 |
14 | [Twitter: 0xTan1319](https://x.com/0xTan1319)
15 |
16 | ### 1. Data Aggregation
17 |
18 | This core module focuses on collecting and structuring data through:
19 |
20 | - **Financial Market Data**: Access real-time and historical data from decentralized and centralized exchanges using APIs like CoinGecko, CoinMarketCap, Binance, and Kraken.
21 |
22 | - **Social Sentiment Data**: Gather insights from platforms such as X (formerly Twitter), Reddit, and Discord using sentiment analysis tools to track community trends.
23 |
24 | - **News Aggregation**: Consolidate relevant financial news through RSS feeds and APIs, using AI models to summarize key information for users.
25 |
26 | ### 2. Analytical Insights
27 |
28 | This module analyzes the collected data to provide actionable insights:
29 |
30 | - **Machine Learning and AI**: Use predictive analytics and Natural Language Processing for market forecasts and sentiment evaluations.
31 |
32 | - **Tailored Trading Strategies**: Develop unique trading signals by backtesting historical data to validate the strategies, employing various methods like momentum-based approaches.
33 |
34 | ---
35 |
36 | ## Features
37 |
38 | - **Onchain Data Support**: Direct access to on-chain data for accurate transaction analysis and insights.
39 | - **AI-Powered Trading Assistance**: On-demand AI recommendations and alerts for trading opportunities.
40 | - **Robust Security**: Implementing best practices in security to protect user data and transactions.
41 |
42 | ---
43 |
44 |
45 | ## MVP (Solana Token Buy/Sell)
46 | 
47 | 
48 | 
49 |
50 |
51 | ## Test with some questions
52 | ```
53 | Q: Find me all the details on token Billy from the list.
54 | ```
55 | ```
56 | Q: What is the price of Popcat?
57 | ```
58 | ```
59 | Q: Ok, so what is current volume of Popcat?
60 | ```
61 | ```
62 | Q: Ok so how many holders does Popcat have?
63 | ```
64 | ```
65 | Q: Is there more buying than selling of Popcat today?
66 | ```
67 | ```
68 | Q: What is the CA?
69 | ```
70 | ```
71 | Q: What is pair address?
72 | ```
73 | ```
74 | Q: Buy me 100 SOL of PopCat.
75 | ```
76 |
77 | ---
78 |
79 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
13 |
17 |
21 |
25 |
29 |
30 | Chat bot
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "chat_bot",
3 | "private": true,
4 | "version": "1.0.0",
5 | "scripts": {
6 | "dev": "vite",
7 | "build": "tsc && vite build",
8 | "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
9 | "preview": "vite preview"
10 | },
11 | "dependencies": {
12 | "@chainlit/react-client": "^0.2.0",
13 | "@metaplex-foundation/js": "^0.20.1",
14 | "@radix-ui/react-slot": "^1.0.2",
15 | "@raydium-io/raydium-sdk": "^1.3.1-beta.58",
16 | "@solana/wallet-adapter-base": "^0.9.23",
17 | "@solana/wallet-adapter-react": "^0.15.35",
18 | "@solana/wallet-adapter-react-ui": "^0.9.35",
19 | "@solana/web3.js": "^1.95.3",
20 | "@vitejs/plugin-react": "^4.3.2",
21 | "class-variance-authority": "^0.7.0",
22 | "clsx": "^2.0.0",
23 | "lucide-react": "^0.292.0",
24 | "react": "^18.2.0",
25 | "react-bootstrap": "^2.10.5",
26 | "react-dom": "^18.2.0",
27 | "react-hot-toast": "^2.4.1",
28 | "react-icons": "^5.3.0",
29 | "react-router-dom": "^6.26.2",
30 | "react-spinners": "^0.14.1",
31 | "recoil": "^0.7.7",
32 | "styled-components": "^6.1.13",
33 | "tailwind-merge": "^2.0.0",
34 | "tailwindcss-animate": "^1.0.7",
35 | "uuid": "^9.0.1",
36 | "vite-plugin-node-polyfills": "^0.22.0"
37 | },
38 | "devDependencies": {
39 | "@types/node": "^20.9.0",
40 | "@types/react": "^18.2.15",
41 | "@types/react-dom": "^18.2.7",
42 | "@types/uuid": "^9.0.7",
43 | "@typescript-eslint/eslint-plugin": "^6.0.0",
44 | "@typescript-eslint/parser": "^6.0.0",
45 | "@vitejs/plugin-react-swc": "^3.3.2",
46 | "autoprefixer": "^10.4.16",
47 | "eslint": "^8.45.0",
48 | "eslint-plugin-react-hooks": "^4.6.0",
49 | "eslint-plugin-react-refresh": "^0.4.3",
50 | "postcss": "^8.4.31",
51 | "sass": "^1.79.4",
52 | "tailwindcss": "^3.3.5",
53 | "typescript": "^5.0.2",
54 | "vite": "^4.4.5"
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/public/dashboard/hero.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/L9T-Development/solana-ai-agent/0ef63ed7de9f32ee730dc56296a5bef7c41f7be7/public/dashboard/hero.jpg
--------------------------------------------------------------------------------
/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/App.tsx:
--------------------------------------------------------------------------------
1 | import { GlobalStyles, darkTheme, lightTheme } from "@styles/globalStyles";
2 | import { AppRouter } from "@utils/routerUtils";
3 | import { useMemo, useState } from "react";
4 | import { BrowserRouter } from "react-router-dom";
5 | import { ThemeProvider } from "styled-components";
6 |
7 | // Web3 Integration Part
8 | import { WalletAdapterNetwork } from "@solana/wallet-adapter-base";
9 | import {
10 | ConnectionProvider,
11 | WalletProvider,
12 | } from "@solana/wallet-adapter-react";
13 | import { WalletModalProvider } from "@solana/wallet-adapter-react-ui";
14 | import "@solana/wallet-adapter-react-ui/styles.css";
15 | // End Web3 Integration Part
16 |
17 | function App() {
18 | const network = WalletAdapterNetwork.Mainnet;
19 | const walletLists = useMemo(
20 | () => [],
21 | [network]
22 | );
23 |
24 | const [theme] = useState("light");
25 |
26 | return (
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | );
40 | }
41 |
42 | export default App;
43 |
--------------------------------------------------------------------------------
/src/assets/svg/Ellipse-usage.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/svg/Ellipse.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/svg/alram.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/svg/apple.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/svg/auth0.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/svg/backspace.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/svg/calendar.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/svg/chevron-left.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/svg/coffee.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/svg/creditCard.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/svg/dashboard.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/svg/database.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/svg/document-report.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/svg/dotsHorizontal.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/svg/emojiHappy.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/svg/external-link.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/svg/eye.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/svg/google.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/svg/graphql.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/assets/svg/key.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/svg/lock.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/svg/logo-no-background.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/svg/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/assets/svg/logs.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/assets/svg/microsoft.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/assets/svg/moon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/assets/svg/office-building.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/assets/svg/paperAirplane.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/assets/svg/pencil.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/assets/svg/playground.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/assets/svg/progressbar.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/assets/svg/question.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/assets/svg/search.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/assets/svg/sidebar.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/assets/svg/subscription.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/assets/svg/template.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/src/assets/svg/tick.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/assets/svg/trash.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/assets/svg/user-circle.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/assets/svg/users.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/assets/svg/visa.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/src/hooks/index.ts:
--------------------------------------------------------------------------------
1 | import { WalletContextState } from '@solana/wallet-adapter-react';
2 | import {
3 | Connection,
4 | PublicKey,
5 | VersionedTransaction,
6 | } from '@solana/web3.js'
7 |
8 | // @ts-ignore
9 | import { Metaplex } from "@metaplex-foundation/js";
10 | import { TOKEN_PROGRAM_ID } from "@raydium-io/raydium-sdk";
11 | import { AccountLayout, getMint } from "@solana/spl-token";
12 |
13 | export const getBuyTxWithJupiter = async (wallet: WalletContextState, baseMint: PublicKey, amount: number, connection: Connection) => {
14 | try {
15 | const lamports = Math.floor(amount * 10 ** 9)
16 | const quoteResponse = await (
17 | await fetch(
18 | `https://quote-api.jup.ag/v6/quote?inputMint=So11111111111111111111111111111111111111112&outputMint=${baseMint.toBase58()}&amount=${lamports}&slippageBps=100`
19 | )
20 | ).json();
21 | // get serialized transactions for the swap
22 | const { swapTransaction } = await (
23 | await fetch("https://quote-api.jup.ag/v6/swap", {
24 | method: "POST",
25 | headers: {
26 | "Content-Type": "application/json",
27 | },
28 | body: JSON.stringify({
29 | quoteResponse,
30 | userPublicKey: wallet.publicKey!.toString(),
31 | wrapAndUnwrapSol: true,
32 | dynamicComputeUnitLimit: true,
33 | prioritizationFeeLamports: 52000
34 | }),
35 | })
36 | ).json();
37 | // deserialize the transaction
38 | const swapTransactionBuf = Buffer.from(swapTransaction, "base64");
39 | var transaction = VersionedTransaction.deserialize(swapTransactionBuf);
40 | // sign the transaction
41 | // transaction.sign([wallet]);
42 | console.log("simulation => ", await connection.simulateTransaction(transaction))
43 | console.log("transaction", transaction)
44 | await wallet.signTransaction!(transaction);
45 | return transaction
46 | } catch (error) {
47 | console.log("Failed to get buy transaction")
48 | return null
49 | }
50 | };
51 |
52 | export async function getTokenData(mint: string, connection: Connection): Promise {
53 | const metaplex = Metaplex.make(connection);
54 | const mintAddress = new PublicKey(mint);
55 | let tokenName;
56 | let tokenSymbol;
57 | const metadataAccount = metaplex
58 | .nfts()
59 | .pdas()
60 | .metadata({ mint: mintAddress });
61 | const metadataAccountInfo = await connection.getAccountInfo(metadataAccount);
62 | if (metadataAccountInfo) {
63 | const token: any = await metaplex.nfts().findByMint({ mintAddress: mintAddress });
64 | tokenName = token.name;
65 | tokenSymbol = token.symbol;
66 | // tokenLogo = token.json.image? token.json.image: "";
67 | }
68 | return {
69 | name: tokenName,
70 | symbol: tokenSymbol,
71 | // uri: tokenLogo
72 | }
73 | }
74 |
75 | export const getMyTokens = async (walletPubKey: PublicKey, connection: Connection) => {
76 | console.log("calling getMyTokens...");
77 | try {
78 | const tokenAccounts = await connection.getTokenAccountsByOwner(walletPubKey, { programId: TOKEN_PROGRAM_ID });
79 | const tokensData = await Promise.all(tokenAccounts.value.map(async (account) => {
80 | const accountInfo = AccountLayout.decode(account.account.data);
81 | const mintAddress = new PublicKey(accountInfo.mint);
82 | let price: number;
83 | const mintInfo = await getMint(connection, mintAddress);
84 | // const tokenInfo = await getTokenInfo(connection, mintAddress)
85 | const tokenInfo = await getTokenData(accountInfo.mint.toBase58(), connection)
86 | // Exclude tokens with a supply of 1 (NFTs)
87 | if (mintInfo.supply.toString() === "1") {
88 | return null;
89 | }
90 | // const res = await axios.get(`https://price.jup.ag/v6/price?ids=${walletPubKey.toBase58()}&vsToken=So11111111111111111111111111111111111111112`)
91 | // console.log("res------------------------>", res.data.data)
92 | const response = await fetch(
93 | `https://price.jup.ag/v6/price?ids=${mintAddress.toBase58()}&vsToken=So11111111111111111111111111111111111111112`
94 | );
95 | if (!response.ok) {
96 | throw new Error('Failed to fetch data');
97 | }
98 | const data: any = await response.json();
99 | if (Object.keys(data.data).length === 0) {
100 | price = 0;
101 | } else {
102 | price = data.data[mintAddress.toBase58()].price;
103 | }
104 | return {
105 | mintAddress: accountInfo.mint.toBase58(),
106 | decimals: mintInfo.decimals,
107 | supply: parseInt((BigInt(mintInfo.supply) / BigInt(10 ** mintInfo.decimals)).toString()), // Assuming supply is a BigInt, convert it to string for better handling in JS.
108 | balance: parseInt((BigInt(accountInfo.amount) / BigInt(10 ** mintInfo.decimals)).toString()), // Same as supply, handle big numbers as strings.
109 | // @ts-ignore
110 | name: tokenInfo.name,
111 | // @ts-ignore
112 | symbol: tokenInfo.symbol,
113 | price: price
114 | };
115 | }));
116 | let txt = '';
117 | const tokens = tokensData.filter(token => token !== null);
118 | for (let i = 0; i < (tokens?.length > 15 ? 15 : tokens?.length); i++) {
119 | txt += `
120 | CA: ${tokens[i].mintAddress}
121 | name: ${tokens[i].name}
122 | symbol: $${tokens[i].symbol}
123 | decimals: ${tokens[i].decimals}
124 | supply: ${tokens[i].supply}
125 | balance: ${tokens[i].balance}
126 | value: ${tokens[i].price * tokens[i].balance}
127 | `
128 | }
129 | return txt
130 | } catch (error) {
131 | console.error("Error fetching tokens:", error);
132 | return "Can't fetch wallet assets, there is something's wrong."
133 | }
134 | };
--------------------------------------------------------------------------------
/src/main.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App.tsx";
4 | import { RecoilRoot } from "recoil";
5 |
6 | import { ChainlitAPI, ChainlitContext } from '@chainlit/react-client';
7 |
8 | const VITE_CHAINLIT_SERVER = import.meta.env.VITE_CHAINLIT_SERVER;
9 | const apiClient = new ChainlitAPI(VITE_CHAINLIT_SERVER, "webapp");
10 |
11 | ReactDOM.createRoot(document.getElementById("root")!).render(
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | );
20 |
--------------------------------------------------------------------------------
/src/pages/buttonSpinner/index.tsx:
--------------------------------------------------------------------------------
1 | import Spinner from 'react-bootstrap/Spinner';
2 |
3 | function buttonSpinner() {
4 |
5 | return ;
6 | }
7 |
8 | export default buttonSpinner;
--------------------------------------------------------------------------------
/src/pages/playground/index.module.scss:
--------------------------------------------------------------------------------
1 | @use "@styles/globalStyles.scss" as G;
2 |
3 | .body {
4 | display: flex;
5 | padding: 24px 32px;
6 | flex-direction: column;
7 | align-items: flex-start;
8 | gap: 24px;
9 | flex: 1 0 0;
10 | align-self: stretch;
11 | @include G.breakpoint("xm") {
12 | padding: 9px;
13 | }
14 | .titleBar{
15 | display: grid;
16 | grid-template-columns: 0.05fr auto;
17 | justify-content: space-between;
18 | align-items: center;
19 | align-self: stretch;
20 |
21 | .selectItem {
22 | padding: 12px;
23 | border-radius: 12px;
24 | }
25 |
26 | .title {
27 | color: var(--Gray-Gray-700, #2D3748);
28 | font-size: 24px;
29 | font-style: normal;
30 | font-weight: 500;
31 | line-height: 32px; /* 133.333% */
32 | @include G.breakpoint("xm") {
33 | font-size: 21px;
34 | }
35 | }
36 | .walletBtn{
37 | cursor: pointer;
38 | transition: 0.2s;
39 | width: 180px;
40 | font-family: "Asap Condensed";
41 | height: 35px;
42 | font-style: normal;
43 | font-weight: 400;
44 | font-size: 21px;
45 | line-height: 32px;
46 | color: black;
47 | border: 1px solid rgb(0, 0, 0);
48 | background: white;
49 | border-radius: 100px;
50 | display: flex;
51 | align-items: center;
52 | justify-content: center;
53 | box-shadow: rgb(0, 0, 0) 4px 4px 0px 0px;
54 | &:hover{
55 | box-shadow: rgb(0, 0, 0) 2px 2px 0px 0px;
56 | }
57 | &:active{
58 | box-shadow: rgb(0, 0, 0) 0px 0px 0px 0px;
59 | }
60 | }
61 |
62 | .newChatBtn {
63 | display: flex;
64 | color: white;
65 | padding: 12px 24px;
66 | align-items: center;
67 | gap: 8px;
68 | border-radius: 15px;
69 | background: var(--Blue, #0073FF);
70 | &:hover{
71 | background: #2f88f5;
72 | }
73 | &:active{
74 | background: #0073FF;
75 | }
76 | cursor: pointer;
77 | @include G.breakpoint("xm") {
78 | padding: 12px 6px;
79 | }
80 | }
81 | .historyBar{
82 | max-width: 400px;
83 | min-width: 245px;
84 | margin-top: 3px;
85 | width: 100%;
86 | height: calc(100vh - 120px);
87 | border-radius: 16px;
88 | border: 1px solid #E2E8F0;
89 | background: var(--White, #FFF);
90 | .historyTitle{
91 | color: var(--Grey, #92929D);
92 | display: flex;
93 | padding: 12px 24px;
94 | align-items: flex-start;
95 | gap: 24px;
96 | align-self: stretch;
97 | border-bottom: 1px solid #E2E8F0;
98 | }
99 | .historyList{
100 | display: flex;
101 | overflow: auto;
102 | height: 100%;
103 | flex-direction: column;
104 | align-items: flex-start;
105 | border-radius: 0px 0px 16px 16px;
106 | border: 1px solid #E2E8F0;
107 | background: var(--White, #FFF);
108 | .listItem {
109 | display: flex;
110 | padding: 8px 16px;
111 | align-items: center;
112 | gap: 16px;
113 | align-self: stretch;
114 | border-bottom: 1px solid #E2E8F0;
115 | &:hover {
116 | cursor: pointer;
117 | background-color: rgb(216, 216, 216);
118 | }
119 | &:active {
120 | cursor: pointer;
121 | background-color: rgb(204, 204, 204);
122 | }
123 | .avatar{
124 | display: flex;
125 | color: white;
126 | width: 40px;
127 | height: 40px;
128 | padding: 8px;
129 | justify-content: center;
130 | align-items: center;
131 | gap: 8px;
132 | border-radius: 100px;
133 | border: 1.5px solid var(--White, #FFF);
134 | background: #48BB78;
135 | box-shadow: 0px 3.5px 5.5px 0px rgba(0, 0, 0, 0.04);
136 | }
137 | .brief{
138 | display: flex;
139 | flex-direction: column;
140 | justify-content: center;
141 | align-items: flex-start;
142 | flex: 1 0 0;
143 | .userInfo{
144 | display: flex;
145 | align-items: center;
146 | gap: 4px;
147 | align-self: stretch;
148 | .userName{
149 | flex: 1 0 0;
150 | color: #44444F;
151 | font-size: 14px;
152 | font-style: normal;
153 | font-weight: 500;
154 | line-height: 150%; /* 21px */
155 | }
156 | .duration{
157 | color: var(--Grey, #92929D);
158 | font-size: 12px;
159 | font-style: normal;
160 | font-weight: 400;
161 | line-height: 150%; /* 18px */
162 | }
163 | }
164 | .latestOne{
165 | flex: 1 0 0;
166 | color: var(--Grey, #92929D);
167 | font-size: 12px;
168 | font-style: normal;
169 | font-weight: 400;
170 | line-height: 150%; /* 18px */
171 | }
172 | }
173 | }
174 | }
175 | }
176 | }
177 |
178 | .playground{
179 | display: flex;
180 | min-height: calc(100vh - 200px);
181 | align-items: flex-start;
182 | gap: 24px;
183 | flex: 1 0 0;
184 | align-self: stretch;
185 | @include G.breakpoint("xm") {
186 | min-height: calc(100vh - 160px);
187 | }
188 | .historyBar{
189 | display: flex;
190 | max-width: 275px;
191 | min-width: 245px;
192 | width: 100%;
193 | border-radius: 16px;
194 | border: 1px solid #E2E8F0;
195 | background: var(--White, #FFF);
196 | flex-direction: column;
197 | align-items: flex-start;
198 | flex: 1 0 0;
199 | align-self: stretch;
200 |
201 | @include G.breakpoint("lg") {
202 | display: none;
203 | }
204 | .historyTitle{
205 | color: var(--Grey, #92929D);
206 | display: flex;
207 | padding: 12px 24px;
208 | align-items: flex-start;
209 | gap: 24px;
210 | align-self: stretch;
211 | border-bottom: 1px solid #E2E8F0;
212 | }
213 | .historyList{
214 | display: flex;
215 | flex-direction: column;
216 | overflow: auto;
217 | min-height: 340px;
218 | align-items: flex-start;
219 | flex: 1 0 0;
220 | border-radius: 0px 0px 16px 16px;
221 | border: 1px solid #E2E8F0;
222 | background: var(--White, #FFF);
223 | align-self: stretch;
224 | .listItem {
225 | display: flex;
226 | padding: 8px 16px;
227 | align-items: center;
228 | gap: 16px;
229 | align-self: stretch;
230 | border-bottom: 1px solid #E2E8F0;
231 | &:hover {
232 | cursor: pointer;
233 | background-color: rgb(216, 216, 216);
234 | }
235 | &:active {
236 | cursor: pointer;
237 | background-color: rgb(204, 204, 204);
238 | }
239 | .avatar{
240 | display: flex;
241 | color: white;
242 | width: 40px;
243 | height: 40px;
244 | padding: 8px;
245 | justify-content: center;
246 | align-items: center;
247 | gap: 8px;
248 | border-radius: 100px;
249 | border: 1.5px solid var(--White, #FFF);
250 | background: #48BB78;
251 | box-shadow: 0px 3.5px 5.5px 0px rgba(0, 0, 0, 0.04);
252 | }
253 | .brief{
254 | display: flex;
255 | flex-direction: column;
256 | justify-content: center;
257 | align-items: flex-start;
258 | flex: 1 0 0;
259 | .userInfo{
260 | display: flex;
261 | align-items: center;
262 | gap: 4px;
263 | align-self: stretch;
264 | .userName{
265 | flex: 1 0 0;
266 | color: #44444F;
267 | font-size: 14px;
268 | font-style: normal;
269 | font-weight: 500;
270 | line-height: 150%; /* 21px */
271 | }
272 | .duration{
273 | color: var(--Grey, #92929D);
274 | font-size: 12px;
275 | font-style: normal;
276 | font-weight: 400;
277 | line-height: 150%; /* 18px */
278 | }
279 | }
280 | .latestOne{
281 | flex: 1 0 0;
282 | color: var(--Grey, #92929D);
283 | font-size: 12px;
284 | font-style: normal;
285 | font-weight: 400;
286 | line-height: 150%; /* 18px */
287 | }
288 | }
289 | }
290 | }
291 | }
292 | .chattingBar{
293 | min-width: 670px;
294 | width: 100%;
295 | display: flex;
296 | flex-direction: column;
297 | align-items: flex-start;
298 | flex: 1 0 0;
299 | align-self: stretch;
300 | border-radius: 16px;
301 | border: 1px solid #E2E8F0;
302 | background: #F8F8FA;
303 | @include G.breakpoint("sm") {
304 | min-width: 250px;
305 | }
306 |
307 | .chatTitleBar{
308 | display: flex;
309 | padding: 12px 24px;
310 | border-radius: 16px 16px 0px 0px;
311 | align-items: center;
312 | gap: 16px;
313 | align-self: stretch;
314 | border-bottom: 1px solid #E2E8F0;
315 | background: #FFF;
316 | .backChatBtn{
317 | display: flex;
318 | padding: 3px;
319 | align-items: center;
320 | gap: 8px;
321 | border-radius: 30px;
322 | border: 1px solid #E1E1E9;
323 | background: var(--White, #FFF);
324 | cursor: pointer;
325 | }
326 | .userBar{
327 | display: flex;
328 | align-items: center;
329 | gap: 6px;
330 | flex: 1 0 0;
331 | .avatar{
332 | display: flex;
333 | color: white;
334 | width: 40px;
335 | height: 40px;
336 | padding: 8px;
337 | justify-content: center;
338 | align-items: center;
339 | gap: 8px;
340 | border-radius: 100px;
341 | border: 1.5px solid var(--White, #FFF);
342 | background: #48BB78;
343 | box-shadow: 0px 3.5px 5.5px 0px rgba(0, 0, 0, 0.04);
344 | }
345 | .userName{
346 | flex: 1 0 0;
347 | color: var(--Dark, #44444F);
348 | font-size: 16px;
349 | font-style: normal;
350 | font-weight: 500;
351 | line-height: 24px; /* 150% */
352 | }
353 | }
354 | .externalBtn{
355 | display: flex;
356 | padding: 8px;
357 | align-items: center;
358 | gap: 8px;
359 | border-radius: 15px;
360 | border: 1px solid #E1E1E9;
361 | background: var(--White, #FFF);
362 | cursor: pointer;
363 | }
364 | }
365 | .workspace{
366 | display: flex;
367 | padding: 32px;
368 | flex-direction: column;
369 | overflow: auto;
370 | align-items: flex-start;
371 | gap: 16px;
372 | flex: 1 0 0;
373 | align-self: stretch;
374 | border-right: 4px solid #FFF;
375 | border-left: 4px solid #FFF;
376 | .userDialog{
377 | display: flex;
378 | align-items: center;
379 | gap: 16px;
380 | align-self: stretch;
381 | .avatar{
382 | display: flex;
383 | width: 40px;
384 | height: 40px;
385 | padding: 8px;
386 | justify-content: center;
387 | align-items: center;
388 | gap: 8px;
389 | border-radius: 100px;
390 | border: 1.5px solid var(--White, #FFF);
391 | background: #48BB78;
392 | box-shadow: 0px 3.5px 5.5px 0px rgba(0, 0, 0, 0.04);
393 | color: var(--White, #FFF);
394 | text-align: center;
395 | font-size: 14px;
396 | font-style: normal;
397 | font-weight: 500;
398 | line-height: 16px; /* 114.286% */
399 | }
400 | .userMessage{
401 | display: flex;
402 | padding: 12px 24px;
403 | flex-direction: column;
404 | justify-content: center;
405 | align-items: flex-start;
406 | border-radius: 8px;
407 | background: #FFF;
408 | color: var(--Dark, #44444F);
409 | font-size: 16px;
410 | font-style: normal;
411 | font-weight: 500;
412 | line-height: 24px; /* 150% */
413 | }
414 | p{
415 | display: flex;
416 | justify-content: end;
417 | }
418 | }
419 | .aiDialog{
420 | display: flex;
421 | justify-content: flex-end;
422 | align-items: center;
423 | gap: 16px;
424 | align-self: stretch;
425 | .aiMessage{
426 | color: white;
427 | display: flex;
428 | padding: 12px 24px;
429 | flex-direction: column;
430 | justify-content: center;
431 | align-items: flex-start;
432 | border-radius: 8px;
433 | background: var(--Blue, #0073FF);
434 | }
435 | .avatar{
436 | display: flex;
437 | width: 40px;
438 | height: 40px;
439 | padding: 8px;
440 | justify-content: center;
441 | align-items: center;
442 | gap: 8px;
443 | border-radius: 100px;
444 | border: 1.5px solid var(--White, #FFF);
445 | background: #bb48ac;
446 | box-shadow: 0px 3.5px 5.5px 0px rgba(0, 0, 0, 0.04);
447 | color: var(--White, #FFF);
448 | text-align: center;
449 | font-size: 14px;
450 | font-style: normal;
451 | font-weight: 500;
452 | line-height: 16px; /* 114.286% */
453 | }
454 | .userMessage{
455 | display: flex;
456 | padding: 12px 24px;
457 | flex-direction: column;
458 | justify-content: center;
459 | align-items: flex-start;
460 | border-radius: 8px;
461 | background: #FFF;
462 | color: var(--Dark, #44444F);
463 | font-size: 16px;
464 | font-style: normal;
465 | font-weight: 500;
466 | line-height: 24px; /* 150% */
467 | }
468 | p{
469 | display: flex;
470 | justify-content: end;
471 | }
472 | }
473 | }
474 | .promptInputBar{
475 | display: flex;
476 | padding: 12px 16px;
477 | align-items: center;
478 | gap: 16px;
479 | align-self: stretch;
480 | border-radius: 0px 0px 16px 16px;
481 | background: #FFF;
482 | .emotic{
483 | width: 24px;
484 | height: 24px;
485 | cursor: pointer;
486 | }
487 | .promptInput{
488 | display: flex;
489 | flex-direction: column;
490 | justify-content: center;
491 | align-items: flex-start;
492 | gap: 4px;
493 | align-self: stretch;
494 | flex: 1 0 0;
495 | color: var(--Grey, #92929D);
496 | font-size: 14px;
497 | font-weight: 400;
498 | line-height: 150%; /* 21px */
499 | .inputWidget{
500 | width: 100%;
501 | border: none;
502 | outline: 0px;
503 | border: 1px solid lightgray;
504 | border-radius: 10px;
505 | padding: 10px;
506 | }
507 | }
508 | .sendBtn{
509 | display: flex;
510 | padding: 8px;
511 | align-items: center;
512 | gap: 8px;
513 | border: none;
514 | border-radius: 15px;
515 | background: var(--Blue, #0073FF);
516 | &:hover{
517 | background: #2f88f5;
518 | }
519 | &:active{
520 | background: #0073FF;
521 | }
522 | cursor: pointer;
523 | }
524 | .disabled{
525 | background: var(--Blue, #748ead);
526 | &:hover{
527 | background: #748ead;
528 | }
529 | &:active{
530 | background: #748ead;
531 | }
532 | cursor: no-drop;
533 | }
534 | }
535 | }
536 | }
537 | }
--------------------------------------------------------------------------------
/src/pages/playground/index.tsx:
--------------------------------------------------------------------------------
1 | import S from "./index.module.scss";
2 | import "@styles/resource.scss"
3 | import emojiHappy from "@assets/svg/emojiHappy.svg"
4 | import paperAirplane from "@assets/svg/paperAirplane.svg"
5 | import backBtn from "@assets/svg/chevron-left.svg"
6 | import dotHorizonBtn from "@assets/svg/dotsHorizontal.svg"
7 | import { Toaster } from 'react-hot-toast'
8 | import { useEffect, useState } from "react";
9 | import clsx from "clsx";
10 |
11 | // Web3 integratino Import Settings
12 | import { useConnection, useWallet } from "@solana/wallet-adapter-react";
13 | import { useWalletModal } from "@solana/wallet-adapter-react-ui";
14 | import { getBuyTxWithJupiter, getMyTokens } from "@hooks/index";
15 |
16 | import {
17 | PublicKey,
18 | } from '@solana/web3.js'
19 |
20 | // Chainlit integration Import Settings--------------------------------------------------------
21 | import { v4 as uuidv4 } from "uuid";
22 | import {
23 | useChatSession,
24 | useChatData,
25 | useChatInteract,
26 | useChatMessages,
27 | IStep,
28 | } from "@chainlit/react-client";
29 |
30 | // END Chainlit integration Import Settings--------------------------------------------------------
31 |
32 | export const Playground = () => {
33 | // Web3 integration
34 | const { connection } = useConnection();
35 | const wallet = useWallet();
36 | const { setVisible } = useWalletModal();
37 |
38 | const handleWalletConnect = async () => {
39 | if (wallet.connected) {
40 | wallet.disconnect()
41 | } else {
42 | setVisible(true)
43 | }
44 | }
45 |
46 | // Chainlit integration--------------------------------------------------------
47 | const { connect, disconnect } = useChatSession();
48 | const { loading } = useChatData();
49 | const { sendMessage } = useChatInteract();
50 | const { messages } = useChatMessages();
51 |
52 | // Connect to the WebSocket server
53 | useEffect(() => {
54 | connect({
55 | userEnv: {},
56 | });
57 |
58 | return () => {
59 | disconnect();
60 | };
61 | }, []);
62 |
63 | const [inputValue, setInputValue] = useState("");
64 | const [txSig, setTxSig] = useState("");
65 | const [assets, setAssets] = useState("");
66 |
67 | const handleSendMessage = () => {
68 | const content = inputValue.trim();
69 | if (content) {
70 | const message: IStep = {
71 | id: uuidv4(),
72 | name: "",
73 | type: "user_message",
74 | output: content,
75 | createdAt: new Date().toISOString(),
76 | };
77 | sendMessage(message, []);
78 | setInputValue("");
79 | }
80 | };
81 |
82 | const renderMessage = (message: IStep) => {
83 | const dateOptions: Intl.DateTimeFormatOptions = {
84 | hour: "2-digit",
85 | minute: "2-digit",
86 | };
87 | const date = new Date(message.createdAt).toLocaleTimeString(
88 | undefined,
89 | dateOptions
90 | );
91 | /*
92 | 1. Check 'chat start' or 'on chat' since msg content structure is different with them
93 | : [conditional statement code] message.name === "on_chat_start"?A:B;
94 | 2. Check whether the response to user's prompt is 'None' or not
95 | : [conditional statement code] message.steps?.[0]?.steps?.[0]?.output !== undefined && ()
96 | - Check whether the response is related to excution of token buy, etc
97 | : [code] message.steps?.[0]?.steps?.[0]?.output.split("--")[0] !== "Execution" ? A:B;
98 | * Check whether txSig is None or not.
99 | */
100 | return (
101 |
102 | {message.name === "on_chat_start" ? (
103 |
104 |
AI
105 |
106 |
{message.steps?.[0]?.output}
107 |
{date}
108 |
109 |
110 | ) : (
111 | <>
112 |
113 |
You
114 |
115 |
{(message.output)}
116 |
{date}
117 |
118 |
119 | {/* response to the user prompt */}
120 | {message.steps?.[0]?.steps?.[0]?.output !== undefined && (
121 | <>
122 | {message.steps?.[0]?.steps?.[0]?.output.split("--")[0] !== "Execution" ?
123 | (
124 |
AI
125 |
126 |
{message.steps?.[0]?.steps?.[0]?.output}
127 |
{date}
128 |
129 |
) :
130 | (
131 |
132 |
AI
133 |
134 | {txSig.length !== 0 && assets.length === 0 && (
135 |
139 | )}
140 | {txSig.length === 0 && assets.length === 0 && (
141 |
142 |
Transaction failed or no assets are there in this wallet.
143 |
{date}
144 |
145 | )}
146 | {txSig.length === 0 && assets.length !== 0 && (
147 |
148 |
{assets}
149 |
{date}
150 |
151 | )}
152 |
153 |
154 | )
155 | }
156 | >
157 | )}
158 | >
159 | )}
160 |
161 | );
162 | };
163 | // END Chainlit Integration--------------------------------------------------------
164 |
165 | useEffect(() => {
166 | const fetchAndExecute = async () => {
167 | if (messages.length > 0) {
168 | const asw_on_last_qn = messages[messages.length - 1].steps?.[0]?.steps?.[0]?.output;
169 | const prefix = asw_on_last_qn?.split("--")[0];
170 | console.log("msgs: ", messages)
171 |
172 | if (prefix === "Execution") {
173 | const token_name = asw_on_last_qn?.split("--")[1];
174 | const baseMint = asw_on_last_qn?.split("--")[2];
175 | const token_amount = asw_on_last_qn?.split("--")[3];
176 | if (token_name == "wallet") {
177 | let assetsInfo = await getMyTokens(wallet.publicKey!, connection);
178 | console.log('assets: ', assetsInfo)
179 | setAssets(assetsInfo);
180 | }
181 | else if (token_name && baseMint && token_amount) {
182 | try {
183 | // Await the transaction retrieval
184 | const tx = await getBuyTxWithJupiter(wallet, new PublicKey(baseMint), Number(token_amount), connection);
185 | console.log("tx", tx)
186 |
187 | // Check if tx is null before proceeding
188 | if (tx) {
189 |
190 | const latestBlockhash = await connection.getLatestBlockhash();
191 | tx.message.recentBlockhash = latestBlockhash.blockhash;
192 | // wallet.signTransaction(walletSendTx);
193 | console.log(
194 | (await connection.simulateTransaction(tx, undefined)).value
195 | .logs
196 | );
197 |
198 | const txSig = await wallet.sendTransaction(tx, connection, {
199 | skipPreflight: true,
200 | preflightCommitment: "confirmed",
201 | });
202 | console.log('Transaction Signature:', txSig);
203 | const res = await connection.confirmTransaction(txSig, "confirmed");
204 | console.log("res", res);
205 |
206 | setTxSig(txSig);
207 | // Optionally handle txSig or log it
208 |
209 | } else {
210 | console.error('Transaction could not be created.');
211 | }
212 | } catch (error) {
213 | console.error('Error executing transaction:', error);
214 | }
215 | }
216 | }
217 | }
218 | };
219 |
220 | fetchAndExecute();
221 | }, [messages]);
222 |
223 | return (
224 |
225 |
226 |
VaLAI
227 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |

241 |
242 |
243 | {/*
AD
244 |
Jason Admin
*/}
245 |
246 |
247 |

248 |
249 |
250 |
251 | {messages.map((message) => renderMessage(message))}
252 |
253 |
254 |
255 |

256 |
257 |
258 | setInputValue(e.target.value)}
267 | onKeyUp={(e) => {
268 | if (e.key === "Enter") {
269 | handleSendMessage();
270 | }
271 | }
272 | }
273 | />
274 |
275 |
278 |
279 |
280 |
281 |
282 |
283 | );
284 | };
285 |
286 |
--------------------------------------------------------------------------------
/src/pages/spinner/index.module.scss:
--------------------------------------------------------------------------------
1 | .body {
2 | display: flex;
3 | justify-content: center;
4 | align-items: center;
5 | width: 100%;
6 | min-height: calc(100vh - 150px);
7 | .wrapper {
8 | margin: auto;
9 | }
10 | }
--------------------------------------------------------------------------------
/src/pages/spinner/index.tsx:
--------------------------------------------------------------------------------
1 | import PropagateLoader from "react-spinners/PropagateLoader";
2 | import S from "./index.module.scss";
3 |
4 | function Spinner() {
5 |
6 | return (
7 |
10 | );
11 | }
12 |
13 | export default Spinner;
--------------------------------------------------------------------------------
/src/styles/globalStyles.scss:
--------------------------------------------------------------------------------
1 | $breakpoints: (
2 | "xxm": 516px,
3 | "xm": 540px,
4 | "sxm": 727px,
5 | "sm": 810px,
6 | "msm": 850px,
7 | "md": 1180px,
8 | "lg": 1280px,
9 | "xl": 1440px,
10 | "xxl": 1920px,
11 | );
12 |
13 | @mixin breakpoint($name) {
14 | @media (max-width: map-get($breakpoints, $name)) {
15 | @content;
16 | }
17 | }
18 |
19 | @mixin flexAlignCenter {
20 | display: flex;
21 | align-items: center;
22 | }
23 |
24 | @mixin flexJustifyCenter {
25 | display: flex;
26 | justify-content: center;
27 | }
28 |
29 | @mixin flexCenter {
30 | @include flexAlignCenter;
31 | justify-content: center;
32 | }
33 |
34 | @mixin sectionPadding {
35 | padding: 40px 0 60px;
36 | }
37 |
38 | @mixin container {
39 | max-width: 1440px;
40 | margin: auto;
41 | }
42 |
--------------------------------------------------------------------------------
/src/styles/globalStyles.ts:
--------------------------------------------------------------------------------
1 | import { createGlobalStyle } from "styled-components";
2 |
3 | export const GlobalStyles = createGlobalStyle`
4 | *{
5 | margin: 0;
6 | padding: 0;
7 | box-sizing: border-box;
8 | font-family: "Roboto", sans-serif;
9 | /* user-select: none; */
10 | }
11 |
12 | body {
13 | background-color: ${({ theme }) => theme.body};
14 | color: ${({ theme }) => theme.text};
15 | font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
16 | }
17 |
18 | #root {
19 | overflow-x: hidden;
20 | max-width: 100vw;
21 | }
22 | `;
23 |
24 | export const lightTheme = {
25 | body: "#fff",
26 | };
27 |
28 | export const darkTheme = {
29 | body: "#000",
30 | };
31 |
--------------------------------------------------------------------------------
/src/styles/resource.scss:
--------------------------------------------------------------------------------
1 | @use "@styles/globalStyles.scss" as G;
2 |
3 | .mobile-menu {
4 | position: fixed;
5 | z-index: 80;
6 | width: 0;
7 | height: 100vh;
8 | top: 70px;
9 |
10 | background-color: rgba($color: rgb(255, 255, 255), $alpha: 0.3);
11 | @media (max-width: 1280px) {
12 | left: 275px;
13 | }
14 | @media (max-width: 1180px) {
15 | left: 0px;
16 | }
17 |
18 | // -webkit-backdrop-filter: blur(10px); /* Blur effect for Chrome, Safari, and Opera */
19 | // backdrop-filter: blur(10px); /* Blur effect for other browsers */
20 | // transition: width 0.1s ease-in-out;
21 |
22 | &.active {
23 | display: flex;
24 | width: 250px;
25 | @media (min-width: 1280px) {
26 | display: none;
27 | }
28 | }
29 |
30 | .side {
31 | width: 100%;
32 | display: flex;
33 | flex-direction: column;
34 | overflow: hidden;
35 |
36 | }
37 | }
38 | .app-mobile-menu {
39 | position: fixed;
40 | z-index: 80;
41 | width: 0;
42 | height: 100vh;
43 | top: 0px;
44 | left: 0px;
45 |
46 | background-color: rgba($color: rgb(255, 255, 255), $alpha: 1);
47 | // -webkit-backdrop-filter: blur(10px); /* Blur effect for Chrome, Safari, and Opera */
48 | // backdrop-filter: blur(10px); /* Blur effect for other browsers */
49 | transition: width 0.1s ease-in-out;
50 |
51 | &.active {
52 | display: flex;
53 | width: 275px;
54 | @media (min-width: 1180px) {
55 | display: none;
56 | }
57 | }
58 |
59 | .side {
60 | width: 100%;
61 | display: flex;
62 | flex-direction: column;
63 | overflow: hidden;
64 |
65 | }
66 | }
67 |
68 | #appHamburger {
69 | margin-left: 10px;
70 | .pad {
71 | position: sticky;
72 | top: 20px;
73 | > div {
74 | width: 30px;
75 | height: 30px;
76 | align-items: center;
77 | justify-content: center;
78 | border-radius: 4px;
79 | cursor: pointer;
80 | display: none;
81 |
82 | @include G.breakpoint("md") {
83 | display: flex;
84 | }
85 | }
86 | }
87 | }
88 | #hamburger {
89 | margin-left: 10px;
90 | .pad {
91 | position: sticky;
92 | top: 20px;
93 | > div {
94 | width: 30px;
95 | height: 30px;
96 | align-items: center;
97 | justify-content: center;
98 | border-radius: 4px;
99 | cursor: pointer;
100 | display: none;
101 |
102 | @include G.breakpoint("lg") {
103 | display: flex;
104 | }
105 | }
106 | }
107 | }
--------------------------------------------------------------------------------
/src/utils/routerUtils.tsx:
--------------------------------------------------------------------------------
1 | import { Playground } from "@pages/playground";
2 | import { Route, Routes} from "react-router-dom";
3 |
4 | export const AppRouter = () => {
5 | return (
6 |
7 | } />
8 |
9 | );
10 | };
11 |
--------------------------------------------------------------------------------
/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2020",
4 | "useDefineForClassFields": true,
5 | "lib": ["ES2020", "DOM", "DOM.Iterable"],
6 | "module": "ESNext",
7 | "skipLibCheck": true,
8 | "allowJs": true,
9 |
10 | /* Bundler mode */
11 | "moduleResolution": "bundler",
12 | "allowImportingTsExtensions": true,
13 | "resolveJsonModule": true,
14 | "isolatedModules": true,
15 | "noEmit": true,
16 | "jsx": "react-jsx",
17 | "esModuleInterop": true,
18 | "allowSyntheticDefaultImports": true,
19 |
20 | /* Linting */
21 | "strict": true,
22 | "noUnusedLocals": true,
23 | "noUnusedParameters": true,
24 | "noFallthroughCasesInSwitch": true,
25 | "forceConsistentCasingInFileNames": true,
26 |
27 | "baseUrl": "src",
28 | "paths": {
29 | "@assets/*": ["assets/*"],
30 | "@features/*": ["features/*"],
31 | "@pages/*": ["pages/*"],
32 | "@styles/*": ["styles/*"],
33 | "@utils/*": ["utils/*"],
34 | "@constants/*": ["constants/*"],
35 | "@context/*": ["context/*"],
36 | "@middleware/*": ["middleware/*"],
37 | "@hooks/*": ["hooks/*"],
38 | }
39 | },
40 | "include": ["src"]
41 | }
42 |
--------------------------------------------------------------------------------
/vercel.json:
--------------------------------------------------------------------------------
1 | {
2 | "rewrites": [
3 | {
4 | "source": "/(.*)",
5 | "destination": "/index.html"
6 | }
7 | ]
8 | }
--------------------------------------------------------------------------------
/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from "vite";
2 | import react from "@vitejs/plugin-react";
3 | import { nodePolyfills } from 'vite-plugin-node-polyfills'
4 |
5 | // https://vitejs.dev/config/
6 | export default defineConfig({
7 | plugins: [react(), nodePolyfills()],
8 | server: {
9 | port: 3005,
10 | },
11 | resolve: {
12 | alias: {
13 | "@assets": "/src/assets",
14 | "@features": "/src/features",
15 | "@pages": "/src/pages",
16 | "@styles": "/src/styles",
17 | "@utils": "/src/utils",
18 | "@constants": "/src/constants",
19 | "@context": "/src/context",
20 | "@middleware": "/src/middleware",
21 | "@hooks": "/src/hooks",
22 | },
23 | },
24 | });
25 |
--------------------------------------------------------------------------------