84 | );
85 | }
86 |
--------------------------------------------------------------------------------
/tailwind.config.ts:
--------------------------------------------------------------------------------
1 | import type { Config } from "tailwindcss"
2 |
3 | const config = {
4 | darkMode: ["class"],
5 | content: [
6 | './pages/**/*.{ts,tsx}',
7 | './components/**/*.{ts,tsx}',
8 | './app/**/*.{ts,tsx}',
9 | './src/**/*.{ts,tsx}',
10 | ],
11 | prefix: "",
12 | theme: {
13 | container: {
14 | center: true,
15 | padding: "2rem",
16 | screens: {
17 | "2xl": "1400px",
18 | },
19 | },
20 | extend: {
21 | colors: {
22 | rabble: "#08F7AF",
23 | back: "#E7E7E7",
24 | border: "hsl(var(--border))",
25 | input: "hsl(var(--input))",
26 | ring: "hsl(var(--ring))",
27 | background: "var(--tg-theme-bg-color)",
28 | "secondary-background": "var(--tg-theme-secondary-bg-color)",
29 | // var(--tg-theme-bg-color)
30 | // var(--tg-theme-text-color)
31 | // var(--tg-theme-hint-color)
32 | // var(--tg-theme-link-color)
33 | // var(--tg-theme-button-color)
34 | // var(--tg-theme-button-text-color)
35 | //
36 | color: "var(--tg-theme-text-color)",
37 | "subtitle-color": "var(--tg-theme-subtitle-text-color)",
38 | foreground: "hsl(var(--foreground))",
39 | primary: {
40 | DEFAULT: "hsl(var(--primary))",
41 | foreground: "hsl(var(--primary-foreground))",
42 | },
43 | secondary: {
44 | DEFAULT: "hsl(var(--secondary))",
45 | foreground: "hsl(var(--secondary-foreground))",
46 | },
47 | destructive: {
48 | DEFAULT: "hsl(var(--destructive))",
49 | foreground: "hsl(var(--destructive-foreground))",
50 | },
51 | muted: {
52 | DEFAULT: "hsl(var(--muted))",
53 | foreground: "hsl(var(--muted-foreground))",
54 | },
55 | accent: {
56 | DEFAULT: "hsl(var(--accent))",
57 | foreground: "hsl(var(--accent-foreground))",
58 | },
59 | popover: {
60 | DEFAULT: "hsl(var(--popover))",
61 | foreground: "hsl(var(--popover-foreground))",
62 | },
63 | card: {
64 | DEFAULT: "hsl(var(--card))",
65 | foreground: "hsl(var(--card-foreground))",
66 | },
67 | },
68 | borderRadius: {
69 | lg: "var(--radius)",
70 | md: "calc(var(--radius) - 2px)",
71 | sm: "calc(var(--radius) - 4px)",
72 | },
73 | keyframes: {
74 | "accordion-down": {
75 | from: { height: "0" },
76 | to: { height: "var(--radix-accordion-content-height)" },
77 | },
78 | "accordion-up": {
79 | from: { height: "var(--radix-accordion-content-height)" },
80 | to: { height: "0" },
81 | },
82 | },
83 | animation: {
84 | "accordion-down": "accordion-down 0.2s ease-out",
85 | "accordion-up": "accordion-up 0.2s ease-out",
86 | },
87 | fontFamily: {
88 | sans: ['var(--font-outfit)'],
89 | mono: ['var(--font-beVietnamPro)'],
90 | },
91 | },
92 | },
93 | plugins: [require("tailwindcss-animate")],
94 | } satisfies Config
95 |
96 | export default config
--------------------------------------------------------------------------------
/src/hooks/useTelegramMock.ts:
--------------------------------------------------------------------------------
1 | import { useClientOnce } from '@/hooks/useClientOnce';
2 | import { mockTelegramEnv, parseInitData, retrieveLaunchParams } from '@telegram-apps/sdk-react';
3 |
4 | /**
5 | * Mocks Telegram environment in development mode.
6 | */
7 | export function useTelegramMock(): void {
8 | useClientOnce(() => {
9 | // It is important, to mock the environment only for development purposes. When building the
10 | // application, import.meta.env.DEV will become false, and the code inside will be tree-shaken,
11 | // so you will not see it in your final bundle.
12 |
13 | let shouldMock: boolean;
14 |
15 | // Try to extract launch parameters to check if the current environment is Telegram-based.
16 | try {
17 | // If we are able to extract launch parameters, it means that we are already in the
18 | // Telegram environment. So, there is no need to mock it.
19 | retrieveLaunchParams();
20 |
21 | // We could previously mock the environment. In case we did, we should do it again. The reason
22 | // is the page could be reloaded, and we should apply mock again, because mocking also
23 | // enables modifying the window object.
24 | shouldMock = !!sessionStorage.getItem('____mocked');
25 | } catch (e) {
26 | shouldMock = true;
27 | }
28 |
29 | if (shouldMock) {
30 | const initDataRaw = new URLSearchParams([
31 | ['user', JSON.stringify({
32 | id: 99281932,
33 | first_name: 'Andrew',
34 | last_name: 'Rogue',
35 | username: 'rogue',
36 | language_code: 'en',
37 | is_premium: true,
38 | allows_write_to_pm: true,
39 | })],
40 | ['hash', '89d6079ad6762351f38c6dbbc41bb53048019256a9443988af7a48bcad16ba31'],
41 | ['auth_date', '1716922846'],
42 | ['start_param', 'debug'],
43 | ['chat_type', 'sender'],
44 | ['chat_instance', '8428209589180549439'],
45 | ]).toString();
46 |
47 | mockTelegramEnv({
48 | themeParams: {
49 | accentTextColor: '#6ab2f2',
50 | bgColor: '#17212b',
51 | buttonColor: '#5288c1',
52 | buttonTextColor: '#ffffff',
53 | destructiveTextColor: '#ec3942',
54 | headerBgColor: '#17212b',
55 | hintColor: '#708499',
56 | linkColor: '#6ab3f3',
57 | secondaryBgColor: '#232e3c',
58 | sectionBgColor: '#17212b',
59 | sectionHeaderTextColor: '#6ab3f3',
60 | subtitleTextColor: '#708499',
61 | textColor: '#f5f5f5',
62 | },
63 | initData: parseInitData(initDataRaw),
64 | initDataRaw,
65 | version: '7.2',
66 | platform: 'tdesktop',
67 | });
68 | sessionStorage.setItem('____mocked', '1');
69 |
70 | console.info(
71 | 'As long as the current environment was not considered as the Telegram-based one, it was mocked. Take a note, that you should not do it in production and current behavior is only specific to the development process. Environment mocking is also applied only in development mode. So, after building the application, you will not see this behavior and related warning, leading to crashing the application outside Telegram.',
72 | );
73 | }
74 | });
75 | }
--------------------------------------------------------------------------------
/public/loader.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/app/page.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import {
4 | useUtils,
5 | usePopup,
6 | useMainButton,
7 | useViewport,
8 | } from "@telegram-apps/sdk-react";
9 | import Link from "next/link";
10 | import Arrow from "@/assets/Arrow";
11 | import { Button } from "@/components/ui/button";
12 |
13 | export default function Home() {
14 | const utils = useUtils();
15 | const popUp = usePopup();
16 | const mainBtn = useMainButton();
17 | const viewport = useViewport();
18 |
19 | const handlePopUp = async () => {
20 | const response = await popUp.open({
21 | title: " Rabble",
22 | message: "Link will lead to website",
23 | buttons: [
24 | { id: "link", type: "default", text: "Open rabble.pro" },
25 | { type: "cancel" },
26 | ],
27 | });
28 | if (response === "link") {
29 | utils.openLink("https://rabble.pro");
30 | }
31 | };
32 |
33 | const handleShare = async () => {
34 | utils.shareURL(
35 | "https://t.me/+rFqLyk4_W-diZDZl",
36 | "Join! Mini Apps Hackathon group!"
37 | );
38 | };
39 | const handleMainBtn = async () => {
40 | mainBtn.enable();
41 | mainBtn.setText("New Text");
42 | mainBtn.setBgColor("#08F7AF");
43 | if (mainBtn.isVisible) {
44 | mainBtn.hide();
45 | } else {
46 | mainBtn.show();
47 | }
48 | };
49 |
50 | mainBtn.on("click", () => {
51 | mainBtn.showLoader();
52 | mainBtn.setText("Action Performing");
53 | setTimeout(() => {
54 | console.log("Main Button Clicked");
55 | mainBtn.hideLoader();
56 | mainBtn.setText("New Text");
57 | mainBtn.hide();
58 | }, 2000);
59 | });
60 |
61 | const handleViewport = async () => {
62 | if (!viewport?.isExpanded) {
63 | viewport?.expand();
64 | }
65 | };
66 | return (
67 |
68 |
69 | Telegram Miniapp Boilerplate
70 |
71 |
72 |
73 |
74 |
75 |
Docs
76 |
77 |
78 |
79 | Find in-depth information on making telegram miniapps for Rabble.
80 |
81 |
82 |
83 |
84 |
Test Modals
85 |
Click to see how modals work
86 |
87 |
90 |
93 |
94 |
95 |
96 |
Test Buttons
97 |
Click to see how buttons work
98 |
99 |
102 |
105 |
106 |
107 |
108 |
109 | );
110 | }
111 |
--------------------------------------------------------------------------------
/public/rabble.svg:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ETH Telegram Mini App Starter Kit
2 |
3 | ## Getting Started
4 |
5 | This starter kit helps you create a mini application integrated with Ethereum and Telegram. Follow the steps below to set up and run the project.
6 |
7 | ## Resources
8 |
9 | [Blog on using this Starter Kit](https://medium.com/rabble-labs/deploy-your-first-telegram-mini-app-on-ethereum-8b589f4e6411)
10 |
11 | **For Visual Learners**
12 | [](https://www.youtube.com/watch?v=cFLKu4sl76I)
13 |
14 | ### Prerequisites
15 |
16 | Ensure you have the following installed on your machine:
17 |
18 | - [Node.js](https://nodejs.org/) (v16 or higher)
19 | - [npm](https://www.npmjs.com/) or [Yarn](https://yarnpkg.com/)
20 |
21 | ### Setup Guide
22 |
23 | 1. **Clone the repository or click on the "Use this template" button:**
24 |
25 | ```bash
26 | git clone https://github.com/HAPPYS1NGH/tg-mini-app-nextjs
27 | ```
28 |
29 | 2. **Navigate to the project directory:**
30 |
31 | ```bash
32 | cd tg-mini-app-nextjs
33 | ```
34 |
35 | 3. **Create a `.env.local` file in the root directory and copy the contents of `.env.sample`:**
36 |
37 | - Obtain the WalletConnect project ID from [Reown](https://cloud.reown.com/).
38 |
39 | - Make sure to select the App Kit.
40 |
41 | ```env
42 | NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID=
43 | ```
44 |
45 | - According change the other environment details to development or production.
46 |
47 | 4. **Install dependencies:**
48 |
49 | Using npm:
50 |
51 | ```bash
52 | npm install
53 | ```
54 |
55 | or using yarn:
56 |
57 | ```bash
58 | yarn install
59 | ```
60 |
61 | 5. **Start the development server:**
62 |
63 | Using npm:
64 |
65 | ```bash
66 | npm run dev
67 | ```
68 |
69 | or using yarn:
70 |
71 | ```bash
72 | yarn dev
73 | ```
74 |
75 | 6. **Open your web browser and navigate to `http://localhost:3000` to view the application.**
76 |
77 | ### Exposing Your Local Server
78 |
79 | To test your application within Telegram, you need to expose your local server using a tunneling service like ngrok or localtunnel.
80 |
81 | **Start the development server:**
82 |
83 | Using npm:
84 |
85 | ```bash
86 | npm run expose
87 | ```
88 |
89 | or using yarn:
90 |
91 | ```bash
92 | yarn expose
93 | ```
94 |
95 | **Alternatively:**
96 |
97 | You can always use ngrok or any proxy service to expose the endpoint.
98 |
99 | ### Registering Your Bot on Telegram while Development
100 |
101 | 1. **Open Telegram and search for `BotFather`.**
102 |
103 | 2. **Register a new bot by using the /newbot command and follow the prompts to choose a name and username.**
104 |
105 | 3. **While in BotFather, use the /setmenubutton command (It may not autocomplete).**
106 |
107 | 4. **Click on the bottom right square to choose the bot**
108 | 
109 |
110 | 5. **Paste the URL for your App in which will be LocalTunnel's during development.**
111 |
112 | 6. **Set the name of the button which will be used to start the mini app.**
113 |
114 | 7. **Go to the Bot and now you can see a small button next to the chat which will bring up the Mini App.**
115 |
116 | 8. **Repeat the steps 3-7 when you have the production URL.**
117 |
118 | ---
119 |
120 | ### Registering Your Bot on Telegram on Production
121 |
122 | 0. **Deploy your App on any Platform like Vercel or Netlify**
123 |
124 | 1. **Open Telegram and search for `BotFather`.**
125 |
126 | 2. **Register a new bot by using the /newbot command and follow the prompts to choose a name and username.**
127 |
128 | 3. **While in BotFather, use the /setmenubutton command (It may not autocomplete).**
129 |
130 | 4. **Click on the bottom right square to choose the bot**
131 | 
132 |
133 | 5. **Paste the Production URL for your App.**
134 |
135 | 6. **Set the name of the button which will be used to start the mini app.**
136 |
137 | 7. **Go to the Bot and now you can see a small button next to the chat which will bring up the Mini App.**
138 |
139 | 8. **Again go to BotFather, use the /setminiapp command (It may not autocomplete) and choose your Bot**
140 |
141 | 9. **Paste the Production URL for your Mini App.**
142 |
143 | 10. **Now you are all set for sharing your Mini App.**
144 |
145 | ## Interacting with Contracts
146 |
147 | This starter kit provides hooks from Wagmi v2 for interacting with smart contracts on the Arbitrum network. You can use these hooks to read and write data to contracts.
148 |
149 | ## Directory Structure
150 |
151 | The project follows a standard directory structure for a Next.js application. Here's an overview:
152 |
153 | ```
154 | .
155 | ├── README.md
156 | ├── components.json
157 | ├── next-env.d.ts
158 | ├── next.config.js
159 | ├── package-lock.json
160 | ├── package.json
161 | ├── postcss.config.js
162 | ├── public
163 | │ ├── arbitrum.svg
164 | │ ├── arrow.svg
165 | │ ├── butterfly.svg
166 | │ ├── loader.svg
167 | │ └── rabble.svg
168 | ├── src
169 | │ ├── app
170 | │ │ ├── contract
171 | │ │ │ └── page.tsx
172 | │ │ ├── favicon.ico
173 | │ │ ├── globals.css
174 | │ │ ├── layout.tsx
175 | │ │ └── page.tsx
176 | │ ├── assets
177 | │ │ └── Arrow.tsx
178 | │ ├── components
179 | │ │ ├── ErrorBoundary.tsx
180 | │ │ ├── ErrorPage.tsx
181 | │ │ ├── Popup.tsx
182 | │ │ ├── shared
183 | │ │ │ └── Navbar.tsx
184 | │ │ └── ui
185 | │ │ ├── button.tsx
186 | │ │ ├── input.tsx
187 | │ │ └── sonner.tsx
188 | │ ├── constants
189 | │ │ ├── abi.ts
190 | │ │ └── index.ts
191 | │ ├── containers
192 | │ │ ├── contract
193 | │ │ │ ├── ReadContract.tsx
194 | │ │ │ └── WriteContract.tsx
195 | │ │ └── home
196 | │ │ └── Profile.tsx
197 | │ ├── hooks
198 | │ │ ├── useClientOnce.ts
199 | │ │ ├── useDidMount.ts
200 | │ │ └── useTelegramMock.ts
201 | │ ├── lib
202 | │ │ └── utils.ts
203 | │ ├── providers
204 | │ │ ├── Layout.tsx
205 | │ │ ├── TelegramProvider.tsx
206 | │ │ └── Web3Provider.tsx
207 | │ └── utils
208 | │ └── config.ts
209 | ├── tailwind.config.ts
210 | └── tsconfig.json
211 | ```
212 |
213 | ## FAQs
214 |
215 | ### What are Telegram Mini Apps?
216 |
217 | Web Apps inside Telegram in the form of a bot.
218 |
219 | ### What is different in Mini Apps?
220 |
221 | Mini Apps offer Telegram-specific UI elements like Main Button, Popups, Telegram Theme Params, and Viewport. They also provide features like Telegram Authentication, Cloud Storage, and more.
222 |
223 | ### Can you tell what all things I need to do to convert my WebApp to a Mini App?
224 |
225 | Your normal website will also work fine in most cases if you do not have in-app links to other domains.
226 |
227 | ## Support
228 |
229 | If you encounter any issues or have questions:
230 |
231 | - **Telegram:** [Rabble Mini App Group](https://t.me/+rFqLyk4_W-diZDZl)
232 | - **Twitter:** [@happys1ngh](https://twitter.com/happys1ngh)
233 | - **GitHub Issues:** [ETH Telegram Mini App Starter Kit Issues](https://github.com/HAPPYS1NGH/tg-mini-app-nextjs/issues)
234 | - **Mini Apps Hackathon:** [MAHa](https://0xmaha.com)
235 |
236 | BUIDL SHOULD NOT STOP!🏗️
237 |
238 | Happy coding! 🚀
239 |
--------------------------------------------------------------------------------