fix: tg safe area
All checks were successful
Deploy to VPS (dist) / deploy (push) Successful in 2m10s

This commit is contained in:
Hewston Fox
2026-03-18 23:06:36 +02:00
parent 43e52e7585
commit a1f6c57901
4 changed files with 51 additions and 27 deletions

View File

@@ -1,9 +1,10 @@
:root { :root {
--header-height: 90px; --header-height: 90px;
--header-total: calc( --header-padding: calc(
var(--header-height) + var(--tg-safe-area-inset-top, 0px) + var(--tg-viewport-safe-area-inset-top, 0px) +
var(--tg-content-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 { @layer base {
@@ -14,9 +15,7 @@
left: 0; left: 0;
z-index: 10; z-index: 10;
height: var(--header-total); height: var(--header-total);
padding-top: calc( padding-top: var(--header-padding);
var(--tg-safe-area-inset-top, 0px) + var(--tg-content-safe-area-inset-top, 0px)
);
background: rgb(59 130 246 / 0.3); background: rgb(59 130 246 / 0.3);
} }
} }

View File

@@ -1,6 +1,7 @@
:root { :root {
--navigation-height: 74px; --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 { @layer base {
@@ -33,7 +34,7 @@
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: flex-start; justify-content: flex-start;
padding-bottom: var(--tg-safe-area-inset-bottom, 0px); padding-bottom: var(--navigation-padding);
} }
.barActive { .barActive {

View File

@@ -7,6 +7,7 @@ import { useEffect } from "react";
import { Route as GameRoute } from "./game"; import { Route as GameRoute } from "./game";
import Header from "./-/Header"; import Header from "./-/Header";
import Navigation from "./-/Navigation"; import Navigation from "./-/Navigation";
import tg from "@/tg";
function AppLayout() { function AppLayout() {
return ( 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({ export const Route = createRootRoute({
notFoundComponent: () => { notFoundComponent: () => {
const navigate = useNavigate(); const navigate = useNavigate();

View File

@@ -5,9 +5,7 @@ export const STORAGE_KEYS = {
} as const; } as const;
export type StorageKey = (typeof STORAGE_KEYS)[keyof typeof STORAGE_KEYS]; export type StorageKey = (typeof STORAGE_KEYS)[keyof typeof STORAGE_KEYS];
type WithChecks<Result> = { type TgResult<T> = { ok: true; data: T } | { ok: false };
ifAvailable: (...args: any[]) => { ok: true; data: Result } | { ok: false };
};
const isPromise = <T>(value: T | Promise<T>): value is Promise<T> => const isPromise = <T>(value: T | Promise<T>): value is Promise<T> =>
value && typeof value === "object" && "then" in value && typeof value.then === "function"; value && typeof value === "object" && "then" in value && typeof value.then === "function";
@@ -16,26 +14,30 @@ const promisify = <T>(value: T | Promise<T>): Promise<T> =>
isPromise(value) ? value : Promise.resolve(value); isPromise(value) ? value : Promise.resolve(value);
const fallbackImplementation = < const fallbackImplementation = <
T extends ((...args: any) => any) & WithChecks<any>, TMain extends (...args: any) => TgResult<any>,
Async extends boolean, Async extends Extract<ReturnType<TMain>, { ok: true }>["data"] extends Promise<any>
Params extends Parameters<T>, ? true
Result extends T extends WithChecks<infer Result> ? Result : never, : false,
F extends (...args: Params) => Async extends true ? Result | Awaited<Result> : Result, Params extends Parameters<TMain>,
Result extends Awaited<Extract<ReturnType<TMain>, { ok: true }>["data"]>,
TFallback extends (...args: Params) => Async extends true ? Result | Awaited<Result> : Result,
>( >(
async: Async, async: Async,
args: Params, args: Params,
cb: T, cb: TMain,
onErr: F, onErr: TFallback,
): Async extends true ? Promise<Result> : Awaited<Result> => { ): Async extends true ? Promise<Result> : Awaited<Result> => {
const res = cb.ifAvailable.apply(null, args); const res = cb.apply(null, args);
const returnValue = (res.ok ? res.data : onErr.apply(null, args)) as Result; 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<Result> : Awaited<Result>; if (!async) return returnValue as Async extends true ? Promise<Result> : Awaited<Result>;
return promisify(returnValue).catch(() => onErr.apply(null, args)) as Async extends true return promisify(returnValue).catch(() => onErr.apply(null, args)) as Async extends true
? Promise<Result> ? Promise<Result>
: Awaited<Result>; : Awaited<Result>;
}; };
export default { const externalTgApi = {
init: () => { init: () => {
tg.setDebug(import.meta.env.DEV); tg.setDebug(import.meta.env.DEV);
@@ -134,13 +136,18 @@ export default {
initData: tg.initData, initData: tg.initData,
storage: { storage: {
async clear() { 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) { async getItem(key: StorageKey, options?: tg.InvokeCustomMethodFpOptions) {
return fallbackImplementation( return fallbackImplementation(
true, true,
[key, options], [key, options],
tg.cloudStorage.getItem, (key, options) => tg.cloudStorage.getItem.ifAvailable(key, options),
(key) => localStorage.getItem(key) ?? "", (key) => localStorage.getItem(key) ?? "",
); );
}, },
@@ -148,17 +155,22 @@ export default {
return fallbackImplementation( return fallbackImplementation(
true, true,
[key, value, options], [key, value, options],
tg.cloudStorage.setItem, (key, value, options) => tg.cloudStorage.setItem.ifAvailable(key, value, options),
localStorage.setItem, (key, value) => localStorage.setItem(key, value),
); );
}, },
async deleteItem(key: StorageKey, options?: tg.InvokeCustomMethodFpOptions) { async deleteItem(key: StorageKey, options?: tg.InvokeCustomMethodFpOptions) {
return fallbackImplementation( return fallbackImplementation(
true, true,
[key, options], [key, options],
tg.cloudStorage.deleteItem, (key, options) => tg.cloudStorage.deleteItem.ifAvailable(key, options),
localStorage.removeItem as typeof tg.cloudStorage.deleteItem, (key) => localStorage.removeItem(key as string),
); );
}, },
}, },
}; };
export default externalTgApi;
// @ts-expect-error
window.TG = externalTgApi;