Skip to content
This repository has been archived by the owner on Jan 7, 2025. It is now read-only.

Commit

Permalink
Actualize template
Browse files Browse the repository at this point in the history
  • Loading branch information
heyqbnk committed Oct 12, 2024
1 parent a607a15 commit 5334682
Show file tree
Hide file tree
Showing 16 changed files with 534 additions and 168 deletions.
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@
},
"dependencies": {
"@solidjs/router": "^0.13.3",
"@telegram-apps/sdk-solid": "^1.0.0",
"@telegram-apps/solid-router-integration": "^1.0.0",
"@telegram-apps/sdk-solid": "^2.0.5",
"@tonconnect/ui": "^2.0.2",
"eruda": "^3.0.1",
"solid-js": "^1.8.17"
"solid-js": "^1.8.17",
"vite-plugin-mkcert": "^1.17.6"
},
"devDependencies": {
"@babel/core": "^7.24.4",
Expand Down
319 changes: 297 additions & 22 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

49 changes: 5 additions & 44 deletions src/components/App.jsx
Original file line number Diff line number Diff line change
@@ -1,54 +1,15 @@
import { Navigate, Route } from '@solidjs/router';
import {
initNavigator,
bindMiniAppCSSVars,
bindThemeParamsCSSVars,
bindViewportCSSVars,
useMiniApp,
useThemeParams,
useViewport,
} from '@telegram-apps/sdk-solid';
import { createRouter } from '@telegram-apps/solid-router-integration';
import { createEffect, For, onCleanup } from 'solid-js';
import { Navigate, Route, HashRouter } from '@solidjs/router';
import { For } from 'solid-js';

import { routes } from '@/navigation/routes.jsx';

/**
* @returns {Node | JSX.ArrayElement | string | number | boolean}
*/
export function App() {
const miniApp = useMiniApp();
const themeParams = useThemeParams();
const viewport = useViewport();

createEffect(() => {
onCleanup(bindMiniAppCSSVars(miniApp(), themeParams()));
});
createEffect(() => {
onCleanup(bindThemeParamsCSSVars(themeParams()));
});
createEffect(() => {
const vp = viewport();
vp && onCleanup(bindViewportCSSVars(vp));
});

// Create new application navigator and attach it to the browser history, so it could modify
// it and listen to its changes.
const navigator = initNavigator('app-navigator-state');
void navigator.attach();

onCleanup(() => {
navigator.detach();
});

const Router = createRouter(navigator);

return (
<Router>
<HashRouter>
<For each={routes}>
{(route) => <Route path={route.path} component={route.Component}/>}
</For>
<Route path='*' component={() => <Navigate href='/'/>}/>
</Router>
<Route path="*" component={() => <Navigate href="/"/>}/>
</HashRouter>
);
}
9 changes: 2 additions & 7 deletions src/components/Link/Link.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { A } from '@solidjs/router';
import { classNames, useUtils } from '@telegram-apps/sdk-solid';
import { classNames, openLink } from '@telegram-apps/sdk-solid';

import './Link.css';

Expand All @@ -8,11 +8,6 @@ import './Link.css';
* @return {import('solid-js').JSXElement}
*/
export function Link(props) {
const utils = useUtils();

/**
* @param {MouseEvent} e
*/
const onClick = (e) => {
// Compute if target path is external. In this case we would like to open link using
// TMA method.
Expand All @@ -23,7 +18,7 @@ export function Link(props) {

if (isExternal) {
e.preventDefault();
return utils().openLink(targetUrl.toString());
openLink(targetUrl.toString());
}
};

Expand Down
28 changes: 17 additions & 11 deletions src/components/Page/Page.jsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
import './Page.css';
import { createEffect } from 'solid-js';
import { backButton } from '@telegram-apps/sdk-solid';

import { useNavigate } from '@solidjs/router';

/**
* @typedef PageProps
* @property {String} title
* @property {import('solid-js').JSXElement} [disclaimer]
* @property {import('solid-js').JSXElement} [children]
*/
import './Page.css';

/**
* @param {PageProps} props
* @return {import('solid-js').JSXElement}
*/
export function Page(props) {
const navigate = useNavigate();

createEffect(() => {
if (props.back) {
backButton.show();
return backButton.onClick(() => {
navigate(-1);
});
}
backButton.hide();
});

return (
<div class="page">
<h1>{props.title}</h1>
Expand Down
66 changes: 22 additions & 44 deletions src/components/Root.jsx
Original file line number Diff line number Diff line change
@@ -1,58 +1,36 @@
import { retrieveLaunchParams, SDKProvider } from '@telegram-apps/sdk-solid';
import { ErrorBoundary, Switch, Match } from 'solid-js';

import { App } from '@/components/App.jsx';
import { TonConnectUIProvider } from '@/tonconnect/TonConnectUIProvider.jsx';
import { publicUrl } from '@/helpers/publicUrl.js';

/**
* @returns {Node | JSX.ArrayElement | string | number | boolean}
*/
function Inner() {
const debug = retrieveLaunchParams().startParam === 'debug';
if (debug) {
import('eruda').then((lib) => lib.default.init());
}

function ErrorBoundaryError(props) {
return (
<TonConnectUIProvider
manifestUrl={new URL('tonconnect-manifest.json', window.location.href).toString()}
>
<SDKProvider acceptCustomStyles={true} debug={debug}>
<App/>
</SDKProvider>
</TonConnectUIProvider>
<div>
<p>ErrorBoundary handled error:</p>
<blockquote>
<code>
<Switch fallback={JSON.stringify(props.error)}>
<Match when={typeof props.error === 'string' ? props.error : false}>
{v => v()}
</Match>
<Match
when={props.error instanceof Error ? props.error.message : false}>
{v => v()}
</Match>
</Switch>
</code>
</blockquote>
</div>
);
}

/**
* @returns {Node | JSX.ArrayElement | string | number | boolean}
*/
export function Root() {
return (
<ErrorBoundary
fallback={err => {
console.error('ErrorBoundary handled error:', err);

return (
<div>
<p>ErrorBoundary handled error:</p>
<blockquote>
<code>
<Switch fallback={JSON.stringify(err)}>
<Match when={typeof err === 'string' ? err : false}>
{v => v()}
</Match>
<Match when={err instanceof Error ? err.message : false}>
{v => v()}
</Match>
</Switch>
</code>
</blockquote>
</div>
);
}}
>
<Inner/>
<ErrorBoundary fallback={ErrorBoundaryError}>
<TonConnectUIProvider manifestUrl={publicUrl('tonconnect-manifest.json')}>
<App/>
</TonConnectUIProvider>
</ErrorBoundary>
);
}
11 changes: 11 additions & 0 deletions src/helpers/publicUrl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* @returns A complete public URL prefixed with the public static assets base
* path.
* @param path - path to prepend prefix to
*/
export function publicUrl(path) {
return new URL(
path.replace(/^\/+/, ''),
window.location.origin + import.meta.env.BASE_URL
).toString();
}
8 changes: 8 additions & 0 deletions src/index.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
/* @refresh reload */
import { render } from 'solid-js/web';
import { retrieveLaunchParams } from '@telegram-apps/sdk-solid';

import { Root } from '@/components/Root.jsx';
import { init } from '@/init.js';

import './index.css';

// Mock the environment in case, we are outside Telegram.
import './mockEnv.js';

// Configure all application dependencies.
init(retrieveLaunchParams().startParam === 'debug' || import.meta.env.DEV);

const root = document.getElementById('root');

if (import.meta.env.DEV && !(root instanceof HTMLElement)) {
Expand Down
40 changes: 40 additions & 0 deletions src/init.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import {
backButton,
viewport,
themeParams,
miniApp,
initData,
$debug,
init as initSDK,
} from '@telegram-apps/sdk-solid';

/**
* Initializes the application and configures its dependencies.
*/
export function init(debug) {
// Set @telegram-apps/sdk-react debug mode.
$debug.set(debug);

// Initialize special event handlers for Telegram Desktop, Android, iOS, etc.
// Also, configure the package.
initSDK();

// Mount all components used in the project.
backButton.isSupported() && backButton.mount();
miniApp.mount();
themeParams.mount();
initData.restore();
void viewport.mount().catch(e => {
console.error('Something went wrong mounting the viewport', e);
});

// Define components-related CSS variables.
viewport.bindCssVars();
miniApp.bindCssVars();
themeParams.bindCssVars();

// Add Eruda if needed.
debug && import('eruda')
.then((lib) => lib.default.init())
.catch(console.error);
}
70 changes: 70 additions & 0 deletions src/mockEnv.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import {
mockTelegramEnv,
isTMA,
parseInitData,
retrieveLaunchParams
} from '@telegram-apps/sdk-solid';

// It is important, to mock the environment only for development purposes.
// When building the application the import.meta.env.DEV will value become
// `false` and the code inside will be tree-shaken (removed), so you will not
// see it in your final bundle.
if (import.meta.env.DEV) {
await (async () => {
if (await isTMA()) {
return;
}

// Determine which launch params should be applied. We could already
// apply them previously, or they may be specified on purpose using the
// default launch parameters transmission method.
let lp;
try {
lp = retrieveLaunchParams();
} catch (e) {
const initDataRaw = new URLSearchParams([
['user', JSON.stringify({
id: 99281932,
first_name: 'Andrew',
last_name: 'Rogue',
username: 'rogue',
language_code: 'en',
is_premium: true,
allows_write_to_pm: true,
})],
['hash', '89d6079ad6762351f38c6dbbc41bb53048019256a9443988af7a48bcad16ba31'],
['auth_date', '1716922846'],
['start_param', 'debug'],
['chat_type', 'sender'],
['chat_instance', '8428209589180549439'],
]).toString();

lp = {
themeParams: {
accentTextColor: '#6ab2f2',
bgColor: '#17212b',
buttonColor: '#5288c1',
buttonTextColor: '#ffffff',
destructiveTextColor: '#ec3942',
headerBgColor: '#17212b',
hintColor: '#708499',
linkColor: '#6ab3f3',
secondaryBgColor: '#232e3c',
sectionBgColor: '#17212b',
sectionHeaderTextColor: '#6ab3f3',
subtitleTextColor: '#708499',
textColor: '#f5f5f5',
},
initData: parseInitData(initDataRaw),
initDataRaw,
version: '8',
platform: 'tdesktop',
}
}

mockTelegramEnv(lp);
console.warn(
'⚠️ 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.',
);
})();
}
2 changes: 1 addition & 1 deletion src/pages/IndexPage/IndexPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import './IndexPage.css';

export function IndexPage() {
return (
<Page title="Home Page">
<Page title="Home Page" back>
<p>
This page is a home page in this boilerplate. You can use the links below to visit other
pages with their own functionality.
Expand Down
Loading

0 comments on commit 5334682

Please sign in to comment.