diff --git a/src/routes/-/Header/Header.module.css b/src/routes/-/Header/Header.module.css index 12ee669..ee2a687 100644 --- a/src/routes/-/Header/Header.module.css +++ b/src/routes/-/Header/Header.module.css @@ -1,9 +1,10 @@ :root { --header-height: 90px; - --header-total: calc( - var(--header-height) + var(--tg-safe-area-inset-top, 0px) + - var(--tg-content-safe-area-inset-top, 0px) + --header-padding: calc( + var(--tg-viewport-safe-area-inset-top, 0px) + + var(--tg-viewport-content-safe-area-inset-top, 0px) ); + --header-total: calc(var(--header-height) + var(--header-padding)); } @layer base { @@ -14,9 +15,7 @@ left: 0; z-index: 10; height: var(--header-total); - padding-top: calc( - var(--tg-safe-area-inset-top, 0px) + var(--tg-content-safe-area-inset-top, 0px) - ); + padding-top: var(--header-padding); background: rgb(59 130 246 / 0.3); } } diff --git a/src/routes/-/Navigation/Navigation.module.css b/src/routes/-/Navigation/Navigation.module.css index 118b967..1ffb666 100644 --- a/src/routes/-/Navigation/Navigation.module.css +++ b/src/routes/-/Navigation/Navigation.module.css @@ -1,6 +1,7 @@ :root { --navigation-height: 74px; - --navigation-total: calc(var(--navigation-height) + var(--tg-safe-area-inset-bottom, 0px)); + --navigation-padding: var(--tg-viewport-safe-area-inset-bottom, 0px); + --navigation-total: calc(var(--navigation-height) + var(--navigation-padding)); } @layer base { @@ -33,7 +34,7 @@ flex-direction: column; align-items: center; justify-content: flex-start; - padding-bottom: var(--tg-safe-area-inset-bottom, 0px); + padding-bottom: var(--navigation-padding); } .barActive { diff --git a/src/routes/__root.tsx b/src/routes/__root.tsx index a62918f..167f2f4 100644 --- a/src/routes/__root.tsx +++ b/src/routes/__root.tsx @@ -7,6 +7,7 @@ import { useEffect } from "react"; import { Route as GameRoute } from "./game"; import Header from "./-/Header"; import Navigation from "./-/Navigation"; +import tg from "@/tg"; function AppLayout() { return ( @@ -22,6 +23,17 @@ function AppLayout() { ); } +tg.storage.setItem("authToken", "123"); + +tg.storage + .getItem("authToken") + .then((value) => { + console.log("Success", `$${value}$`); + }) + .catch((error) => { + console.error("Error", error); + }); + export const Route = createRootRoute({ notFoundComponent: () => { const navigate = useNavigate(); diff --git a/src/tg/index.ts b/src/tg/index.ts index 232cb7d..c953a88 100644 --- a/src/tg/index.ts +++ b/src/tg/index.ts @@ -5,9 +5,7 @@ export const STORAGE_KEYS = { } as const; export type StorageKey = (typeof STORAGE_KEYS)[keyof typeof STORAGE_KEYS]; -type WithChecks = { - ifAvailable: (...args: any[]) => { ok: true; data: Result } | { ok: false }; -}; +type TgResult = { ok: true; data: T } | { ok: false }; const isPromise = (value: T | Promise): value is Promise => value && typeof value === "object" && "then" in value && typeof value.then === "function"; @@ -16,26 +14,30 @@ const promisify = (value: T | Promise): Promise => isPromise(value) ? value : Promise.resolve(value); const fallbackImplementation = < - T extends ((...args: any) => any) & WithChecks, - Async extends boolean, - Params extends Parameters, - Result extends T extends WithChecks ? Result : never, - F extends (...args: Params) => Async extends true ? Result | Awaited : Result, + TMain extends (...args: any) => TgResult, + Async extends Extract, { ok: true }>["data"] extends Promise + ? true + : false, + Params extends Parameters, + Result extends Awaited, { ok: true }>["data"]>, + TFallback extends (...args: Params) => Async extends true ? Result | Awaited : Result, >( async: Async, args: Params, - cb: T, - onErr: F, + cb: TMain, + onErr: TFallback, ): Async extends true ? Promise : Awaited => { - const res = cb.ifAvailable.apply(null, args); - const returnValue = (res.ok ? res.data : onErr.apply(null, args)) as Result; + const res = cb.apply(null, args); + const returnValue = ( + res.ok && !import.meta.env.DEV ? res.data : onErr.apply(null, args) + ) as Result; if (!async) return returnValue as Async extends true ? Promise : Awaited; return promisify(returnValue).catch(() => onErr.apply(null, args)) as Async extends true ? Promise : Awaited; }; -export default { +const externalTgApi = { init: () => { tg.setDebug(import.meta.env.DEV); @@ -134,13 +136,18 @@ export default { initData: tg.initData, storage: { async clear() { - return fallbackImplementation(true, [], tg.cloudStorage.clear, localStorage.clear); + return fallbackImplementation( + true, + [], + () => tg.cloudStorage.clear.ifAvailable(), + () => Object.values(STORAGE_KEYS).forEach((key) => localStorage.removeItem(key)), + ); }, async getItem(key: StorageKey, options?: tg.InvokeCustomMethodFpOptions) { return fallbackImplementation( true, [key, options], - tg.cloudStorage.getItem, + (key, options) => tg.cloudStorage.getItem.ifAvailable(key, options), (key) => localStorage.getItem(key) ?? "", ); }, @@ -148,17 +155,22 @@ export default { return fallbackImplementation( true, [key, value, options], - tg.cloudStorage.setItem, - localStorage.setItem, + (key, value, options) => tg.cloudStorage.setItem.ifAvailable(key, value, options), + (key, value) => localStorage.setItem(key, value), ); }, async deleteItem(key: StorageKey, options?: tg.InvokeCustomMethodFpOptions) { return fallbackImplementation( true, [key, options], - tg.cloudStorage.deleteItem, - localStorage.removeItem as typeof tg.cloudStorage.deleteItem, + (key, options) => tg.cloudStorage.deleteItem.ifAvailable(key, options), + (key) => localStorage.removeItem(key as string), ); }, }, }; + +export default externalTgApi; + +// @ts-expect-error +window.TG = externalTgApi;