Added deeplinks, added qr code login, added settings, other stuff
This commit is contained in:
parent
462fc19591
commit
8ff8bd9528
32 changed files with 917 additions and 78 deletions
|
|
@ -7,31 +7,31 @@ import { SidebarProvider } from "@tensamin/ui/cmp/sidebar";
|
|||
import { useIsMobile, cn } from "@tensamin/ui/utils";
|
||||
|
||||
import { isTauri } from "@tauri-apps/api/core";
|
||||
import { useLocation } from "@tanstack/react-router";
|
||||
import { useLocation, useMatches } from "@tanstack/react-router";
|
||||
|
||||
/**
|
||||
* Executes Layout.
|
||||
* @param props Parameter props.
|
||||
* @returns unknown.
|
||||
*/
|
||||
export default function Layout(props: { children: ReactNode }) {
|
||||
export default function Layout({ children }: { children: ReactNode }) {
|
||||
const isMobile = useIsMobile();
|
||||
const location = useLocation();
|
||||
const showMobileNavbar = useShowMobileNavbar();
|
||||
|
||||
return (
|
||||
<div className="w-full h-full flex bg-sidebar">
|
||||
<SidebarProvider>
|
||||
<Sidebar />
|
||||
<div
|
||||
// Background of ui that is overlapping with the system ui
|
||||
className={cn(
|
||||
"w-full h-full flex flex-col",
|
||||
isTauri() && isMobile && "pt-[env(safe-area-inset-top)]",
|
||||
isMobile && showMobileNavbar && "bg-background",
|
||||
)}
|
||||
>
|
||||
{!isMobile && <Navbar forMobile={false} />}
|
||||
{isMobile && location.pathname === "/chat" && (
|
||||
<Navbar forMobile={true} />
|
||||
)}
|
||||
{isMobile && !showMobileNavbar && <Navbar forMobile={true} />}
|
||||
|
||||
<div
|
||||
className={cn(
|
||||
|
|
@ -39,11 +39,26 @@ export default function Layout(props: { children: ReactNode }) {
|
|||
!isMobile && "rounded-tl-3xl border-t border-l",
|
||||
)}
|
||||
>
|
||||
{props.children}
|
||||
{children}
|
||||
</div>
|
||||
{isMobile && location.pathname !== "/chat" && <MobileNavbar />}
|
||||
|
||||
{isMobile && showMobileNavbar && <MobileNavbar />}
|
||||
</div>
|
||||
</SidebarProvider>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function useShowMobileNavbar(): boolean {
|
||||
const matches = useMatches();
|
||||
const location = useLocation();
|
||||
|
||||
const value = matches.some(
|
||||
(match) =>
|
||||
match.pathname === location.pathname &&
|
||||
// @ts-expect-error Stuff
|
||||
match.staticData?.showMobileNavbar === true,
|
||||
);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
|
|
|||
12
apps/web/src/routes/settings/chat.tsx
Normal file
12
apps/web/src/routes/settings/chat.tsx
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import { Switch } from "@/features/settings/components";
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<div>
|
||||
<Switch
|
||||
label="Reverse Enter Key Behavior"
|
||||
id="settings.reverse_enter_behavior"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
7
apps/web/src/routes/settings/index.tsx
Normal file
7
apps/web/src/routes/settings/index.tsx
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import { SettingsSidebar } from "@/features/settings/layout";
|
||||
import { useIsMobile } from "@tensamin/ui/utils";
|
||||
|
||||
export default function Page() {
|
||||
const isMobile = useIsMobile();
|
||||
return isMobile && <SettingsSidebar />;
|
||||
}
|
||||
111
apps/web/src/routes/settings/security.tsx
Normal file
111
apps/web/src/routes/settings/security.tsx
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
import { useStorage } from "@tensamin/storage/context";
|
||||
import { useEffect, useState } from "react";
|
||||
import QRCode from "qrcode";
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogAction,
|
||||
AlertDialogCancel,
|
||||
AlertDialogContent,
|
||||
AlertDialogDescription,
|
||||
AlertDialogFooter,
|
||||
AlertDialogHeader,
|
||||
AlertDialogTitle,
|
||||
AlertDialogTrigger,
|
||||
} from "@tensamin/ui/cmp/alert-dialog";
|
||||
import { Button } from "@tensamin/ui/cmp/button";
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<div>
|
||||
<QrCodeLogin />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// QR Code Login
|
||||
const generateQR = async (text: string): Promise<string> => {
|
||||
try {
|
||||
const url = await QRCode.toDataURL(text, {
|
||||
errorCorrectionLevel: "H",
|
||||
margin: 1,
|
||||
color: {
|
||||
dark: "#000000FF",
|
||||
light: "#FFFFFFFF",
|
||||
},
|
||||
});
|
||||
return url;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
function QrCodeLogin() {
|
||||
const { load } = useStorage();
|
||||
const [userId, setUserId] = useState<number>(0);
|
||||
const [privateKey, setPrivateKey] = useState<string>("");
|
||||
const [qrCodeBase64, setQrCodeBase64] = useState<string | undefined>(
|
||||
undefined,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
load("private_key").then((value) => {
|
||||
if (value) {
|
||||
setPrivateKey(value);
|
||||
}
|
||||
});
|
||||
load("user_id").then((value) => {
|
||||
if (value) {
|
||||
setUserId(value);
|
||||
}
|
||||
});
|
||||
}, [load]);
|
||||
|
||||
useEffect(() => {
|
||||
if (userId && privateKey) {
|
||||
generateQR(`tensamin://tu::${userId}::${privateKey}`).then(
|
||||
setQrCodeBase64,
|
||||
);
|
||||
}
|
||||
}, [userId, privateKey]);
|
||||
|
||||
const [qrCodeVisible, setQrCodeVisible] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="relative rounded-lg w-50 border-3 aspect-square overflow-hidden">
|
||||
{qrCodeBase64 && (
|
||||
<img className="w-full h-full" src={qrCodeBase64} alt="QR Code" />
|
||||
)}
|
||||
{!qrCodeVisible && (
|
||||
<>
|
||||
<div className="absolute top-0 left-0 w-full h-full backdrop-blur-sm bg-background/50" />
|
||||
<div className="absolute top-0 left-0 w-full h-full flex items-center justify-center">
|
||||
<AlertDialog>
|
||||
<AlertDialogTrigger render={<Button>Show QR Code</Button>} />
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>Are you sure?</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
This will expose your private key! This is the same as
|
||||
sharing the .tu file! It's very tedious to change the
|
||||
private key, so only do this if you are sure no one can
|
||||
steal it!
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
||||
<AlertDialogAction
|
||||
render={
|
||||
<Button onClick={() => setQrCodeVisible(true)}>
|
||||
Show QR Code
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Loading…
Reference in a new issue