alternative tangled frontend (extremely wip)

chore: prettier

serenity f5d65204 3cc3215f

+171 -159
+12 -12
src/components/Animated/UnderlinedLink.tsx
··· 1 - import { motion } from 'motion/react' 2 - import { ReactNode } from 'react' 3 4 export const UnderlineLink = ({ 5 href, 6 children, 7 - className = 'text-[#cba6f7]', 8 - underlineColor = 'bg-[#cba6f7]', 9 }: { 10 - href: string 11 - children: ReactNode 12 - className?: string 13 - underlineColor?: string 14 }) => { 15 return ( 16 <motion.a ··· 21 > 22 {children} 23 <motion.span 24 - className={`absolute bottom-1 left-0 w-full h-0.25 origin-center ${underlineColor}`} 25 variants={{ 26 initial: { scaleX: 0 }, 27 hover: { scaleX: 1 }, 28 }} 29 transition={{ 30 - type: 'spring', 31 duration: 0.25, 32 bounce: 0.3, 33 }} 34 /> 35 </motion.a> 36 - ) 37 - }
··· 1 + import { motion } from "motion/react"; 2 + import { ReactNode } from "react"; 3 4 export const UnderlineLink = ({ 5 href, 6 children, 7 + className = "text-[#cba6f7]", 8 + underlineColor = "bg-[#cba6f7]", 9 }: { 10 + href: string; 11 + children: ReactNode; 12 + className?: string; 13 + underlineColor?: string; 14 }) => { 15 return ( 16 <motion.a ··· 21 > 22 {children} 23 <motion.span 24 + className={`absolute bottom-1 left-0 h-0.25 w-full origin-center ${underlineColor}`} 25 variants={{ 26 initial: { scaleX: 0 }, 27 hover: { scaleX: 1 }, 28 }} 29 transition={{ 30 + type: "spring", 31 duration: 0.25, 32 bounce: 0.3, 33 }} 34 /> 35 </motion.a> 36 + ); 37 + };
+23 -22
src/components/Auth/SignIn.tsx
··· 1 - import { UnderlineLink } from '@/components/Animated/UnderlinedLink' 2 - import { LucideAtSign } from '@/components/Icons/LucideAtSign' 3 - import { LucideCircleUserRound } from '@/components/Icons/LucideCircleUserRound' 4 - import { LucideInfo } from '@/components/Icons/LucideInfo' 5 - import { LucideLogIn } from '@/components/Icons/LucideLogIn' 6 - import { useState } from 'react' 7 8 export const SignIn = () => { 9 - const [handle, setHandle] = useState('') 10 - const isValidHandle = handle.includes('.') 11 12 return ( 13 - <div className="bg-surface0 flex flex-col items-center m-36 rounded-md max-w-1/4 px-6 py-4 border-1 border-surface1"> 14 <LucideCircleUserRound 15 height={28} 16 width={28} 17 className="mt-4 mb-1" 18 /> 19 - <h2 className="font-semibold text-xl tracking-wide">Sign In</h2> 20 <p className="text-subtext m-4"> 21 - Continue with an{' '} 22 <UnderlineLink 23 href="https://atproto.com" 24 underlineColor="bg-accent" 25 className="text-accent" 26 > 27 Atmosphere 28 - </UnderlineLink>{' '} 29 account 30 </p> 31 <div className="w-full"> ··· 37 height={14} 38 width={14} 39 /> 40 - <div className="absolute bottom-full left-1/2 mb-2 w-64 -translate-x-1/2 rounded-lg bg-surface1 px-3 py-2 text-sm opacity-0 pointer-events-none transition-opacity group-hover:pointer-events-auto group-hover:opacity-100"> 41 If you have a Bluesky, Blacksky, Tangled, or any 42 - other ATProto account, you can use that account's handle. 43 - <div className="absolute left-1/2 top-full -translate-x-1/2 border-4 border-transparent border-t-surface1" /> 44 </div> 45 </div> 46 </div> 47 - <div className="flex items-center rounded-sm border border-surface1 overflow-hidden transition-all group has-[:focus]:border-accent"> 48 - <LucideAtSign className="text-subtext px-2 w-max h-full group-has-[:focus]:text-accent transition-all" /> 49 - <div className="w-px bg-surface1 group-has-[:focus]:bg-accent self-stretch transition-all" /> 50 <input 51 placeholder="akshay.tngl.sh" 52 - className="w-full p-1 focus:outline-0 rounded-tr-sm rounded-br-sm py-2 pl-2 peer transition-all" 53 onChange={(e) => setHandle(e.target.value)} 54 /> 55 </div> 56 </div> 57 <button 58 disabled={!isValidHandle} 59 - className="cursor-pointer p-2 transition-all hover:bg-positive hover:text-crust rounded-sm w-full m-2 mt-6 mb-2 flex items-center gap-2 justify-center disabled:cursor-not-allowed hover:disabled:bg-surface1 hover:disabled:text-text bg-accent text-crust disabled:bg-surface1 disabled:text-text" 60 > 61 <p>Continue</p> 62 <LucideLogIn /> 63 </button> 64 </div> 65 - ) 66 - }
··· 1 + import { UnderlineLink } from "@/components/Animated/UnderlinedLink"; 2 + import { LucideAtSign } from "@/components/Icons/LucideAtSign"; 3 + import { LucideCircleUserRound } from "@/components/Icons/LucideCircleUserRound"; 4 + import { LucideInfo } from "@/components/Icons/LucideInfo"; 5 + import { LucideLogIn } from "@/components/Icons/LucideLogIn"; 6 + import { useState } from "react"; 7 8 export const SignIn = () => { 9 + const [handle, setHandle] = useState(""); 10 + const isValidHandle = handle.includes("."); 11 12 return ( 13 + <div className="bg-surface0 border-surface1 m-36 flex max-w-1/4 flex-col items-center rounded-md border-1 px-6 py-4"> 14 <LucideCircleUserRound 15 height={28} 16 width={28} 17 className="mt-4 mb-1" 18 /> 19 + <h2 className="text-xl font-semibold tracking-wide">Sign In</h2> 20 <p className="text-subtext m-4"> 21 + Continue with an{" "} 22 <UnderlineLink 23 href="https://atproto.com" 24 underlineColor="bg-accent" 25 className="text-accent" 26 > 27 Atmosphere 28 + </UnderlineLink>{" "} 29 account 30 </p> 31 <div className="w-full"> ··· 37 height={14} 38 width={14} 39 /> 40 + <div className="bg-surface1 pointer-events-none absolute bottom-full left-1/2 mb-2 w-64 -translate-x-1/2 rounded-lg px-3 py-2 text-sm opacity-0 transition-opacity group-hover:pointer-events-auto group-hover:opacity-100"> 41 If you have a Bluesky, Blacksky, Tangled, or any 42 + other ATProto account, you can use that account's 43 + handle. 44 + <div className="border-t-surface1 absolute top-full left-1/2 -translate-x-1/2 border-4 border-transparent" /> 45 </div> 46 </div> 47 </div> 48 + <div className="border-surface1 group has-[:focus]:border-accent flex items-center overflow-hidden rounded-sm border transition-all"> 49 + <LucideAtSign className="text-subtext group-has-[:focus]:text-accent h-full w-max px-2 transition-all" /> 50 + <div className="bg-surface1 group-has-[:focus]:bg-accent w-px self-stretch transition-all" /> 51 <input 52 placeholder="akshay.tngl.sh" 53 + className="peer w-full rounded-tr-sm rounded-br-sm p-1 py-2 pl-2 transition-all focus:outline-0" 54 onChange={(e) => setHandle(e.target.value)} 55 /> 56 </div> 57 </div> 58 <button 59 disabled={!isValidHandle} 60 + className="hover:bg-positive hover:text-crust hover:disabled:bg-surface1 hover:disabled:text-text bg-accent text-crust disabled:bg-surface1 disabled:text-text m-2 mt-6 mb-2 flex w-full cursor-pointer items-center justify-center gap-2 rounded-sm p-2 transition-all disabled:cursor-not-allowed" 61 > 62 <p>Continue</p> 63 <LucideLogIn /> 64 </button> 65 </div> 66 + ); 67 + };
+3 -3
src/components/Icons/Branding/StrandIcon.tsx
··· 1 - import { LucideSpool } from '@/components/Icons/LucideSpool' 2 3 export const StrandIcon = () => { 4 - return <LucideSpool /> 5 - }
··· 1 + import { LucideSpool } from "@/components/Icons/LucideSpool"; 2 3 export const StrandIcon = () => { 4 + return <LucideSpool />; 5 + };
+2 -2
src/components/Icons/LucideAtSign.tsx
··· 1 - import { SVGProps } from 'react' 2 3 export function LucideAtSign(props: SVGProps<SVGSVGElement>) { 4 return ( ··· 21 <path d="M16 8v5a3 3 0 0 0 6 0v-1a10 10 0 1 0-4 8" /> 22 </g> 23 </svg> 24 - ) 25 }
··· 1 + import { SVGProps } from "react"; 2 3 export function LucideAtSign(props: SVGProps<SVGSVGElement>) { 4 return ( ··· 21 <path d="M16 8v5a3 3 0 0 0 6 0v-1a10 10 0 1 0-4 8" /> 22 </g> 23 </svg> 24 + ); 25 }
+2 -2
src/components/Icons/LucideCircleUserRound.tsx
··· 1 - import { SVGProps } from 'react' 2 3 export function LucideCircleUserRound(props: SVGProps<SVGSVGElement>) { 4 return ( ··· 22 <circle cx="12" cy="12" r="10" /> 23 </g> 24 </svg> 25 - ) 26 }
··· 1 + import { SVGProps } from "react"; 2 3 export function LucideCircleUserRound(props: SVGProps<SVGSVGElement>) { 4 return ( ··· 22 <circle cx="12" cy="12" r="10" /> 23 </g> 24 </svg> 25 + ); 26 }
+2 -2
src/components/Icons/LucideInfo.tsx
··· 1 - import { SVGProps } from 'react' 2 3 export function LucideInfo(props: SVGProps<SVGSVGElement>) { 4 return ( ··· 21 <path d="M12 16v-4m0-4h.01" /> 22 </g> 23 </svg> 24 - ) 25 }
··· 1 + import { SVGProps } from "react"; 2 3 export function LucideInfo(props: SVGProps<SVGSVGElement>) { 4 return ( ··· 21 <path d="M12 16v-4m0-4h.01" /> 22 </g> 23 </svg> 24 + ); 25 }
+2 -2
src/components/Icons/LucideLogIn.tsx
··· 1 - import { SVGProps } from 'react' 2 3 export function LucideLogIn(props: SVGProps<SVGSVGElement>) { 4 return ( ··· 19 d="m10 17l5-5l-5-5m5 5H3m12-9h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4" 20 /> 21 </svg> 22 - ) 23 }
··· 1 + import { SVGProps } from "react"; 2 3 export function LucideLogIn(props: SVGProps<SVGSVGElement>) { 4 return ( ··· 19 d="m10 17l5-5l-5-5m5 5H3m12-9h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4" 20 /> 21 </svg> 22 + ); 23 }
+2 -2
src/components/Icons/LucideSpool.tsx
··· 1 - import { SVGProps } from 'react' 2 3 export function LucideSpool(props: SVGProps<SVGSVGElement>) { 4 return ( ··· 21 <path d="m7 10.56l12.558-3.642A2 2 0 0 0 19.018 3H5a2 2 0 0 0-.558 3.921l1.115.32A2 2 0 0 1 7 9.163v7.178" /> 22 </g> 23 </svg> 24 - ) 25 }
··· 1 + import { SVGProps } from "react"; 2 3 export function LucideSpool(props: SVGProps<SVGSVGElement>) { 4 return ( ··· 21 <path d="m7 10.56l12.558-3.642A2 2 0 0 0 19.018 3H5a2 2 0 0 0-.558 3.921l1.115.32A2 2 0 0 1 7 9.163v7.178" /> 22 </g> 23 </svg> 24 + ); 25 }
+7
src/components/Nav/NavBarUnauthed.tsx
···
··· 1 + export const NavBarUnauthed = () => { 2 + return ( 3 + <div> 4 + <p>Unauthed Nav Bar</p> 5 + </div> 6 + ); 7 + };
+3 -3
src/integrations/tanstack-query/devtools.tsx
··· 1 - import { ReactQueryDevtoolsPanel } from '@tanstack/react-query-devtools' 2 3 export default { 4 - name: 'Tanstack Query', 5 render: <ReactQueryDevtoolsPanel />, 6 - }
··· 1 + import { ReactQueryDevtoolsPanel } from "@tanstack/react-query-devtools"; 2 3 export default { 4 + name: "Tanstack Query", 5 render: <ReactQueryDevtoolsPanel />, 6 + };
+6 -6
src/integrations/tanstack-query/root-provider.tsx
··· 1 - import { QueryClient, QueryClientProvider } from '@tanstack/react-query' 2 3 export function getContext() { 4 - const queryClient = new QueryClient() 5 return { 6 queryClient, 7 - } 8 } 9 10 export function Provider({ 11 children, 12 queryClient, 13 }: { 14 - children: React.ReactNode 15 - queryClient: QueryClient 16 }) { 17 return ( 18 <QueryClientProvider client={queryClient}> 19 {children} 20 </QueryClientProvider> 21 - ) 22 }
··· 1 + import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; 2 3 export function getContext() { 4 + const queryClient = new QueryClient(); 5 return { 6 queryClient, 7 + }; 8 } 9 10 export function Provider({ 11 children, 12 queryClient, 13 }: { 14 + children: React.ReactNode; 15 + queryClient: QueryClient; 16 }) { 17 return ( 18 <QueryClientProvider client={queryClient}> 19 {children} 20 </QueryClientProvider> 21 + ); 22 }
+47 -47
src/lib/consts.ts
··· 1 - const __DEV__oAuthCallbackUrl = 'http://127.0.0.1:8081/login/' 2 3 const oAuthScopes = [ 4 - 'atproto', 5 6 - 'repo:sh.tangled.publicKey', 7 - 'repo:sh.tangled.repo', 8 - 'repo:sh.tangled.repo.pull', 9 - 'repo:sh.tangled.repo.pull.comment', 10 - 'repo:sh.tangled.repo.artifact', 11 - 'repo:sh.tangled.repo.issue', 12 - 'repo:sh.tangled.repo.issue.comment', 13 - 'repo:sh.tangled.repo.collaborator', 14 - 'repo:sh.tangled.knot', 15 - 'repo:sh.tangled.knot.member', 16 - 'repo:sh.tangled.spindle', 17 - 'repo:sh.tangled.spindle.member', 18 - 'repo:sh.tangled.graph.follow', 19 - 'repo:sh.tangled.feed.star', 20 - 'repo:sh.tangled.feed.reaction', 21 - 'repo:sh.tangled.label.definition', 22 - 'repo:sh.tangled.label.op', 23 - 'repo:sh.tangled.string', 24 - 'repo:sh.tangled.actor.profile', 25 26 - 'blob:*/*', 27 28 - 'rpc:sh.tangled.repo.create?aud=*', 29 - 'rpc:sh.tangled.repo.delete?aud=*', 30 - 'rpc:sh.tangled.repo.merge?aud=*', 31 - 'rpc:sh.tangled.repo.hiddenRef?aud=*', 32 - 'rpc:sh.tangled.repo.deleteBranch?aud=*', 33 - 'rpc:sh.tangled.repo.setDefaultBranch?aud=*', 34 - 'rpc:sh.tangled.repo.forkSync?aud=*', 35 - 'rpc:sh.tangled.repo.forkStatus?aud=*', 36 - 'rpc:sh.tangled.repo.mergeCheck?aud=*', 37 - 'rpc:sh.tangled.pipeline.cancelPipeline?aud=*', 38 - 'rpc:sh.tangled.repo.addSecret?aud=*', 39 - 'rpc:sh.tangled.repo.removeSecret?aud=*', 40 - 'rpc:sh.tangled.repo.listSecrets?aud=*', 41 - ] 42 43 const oAuthScopesString = oAuthScopes 44 .reduce((prev, curr) => `${prev} ${curr}`) 45 - .trim() 46 47 export const __DEV__loopbackOAuthMetadata = { 48 client_id: `http://localhost?redirect_uri=${encodeURIComponent(__DEV__oAuthCallbackUrl)}&scope=${encodeURIComponent(oAuthScopesString)}`, 49 redirect_uris: [__DEV__oAuthCallbackUrl], 50 scope: oAuthScopesString, 51 - token_endpoint_auth_method: 'none', 52 - response_types: ['code'], 53 - grant_types: ['authorization_code', 'refresh_token'], 54 - application_type: 'web', 55 dpop_bound_access_tokens: true, 56 - subject_type: 'public', 57 - client_name: 'Strand Localhost', 58 - } 59 60 - export const DEFAULT_STALE_TIME = 5 * 60 * 1000 61 62 export const CONSTELLATION_URL = new URL( 63 - 'https://constellation.microcosm.blue/', 64 - )
··· 1 + const __DEV__oAuthCallbackUrl = "http://127.0.0.1:8081/login/"; 2 3 const oAuthScopes = [ 4 + "atproto", 5 6 + "repo:sh.tangled.publicKey", 7 + "repo:sh.tangled.repo", 8 + "repo:sh.tangled.repo.pull", 9 + "repo:sh.tangled.repo.pull.comment", 10 + "repo:sh.tangled.repo.artifact", 11 + "repo:sh.tangled.repo.issue", 12 + "repo:sh.tangled.repo.issue.comment", 13 + "repo:sh.tangled.repo.collaborator", 14 + "repo:sh.tangled.knot", 15 + "repo:sh.tangled.knot.member", 16 + "repo:sh.tangled.spindle", 17 + "repo:sh.tangled.spindle.member", 18 + "repo:sh.tangled.graph.follow", 19 + "repo:sh.tangled.feed.star", 20 + "repo:sh.tangled.feed.reaction", 21 + "repo:sh.tangled.label.definition", 22 + "repo:sh.tangled.label.op", 23 + "repo:sh.tangled.string", 24 + "repo:sh.tangled.actor.profile", 25 26 + "blob:*/*", 27 28 + "rpc:sh.tangled.repo.create?aud=*", 29 + "rpc:sh.tangled.repo.delete?aud=*", 30 + "rpc:sh.tangled.repo.merge?aud=*", 31 + "rpc:sh.tangled.repo.hiddenRef?aud=*", 32 + "rpc:sh.tangled.repo.deleteBranch?aud=*", 33 + "rpc:sh.tangled.repo.setDefaultBranch?aud=*", 34 + "rpc:sh.tangled.repo.forkSync?aud=*", 35 + "rpc:sh.tangled.repo.forkStatus?aud=*", 36 + "rpc:sh.tangled.repo.mergeCheck?aud=*", 37 + "rpc:sh.tangled.pipeline.cancelPipeline?aud=*", 38 + "rpc:sh.tangled.repo.addSecret?aud=*", 39 + "rpc:sh.tangled.repo.removeSecret?aud=*", 40 + "rpc:sh.tangled.repo.listSecrets?aud=*", 41 + ]; 42 43 const oAuthScopesString = oAuthScopes 44 .reduce((prev, curr) => `${prev} ${curr}`) 45 + .trim(); 46 47 export const __DEV__loopbackOAuthMetadata = { 48 client_id: `http://localhost?redirect_uri=${encodeURIComponent(__DEV__oAuthCallbackUrl)}&scope=${encodeURIComponent(oAuthScopesString)}`, 49 redirect_uris: [__DEV__oAuthCallbackUrl], 50 scope: oAuthScopesString, 51 + token_endpoint_auth_method: "none", 52 + response_types: ["code"], 53 + grant_types: ["authorization_code", "refresh_token"], 54 + application_type: "web", 55 dpop_bound_access_tokens: true, 56 + subject_type: "public", 57 + client_name: "Strand Localhost", 58 + }; 59 60 + export const DEFAULT_STALE_TIME = 5 * 60 * 1000; 61 62 export const CONSTELLATION_URL = new URL( 63 + "https://constellation.microcosm.blue/", 64 + );
+2 -2
src/lib/styles/theme.ts
··· 1 // TODO: restrict key to our expected strings 2 export const impurelyApplyThemeOverride = (key: string, value: string) => { 3 - document.documentElement.style.setProperty(`--color-${key}`, value); 4 - }
··· 1 // TODO: restrict key to our expected strings 2 export const impurelyApplyThemeOverride = (key: string, value: string) => { 3 + document.documentElement.style.setProperty(`--color-${key}`, value); 4 + };
+10 -10
src/router.tsx
··· 1 - import { createRouter } from '@tanstack/react-router' 2 - import { setupRouterSsrQueryIntegration } from '@tanstack/react-router-ssr-query' 3 - import * as TanstackQuery from './integrations/tanstack-query/root-provider' 4 5 // Import the generated route tree 6 - import { routeTree } from './routeTree.gen' 7 8 // Create a new router instance 9 export const getRouter = () => { 10 - const rqContext = TanstackQuery.getContext() 11 12 const router = createRouter({ 13 routeTree, ··· 15 ...rqContext, 16 }, 17 18 - defaultPreload: 'intent', 19 - }) 20 21 setupRouterSsrQueryIntegration({ 22 router, 23 queryClient: rqContext.queryClient, 24 - }) 25 26 - return router 27 - }
··· 1 + import { createRouter } from "@tanstack/react-router"; 2 + import { setupRouterSsrQueryIntegration } from "@tanstack/react-router-ssr-query"; 3 + import * as TanstackQuery from "./integrations/tanstack-query/root-provider"; 4 5 // Import the generated route tree 6 + import { routeTree } from "./routeTree.gen"; 7 8 // Create a new router instance 9 export const getRouter = () => { 10 + const rqContext = TanstackQuery.getContext(); 11 12 const router = createRouter({ 13 routeTree, ··· 15 ...rqContext, 16 }, 17 18 + defaultPreload: "intent", 19 + }); 20 21 setupRouterSsrQueryIntegration({ 22 router, 23 queryClient: rqContext.queryClient, 24 + }); 25 26 + return router; 27 + };
+16 -16
src/routes/__root.tsx
··· 2 HeadContent, 3 Scripts, 4 createRootRouteWithContext, 5 - } from '@tanstack/react-router' 6 - import { TanStackRouterDevtoolsPanel } from '@tanstack/react-router-devtools' 7 - import { TanStackDevtools } from '@tanstack/react-devtools' 8 9 - import TanStackQueryDevtools from '../integrations/tanstack-query/devtools' 10 11 - import appCss from '../styles.css?url' 12 13 - import type { QueryClient } from '@tanstack/react-query' 14 15 interface MyRouterContext { 16 - queryClient: QueryClient 17 } 18 19 export const Route = createRootRouteWithContext<MyRouterContext>()({ 20 head: () => ({ 21 meta: [ 22 { 23 - charSet: 'utf-8', 24 }, 25 { 26 - name: 'viewport', 27 - content: 'width=device-width, initial-scale=1', 28 }, 29 { 30 - title: 'Strand', 31 }, 32 ], 33 links: [ 34 { 35 - rel: 'stylesheet', 36 href: appCss, 37 }, 38 ], 39 }), 40 41 shellComponent: RootDocument, 42 - }) 43 44 function RootDocument({ children }: { children: React.ReactNode }) { 45 return ( ··· 51 {children} 52 <TanStackDevtools 53 config={{ 54 - position: 'bottom-right', 55 }} 56 plugins={[ 57 { 58 - name: 'Tanstack Router', 59 render: <TanStackRouterDevtoolsPanel />, 60 }, 61 TanStackQueryDevtools, ··· 64 <Scripts /> 65 </body> 66 </html> 67 - ) 68 }
··· 2 HeadContent, 3 Scripts, 4 createRootRouteWithContext, 5 + } from "@tanstack/react-router"; 6 + import { TanStackRouterDevtoolsPanel } from "@tanstack/react-router-devtools"; 7 + import { TanStackDevtools } from "@tanstack/react-devtools"; 8 9 + import TanStackQueryDevtools from "../integrations/tanstack-query/devtools"; 10 11 + import appCss from "../styles.css?url"; 12 13 + import type { QueryClient } from "@tanstack/react-query"; 14 15 interface MyRouterContext { 16 + queryClient: QueryClient; 17 } 18 19 export const Route = createRootRouteWithContext<MyRouterContext>()({ 20 head: () => ({ 21 meta: [ 22 { 23 + charSet: "utf-8", 24 }, 25 { 26 + name: "viewport", 27 + content: "width=device-width, initial-scale=1", 28 }, 29 { 30 + title: "Strand", 31 }, 32 ], 33 links: [ 34 { 35 + rel: "stylesheet", 36 href: appCss, 37 }, 38 ], 39 }), 40 41 shellComponent: RootDocument, 42 + }); 43 44 function RootDocument({ children }: { children: React.ReactNode }) { 45 return ( ··· 51 {children} 52 <TanStackDevtools 53 config={{ 54 + position: "bottom-right", 55 }} 56 plugins={[ 57 { 58 + name: "Tanstack Router", 59 render: <TanStackRouterDevtoolsPanel />, 60 }, 61 TanStackQueryDevtools, ··· 64 <Scripts /> 65 </body> 66 </html> 67 + ); 68 }
+4 -4
src/routes/_authed.tsx
··· 1 - import { createFileRoute, Outlet } from '@tanstack/react-router' 2 3 - export const Route = createFileRoute('/_authed')({ 4 component: RouteComponent, 5 - }) 6 7 function RouteComponent() { 8 return ( ··· 10 <p>Hello "/_authed"!</p> 11 <Outlet /> 12 </div> 13 - ) 14 }
··· 1 + import { createFileRoute, Outlet } from "@tanstack/react-router"; 2 3 + export const Route = createFileRoute("/_authed")({ 4 component: RouteComponent, 5 + }); 6 7 function RouteComponent() { 8 return ( ··· 10 <p>Hello "/_authed"!</p> 11 <Outlet /> 12 </div> 13 + ); 14 }
+4 -4
src/routes/_authed/oauth/callback.tsx
··· 1 - import { createFileRoute } from '@tanstack/react-router' 2 3 - export const Route = createFileRoute('/_authed/oauth/callback')({ 4 component: RouteComponent, 5 - }) 6 7 function RouteComponent() { 8 - return <div>Hello "/reserved/oauth/callback"!</div> 9 }
··· 1 + import { createFileRoute } from "@tanstack/react-router"; 2 3 + export const Route = createFileRoute("/_authed/oauth/callback")({ 4 component: RouteComponent, 5 + }); 6 7 function RouteComponent() { 8 + return <div>Hello "/reserved/oauth/callback"!</div>; 9 }
+5 -5
src/routes/index.tsx
··· 1 - import { createFileRoute, Link } from '@tanstack/react-router' 2 3 - export const Route = createFileRoute('/')({ component: App }) 4 5 function App() { 6 return ( 7 - <div className="min-w-screen flex items-center justify-center pt-8 flex-col gap-4"> 8 <h1 className="text-xl font-bold"> 9 The better frontend for the better forge. 10 </h1> 11 <Link 12 to="/login" 13 - className="transition-all hover:bg-overlay0 bg-surface0 text-text p-2 rounded-xs" 14 > 15 Sign in 16 </Link> 17 </div> 18 - ) 19 }
··· 1 + import { createFileRoute, Link } from "@tanstack/react-router"; 2 3 + export const Route = createFileRoute("/")({ component: App }); 4 5 function App() { 6 return ( 7 + <div className="flex min-w-screen flex-col items-center justify-center gap-4 pt-8"> 8 <h1 className="text-xl font-bold"> 9 The better frontend for the better forge. 10 </h1> 11 <Link 12 to="/login" 13 + className="hover:bg-overlay0 bg-surface0 text-text rounded-xs p-2 transition-all" 14 > 15 Sign in 16 </Link> 17 </div> 18 + ); 19 }
+11 -7
src/routes/login.tsx
··· 1 - import { SignIn } from '@/components/Auth/SignIn' 2 - import { createFileRoute } from '@tanstack/react-router' 3 4 - export const Route = createFileRoute('/login')({ 5 component: RouteComponent, 6 - }) 7 8 function RouteComponent() { 9 return ( 10 - <div className="min-w-screen flex items-center justify-center pt-8 flex-col gap-4"> 11 - <SignIn /> 12 </div> 13 - ) 14 }
··· 1 + import { SignIn } from "@/components/Auth/SignIn"; 2 + import { NavBarUnauthed } from "@/components/Nav/NavBarUnauthed"; 3 + import { createFileRoute } from "@tanstack/react-router"; 4 5 + export const Route = createFileRoute("/login")({ 6 component: RouteComponent, 7 + }); 8 9 function RouteComponent() { 10 return ( 11 + <div className="flex min-w-screen flex-col items-center"> 12 + <NavBarUnauthed /> 13 + <div className="flex w-full justify-center pt-8"> 14 + <SignIn /> 15 + </div> 16 </div> 17 + ); 18 }
+8 -8
src/styles.css
··· 1 - @import 'tailwindcss'; 2 3 - @import '@fontsource-variable/hanken-grotesk'; 4 - @import '@fontsource/amiri'; 5 - @import '@fontsource/maple-mono'; 6 - @import '@fontsource/maple-mono/400-italic.css'; 7 8 @theme { 9 - --font-sans: 'Hanken Grotesk Variable', sans-serif; 10 - --font-serif: 'Amiri', serif; 11 - --font-mono: 'Maple Mono', monospace; 12 13 --color-crust: oklch(0.1286 0 0); 14 --color-mantle: oklch(0.1776 0 0);
··· 1 + @import "tailwindcss"; 2 3 + @import "@fontsource-variable/hanken-grotesk"; 4 + @import "@fontsource/amiri"; 5 + @import "@fontsource/maple-mono"; 6 + @import "@fontsource/maple-mono/400-italic.css"; 7 8 @theme { 9 + --font-sans: "Hanken Grotesk Variable", sans-serif; 10 + --font-serif: "Amiri", serif; 11 + --font-mono: "Maple Mono", monospace; 12 13 --color-crust: oklch(0.1286 0 0); 14 --color-mantle: oklch(0.1776 0 0);