feat: add basic example

This commit is contained in:
2025-02-06 04:26:07 +08:00
parent 58d7b3c89e
commit 13886502b6
18 changed files with 1568 additions and 111 deletions

View File

@@ -8,16 +8,24 @@
"preview": "rsbuild preview"
},
"dependencies": {
"@abraham/reflection": "^0.12.0",
"@outposts/injection-js": "^2.5.1",
"@tanstack/react-router": "^1.99.6",
"@tanstack/router-devtools": "^1.99.6",
"autoprefixer": "^10.4.20",
"observable-hooks": "^4.2.4",
"oidc-client-rx": "workspace:*",
"react": "^19.0.0",
"react-dom": "^19.0.0"
"react-dom": "^19.0.0",
"tailwindcss": "^3.0.0"
},
"devDependencies": {
"@rsbuild/core": "^1.2.3",
"@rsbuild/plugin-react": "^1.1.0",
"@tanstack/router-plugin": "^1.99.6",
"@types/react": "^19.0.8",
"@types/react-dom": "^19.0.3",
"oidc-client-rx": "workspace:*",
"postcss": "^8.5.1",
"typescript": "^5.7.3"
}
}

View File

@@ -0,0 +1,6 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};

View File

@@ -1,6 +1,12 @@
import { defineConfig } from '@rsbuild/core';
import { pluginReact } from '@rsbuild/plugin-react';
import { TanStackRouterRspack } from '@tanstack/router-plugin/rspack';
export default defineConfig({
plugins: [pluginReact()],
tools: {
rspack: {
plugins: [TanStackRouterRspack()],
},
},
});

View File

@@ -1,26 +0,0 @@
body {
margin: 0;
color: #fff;
font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
background-image: linear-gradient(to bottom, #020917, #101725);
}
.content {
display: flex;
min-height: 100vh;
line-height: 1.1;
text-align: center;
flex-direction: column;
justify-content: center;
}
.content h1 {
font-size: 3.6rem;
font-weight: 700;
}
.content p {
font-size: 1.2rem;
font-weight: 400;
opacity: 0.5;
}

View File

@@ -1,15 +0,0 @@
import { useOidcClient } from 'oidc-client-rx/adapters/react';
import './App.css';
const App = () => {
const { oidcSecurityService } = useOidcClient();
return (
<div className="content">
<h1>Rsbuild with React</h1>
<p>Start building amazing things with Rsbuild.</p>
</div>
);
};
export default App;

View File

@@ -1,39 +1,76 @@
import '@abraham/reflection'; // or 'reflect-metadata' | 'core-js/es7/reflect'
import { type Injector, ReflectiveInjector } from '@outposts/injection-js';
import { RouterProvider, createRouter } from '@tanstack/react-router';
import { LogLevel, OidcSecurityService, provideAuth } from 'oidc-client-rx';
import { InjectorProvider } from 'oidc-client-rx/adapters/react';
import {
InjectorContextVoidInjector,
InjectorProvider,
} from 'oidc-client-rx/adapters/react';
import { withTanstackRouter } from 'oidc-client-rx/adapters/tanstack-router';
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { routeTree } from './routeTree.gen';
const rootEl = document.getElementById('root');
import './style.css';
if (rootEl) {
const injector = ReflectiveInjector.resolveAndCreate(
provideAuth({
// Set up a Router instance
const router = createRouter({
routeTree,
defaultPreload: 'intent',
scrollRestoration: true,
context: {
injector: InjectorContextVoidInjector,
oidcSecurityService: {} as OidcSecurityService,
},
});
// Register things for typesafety
declare module '@tanstack/react-router' {
interface Register {
router: typeof router;
}
}
const injector = ReflectiveInjector.resolveAndCreate(
provideAuth(
{
config: {
authority: '<your authority address here>',
redirectUrl: window.location.origin,
authority: 'https://k9bor3.logto.app/oidc',
redirectUrl: `${window.location.origin}/auth/callback`,
postLogoutRedirectUri: window.location.origin,
clientId: '<your clientId>',
scope: 'openid profile email offline_access',
clientId: 'zz5vo27wtvtjf36srwtbp',
scope: 'openid offline_access',
responseType: 'code',
silentRenew: true,
useRefreshToken: true,
logLevel: LogLevel.Debug,
autoUserInfo: true,
renewUserInfoAfterTokenRenew: true,
customParamsAuthRequest: {
prompt: 'consent',
},
},
})
) as Injector;
},
withTanstackRouter(router)
)
) as Injector;
// if needed, check when init
const oidcSecurityService = injector.get(OidcSecurityService);
oidcSecurityService.checkAuthMultiple();
// if needed, check when init
const oidcSecurityService = injector.get(OidcSecurityService);
oidcSecurityService.checkAuth().subscribe();
const rootEl = document.getElementById('root');
if (rootEl) {
const root = ReactDOM.createRoot(rootEl);
root.render(
<React.StrictMode>
<InjectorProvider injector={injector}>
<App />
<RouterProvider
router={router}
context={{ injector, oidcSecurityService }}
/>
</InjectorProvider>
</React.StrictMode>
);

View File

@@ -0,0 +1,111 @@
/* eslint-disable */
// @ts-nocheck
// noinspection JSUnusedGlobalSymbols
// This file was automatically generated by TanStack Router.
// You should NOT make any changes in this file as it will be overwritten.
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
// Import Routes
import { Route as rootRoute } from './routes/__root'
import { Route as IndexImport } from './routes/index'
import { Route as AuthCallbackImport } from './routes/auth/callback'
// Create/Update Routes
const IndexRoute = IndexImport.update({
id: '/',
path: '/',
getParentRoute: () => rootRoute,
} as any)
const AuthCallbackRoute = AuthCallbackImport.update({
id: '/auth/callback',
path: '/auth/callback',
getParentRoute: () => rootRoute,
} as any)
// Populate the FileRoutesByPath interface
declare module '@tanstack/react-router' {
interface FileRoutesByPath {
'/': {
id: '/'
path: '/'
fullPath: '/'
preLoaderRoute: typeof IndexImport
parentRoute: typeof rootRoute
}
'/auth/callback': {
id: '/auth/callback'
path: '/auth/callback'
fullPath: '/auth/callback'
preLoaderRoute: typeof AuthCallbackImport
parentRoute: typeof rootRoute
}
}
}
// Create and export the route tree
export interface FileRoutesByFullPath {
'/': typeof IndexRoute
'/auth/callback': typeof AuthCallbackRoute
}
export interface FileRoutesByTo {
'/': typeof IndexRoute
'/auth/callback': typeof AuthCallbackRoute
}
export interface FileRoutesById {
__root__: typeof rootRoute
'/': typeof IndexRoute
'/auth/callback': typeof AuthCallbackRoute
}
export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
fullPaths: '/' | '/auth/callback'
fileRoutesByTo: FileRoutesByTo
to: '/' | '/auth/callback'
id: '__root__' | '/' | '/auth/callback'
fileRoutesById: FileRoutesById
}
export interface RootRouteChildren {
IndexRoute: typeof IndexRoute
AuthCallbackRoute: typeof AuthCallbackRoute
}
const rootRouteChildren: RootRouteChildren = {
IndexRoute: IndexRoute,
AuthCallbackRoute: AuthCallbackRoute,
}
export const routeTree = rootRoute
._addFileChildren(rootRouteChildren)
._addFileTypes<FileRouteTypes>()
/* ROUTE_MANIFEST_START
{
"routes": {
"__root__": {
"filePath": "__root.tsx",
"children": [
"/",
"/auth/callback"
]
},
"/": {
"filePath": "index.tsx"
},
"/auth/callback": {
"filePath": "auth/callback.tsx"
}
}
}
ROUTE_MANIFEST_END */

View File

@@ -0,0 +1,38 @@
import type { Injector } from '@outposts/injection-js';
import {
Link,
Outlet,
createRootRouteWithContext,
} from '@tanstack/react-router';
import { TanStackRouterDevtools } from '@tanstack/router-devtools';
import type { OidcSecurityService } from 'oidc-client-rx';
export interface RouterContext {
injector: Injector;
oidcSecurityService: OidcSecurityService;
}
export const Route = createRootRouteWithContext<RouterContext>()({
component: RootComponent,
});
function RootComponent() {
return (
<>
<div className="flex gap-2 p-2 text-lg">
<Link
to="/"
activeProps={{
className: 'font-bold',
}}
activeOptions={{ exact: true }}
>
Home
</Link>{' '}
</div>
<hr />
<Outlet />
<TanStackRouterDevtools position="bottom-right" />
</>
);
}

View File

@@ -0,0 +1,13 @@
import { createFileRoute } from '@tanstack/react-router';
export const Route = createFileRoute('/auth/callback')({
component: AuthCallbackComponent,
});
function AuthCallbackComponent() {
return (
<div className="p-2">
<h3>Auth Callback: validating...</h3>
</div>
);
}

View File

@@ -0,0 +1,40 @@
import { createFileRoute } from '@tanstack/react-router';
import { useObservableEagerState } from 'observable-hooks';
import { useOidcClient } from 'oidc-client-rx/adapters/react';
import { useCallback } from 'react';
export const Route = createFileRoute('/')({
component: HomeComponent,
});
function HomeComponent() {
const { oidcSecurityService } = useOidcClient();
const { isAuthenticated } = useObservableEagerState(
oidcSecurityService.isAuthenticated$
);
const handleLogin = useCallback(() => {
oidcSecurityService.authorize().subscribe();
}, [oidcSecurityService]);
const handleLogout = useCallback(() => {
oidcSecurityService.logoff().subscribe();
}, [oidcSecurityService]);
return (
<div className="p-2 text-center">
<h1>Welcome OIDC-CLIENT-RX DEMO of react-tanstack-router</h1>
<p>Is authenticated? {isAuthenticated ? 'True' : 'False'}</p>
{isAuthenticated ? (
<button onClick={handleLogout} type="button">
Click to Logout
</button>
) : (
<button onClick={handleLogin} type="button">
Click to Login
</button>
)}
</div>
);
}

View File

@@ -0,0 +1,13 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
html {
color-scheme: light dark;
}
* {
@apply border-gray-200 dark:border-gray-800;
}
body {
@apply bg-gray-50 text-gray-950 dark:bg-gray-900 dark:text-gray-200;
}

View File

@@ -0,0 +1,4 @@
/** @type {import('tailwindcss').Config} */
export default {
content: ['./src/**/*.{js,jsx,ts,tsx}', './index.html'],
};

View File

@@ -0,0 +1,4 @@
{
"routesDirectory": "./src/routes",
"generatedRouteTree": "./src/routeTree.gen.ts"
}