├── .gitignore ├── dist ├── css │ ├── link.css │ ├── page.css │ ├── initDataPage.css │ ├── rgb.css │ ├── tonConnectPage.css │ ├── homePage.css │ ├── displayData.css │ ├── walletProvider.css │ └── index.css ├── tonconnect-manifest.json ├── js │ ├── utils.js │ ├── initTonConnect.js │ ├── components │ │ ├── PageComponent.js │ │ ├── TonConnectButton.js │ │ ├── RGB.js │ │ ├── Page.js │ │ ├── Link.js │ │ ├── DisplayData.js │ │ └── WalletProvider.js │ ├── initNavigrator.js │ ├── initComponents.js │ ├── pages │ │ ├── HomePage.js │ │ ├── LaunchParamsPage.js │ │ ├── ThemeParamsPage.js │ │ ├── TonConnectPage.js │ │ └── InitDataPage.js │ ├── mockEnv.js │ └── index.js ├── ton.svg └── index.html ├── .github ├── deployment-branches.png └── workflows │ └── github-pages-deploy.yml ├── package.json ├── README.md └── pnpm-lock.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | node_modules 3 | -------------------------------------------------------------------------------- /dist/css/link.css: -------------------------------------------------------------------------------- 1 | .link { 2 | text-decoration: none; 3 | color: var(--tg-theme-link-color); 4 | } -------------------------------------------------------------------------------- /.github/deployment-branches.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Telegram-Mini-Apps/vanillajs-template/HEAD/.github/deployment-branches.png -------------------------------------------------------------------------------- /dist/tonconnect-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://ton.vote", 3 | "name": "TON Vote", 4 | "iconUrl": "https://ton.vote/logo.png" 5 | } -------------------------------------------------------------------------------- /dist/css/page.css: -------------------------------------------------------------------------------- 1 | .page { 2 | padding: 0 10px; 3 | box-sizing: border-box; 4 | } 5 | 6 | .page__disclaimer { 7 | margin-bottom: 16px; 8 | } -------------------------------------------------------------------------------- /dist/css/initDataPage.css: -------------------------------------------------------------------------------- 1 | .init-data-page__section + .init-data-page__section { 2 | margin-top: 12px; 3 | } 4 | 5 | .init-data-page__section-title { 6 | margin-bottom: 4px; 7 | } -------------------------------------------------------------------------------- /dist/css/rgb.css: -------------------------------------------------------------------------------- 1 | .rgb { 2 | display: inline-flex; 3 | align-items: center; 4 | gap: 5px; 5 | } 6 | 7 | .rgb__icon { 8 | width: 18px; 9 | aspect-ratio: 1; 10 | border: 1px solid #555; 11 | border-radius: 50%; 12 | } -------------------------------------------------------------------------------- /dist/css/tonConnectPage.css: -------------------------------------------------------------------------------- 1 | .ton-connect-page__button-container { 2 | display: flex; 3 | align-items: center; 4 | justify-content: flex-end; 5 | } 6 | 7 | .ton-connect-page__provider { 8 | margin-bottom: 16px; 9 | } 10 | -------------------------------------------------------------------------------- /dist/js/utils.js: -------------------------------------------------------------------------------- 1 | function filterChildren(children) { 2 | return children.filter(function(c) { 3 | return c !== undefined && c !== null && typeof c !== 'boolean'; 4 | }); 5 | } 6 | 7 | function toArray(elem) { 8 | return Array.isArray(elem) ? elem : [elem]; 9 | } -------------------------------------------------------------------------------- /dist/js/initTonConnect.js: -------------------------------------------------------------------------------- 1 | function initTonConnectUI() { 2 | const tonConnectUI = new window.TON_CONNECT_UI.TonConnectUI({ 3 | manifestUrl: new URL('/vanillajs-template/tonconnect-manifest.json', window.location.href).toString(), 4 | }); 5 | 6 | return tonConnectUI; 7 | } -------------------------------------------------------------------------------- /dist/js/components/PageComponent.js: -------------------------------------------------------------------------------- 1 | function PageComponent(page) { 2 | this.page = page; 3 | } 4 | 5 | /** 6 | * @param {HTMLElement} root 7 | * @returns {void} 8 | */ 9 | PageComponent.prototype.render = function(root) { 10 | $(root).empty().append(this.page.element()); 11 | }; -------------------------------------------------------------------------------- /dist/js/initNavigrator.js: -------------------------------------------------------------------------------- 1 | function initNavigator() { 2 | return new Promise(function(resolve) { 3 | var navigator = window.telegramApps.sdk.initNavigator('app-navigator-state'); 4 | 5 | // Attach the navigator to the browser history, so it could modify the history and listen to 6 | // its changes. 7 | navigator.attach().then(function() { 8 | resolve(navigator); 9 | }); 10 | }); 11 | } -------------------------------------------------------------------------------- /dist/css/homePage.css: -------------------------------------------------------------------------------- 1 | .index-page__links { 2 | list-style: none; 3 | padding-left: 0; 4 | } 5 | 6 | .index-page__link { 7 | font-weight: bold; 8 | display: inline-flex; 9 | gap: 5px; 10 | } 11 | 12 | .index-page__link-item + .index-page__link-item { 13 | margin-top: 10px; 14 | } 15 | 16 | .index-page__link-icon { 17 | width: 20px; 18 | display: block; 19 | } 20 | 21 | .index-page__link-icon svg { 22 | display: block; 23 | } -------------------------------------------------------------------------------- /dist/css/displayData.css: -------------------------------------------------------------------------------- 1 | .display-data__line { 2 | display: flex; 3 | align-items: center; 4 | margin-bottom: 8px; 5 | gap: 10px; 6 | flex-flow: wrap; 7 | } 8 | 9 | .display-data__line-title { 10 | border: 1px solid var(--tg-theme-accent-text-color); 11 | background-color: var(--tg-theme-bg-color); 12 | border-radius: 5px; 13 | padding: 2px 8px 4px; 14 | box-sizing: border-box; 15 | } 16 | 17 | .display-data__line-value { 18 | word-break: break-word; 19 | } -------------------------------------------------------------------------------- /dist/js/components/TonConnectButton.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {{ id: string, class?: string }} options 3 | */ 4 | function TonConnectButton(options) { 5 | var id = options.id; 6 | var className = options.class; 7 | 8 | this.el = $('
') 9 | .addClass(className || '') 10 | .append($('
').attr('id', id)); 11 | } 12 | 13 | /** 14 | * @returns {HTMLDivElement} 15 | */ 16 | TonConnectButton.prototype.element = function() { 17 | return this.el[0]; 18 | }; -------------------------------------------------------------------------------- /dist/css/walletProvider.css: -------------------------------------------------------------------------------- 1 | .wallet-provider { 2 | display: flex; 3 | align-items: center; 4 | gap: 15px; 5 | } 6 | 7 | .wallet-provider__image { 8 | border-radius: 5px; 9 | } 10 | 11 | .wallet-provider__meta { 12 | display: flex; 13 | flex-direction: column; 14 | } 15 | 16 | .wallet-provider__wallet-name { 17 | font-weight: bold; 18 | font-size: 20px; 19 | margin: 0; 20 | } 21 | 22 | .wallet-provider__app-name { 23 | opacity: .4; 24 | font-weight: 400; 25 | font-size: 14px; 26 | vertical-align: top; 27 | } -------------------------------------------------------------------------------- /dist/js/components/RGB.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {{ color: string; class?: string }} options 3 | */ 4 | function RGB(options) { 5 | var color = options.color; 6 | var className = options.class; 7 | 8 | this.el = $('') 9 | .attr('class', 'rgb') 10 | .addClass(className || '') 11 | .append( 12 | $('').css('background-color', color), 13 | color 14 | ); 15 | } 16 | 17 | /** 18 | * @returns {HTMLSpanElement} 19 | */ 20 | RGB.prototype.element = function() { 21 | return this.el[0]; 22 | }; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vanillajs-template", 3 | "description": "Telegram Mini Apps application template using JavaScript.", 4 | "private": true, 5 | "version": "0.0.1", 6 | "main": "index.html", 7 | "homepage": "https://telegram-mini-apps.github.io/vanillajs-template", 8 | "scripts": { 9 | "deploy": "gh-pages -d dist", 10 | "serve": "serve ./dist", 11 | "tunnel": "lt --port 3000" 12 | }, 13 | "keywords": [], 14 | "author": "Vladislav Kibenko", 15 | "license": "MIT", 16 | "devDependencies": { 17 | "gh-pages": "^6.1.1", 18 | "localtunnel": "^2.0.2", 19 | "serve": "^14.2.1" 20 | } 21 | } -------------------------------------------------------------------------------- /dist/css/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: -apple-system, BlinkMacSystemFont, 'Roboto', 'Oxygen', 3 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 4 | sans-serif; 5 | -webkit-font-smoothing: antialiased; 6 | -moz-osx-font-smoothing: grayscale; 7 | line-height: 1.5; 8 | 9 | background: var(--tg-theme-secondary-bg-color, white); 10 | color: var(--tg-theme-text-color, black); 11 | } 12 | 13 | blockquote { 14 | margin: 0; 15 | } 16 | 17 | blockquote p { 18 | padding: 15px; 19 | background: #eee; 20 | border-radius: 5px; 21 | } 22 | 23 | pre { 24 | overflow: auto; 25 | } 26 | 27 | h1 { 28 | margin-top: 0.67em; 29 | } -------------------------------------------------------------------------------- /dist/ton.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | -------------------------------------------------------------------------------- /dist/js/components/Page.js: -------------------------------------------------------------------------------- 1 | function Page(options) { 2 | var title = options.title; 3 | this.el = $('
').append($('

').text(title)); 4 | } 5 | 6 | Page.prototype.appendChild = function() { 7 | var children = Array.prototype.slice.call(arguments); 8 | this.el.append.apply(this.el, filterChildren(children)); 9 | return this; 10 | }; 11 | 12 | /** 13 | * @returns {HTMLDivElement} 14 | */ 15 | Page.prototype.element = function() { 16 | return this.el[0]; 17 | }; 18 | 19 | Page.prototype.setDisclaimer = function(disclaimer) { 20 | if (this.disclaimer) { 21 | this.disclaimer.empty().append.apply(this.disclaimer, toArray(disclaimer)); 22 | } else { 23 | var disclaimerEl = $('
'); 24 | this.disclaimer = disclaimerEl 25 | .append.apply(disclaimerEl, toArray(disclaimer)) 26 | .insertAfter(this.el.children('h1')); 27 | } 28 | return this; 29 | }; -------------------------------------------------------------------------------- /dist/js/initComponents.js: -------------------------------------------------------------------------------- 1 | function initComponents() { 2 | return new Promise(function(resolve, reject) { 3 | var miniApp = window.telegramApps.sdk.initMiniApp()[0]; 4 | var themeParams = window.telegramApps.sdk.initThemeParams()[0]; 5 | var utils = window.telegramApps.sdk.initUtils(); 6 | var initData = window.telegramApps.sdk.initInitData(); 7 | var viewportPromise = window.telegramApps.sdk.initViewport()[0]; 8 | 9 | viewportPromise.then(function(viewport) { 10 | // Generate Mini Apps related CSS-variables and track their changes. 11 | window.telegramApps.sdk.bindMiniAppCSSVars(miniApp, themeParams); 12 | window.telegramApps.sdk.bindThemeParamsCSSVars(themeParams); 13 | window.telegramApps.sdk.bindViewportCSSVars(viewport); 14 | 15 | resolve({ 16 | initData: initData, 17 | miniApp: miniApp, 18 | themeParams: themeParams, 19 | utils: utils, 20 | viewport: viewport, 21 | }); 22 | }).catch(reject); 23 | }); 24 | } -------------------------------------------------------------------------------- /dist/js/components/Link.js: -------------------------------------------------------------------------------- 1 | function Link(options, context) { 2 | var href = options.href; 3 | var className = options.class; 4 | 5 | var targetUrl = new URL(href, window.location.toString()); 6 | var currentUrl = new URL(window.location.toString()); 7 | var isExternal = targetUrl.protocol !== currentUrl.protocol || targetUrl.host !== currentUrl.host; 8 | 9 | this.el = $('') 10 | .attr('class', 'link') 11 | .addClass(className || '') 12 | .attr('href', isExternal ? href : context.navigator.renderPath(href)); 13 | 14 | if (isExternal) { 15 | this.el.on('click', function(e) { 16 | e.preventDefault(); 17 | context.utils.openLink(targetUrl.toString()); 18 | }); 19 | } 20 | } 21 | 22 | Link.prototype.appendChild = function() { 23 | var children = Array.prototype.slice.call(arguments); 24 | this.el.append.apply(this.el, filterChildren(children)); 25 | return this; 26 | }; 27 | 28 | /** 29 | * @returns {HTMLAnchorElement} 30 | */ 31 | Link.prototype.element = function() { 32 | return this.el[0]; 33 | }; -------------------------------------------------------------------------------- /dist/js/pages/HomePage.js: -------------------------------------------------------------------------------- 1 | function HomePage(context) { 2 | var routes = context.routes; 3 | 4 | this.page = new Page({ title: 'Home Page' }).appendChild( 5 | $('

').text( 6 | 'This page is a home page in this boilerplate. You can use the links below to visit other pages with their own functionality.' 7 | ), 8 | $('