mirror of
https://github.com/stack-auth/stack.git
synced 2026-06-04 21:04:37 +08:00
added demo app, renamed nextjs folder to dev, added docusaurus to turbo
This commit is contained in:
parent
d37c3a206e
commit
a5933c43de
26
apps/demo/package.json
Normal file
26
apps/demo/package.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "demo-app",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"typecheck": "tsc --noEmit",
|
||||
"clean": "rm -rf .next",
|
||||
"dev": "next dev --port 8103",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"next": "14.0.4",
|
||||
"next-themes": "^0.2.1",
|
||||
"react": "^18",
|
||||
"react-dom": "^18",
|
||||
"stack": "workspace:*",
|
||||
"stack-shared": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.2.23",
|
||||
"@types/react-dom": "^18.2.8"
|
||||
}
|
||||
}
|
||||
4
apps/dev/.env
Normal file
4
apps/dev/.env
Normal file
@ -0,0 +1,4 @@
|
||||
NEXT_PUBLIC_STACK_URL=# enter your stack endpoint here, e.g. http://localhost:8101
|
||||
NEXT_PUBLIC_STACK_PROJECT_ID=# enter your stack project id here
|
||||
NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY=# enter your stack publishable client key here
|
||||
STACK_SECRET_SERVER_KEY=# enter your stack secret server key here
|
||||
22
apps/dev/.eslintrc.js
Normal file
22
apps/dev/.eslintrc.js
Normal file
@ -0,0 +1,22 @@
|
||||
module.exports = {
|
||||
"extends": [
|
||||
"../../eslint-configs/defaults.js",
|
||||
"../../eslint-configs/next.js",
|
||||
],
|
||||
"ignorePatterns": ['/*', '!/src'],
|
||||
rules: {
|
||||
"import/order": [
|
||||
1,
|
||||
{
|
||||
groups: [
|
||||
"external",
|
||||
"builtin",
|
||||
"internal",
|
||||
"sibling",
|
||||
"parent",
|
||||
"index",
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
7
apps/dev/.gitignore
vendored
Normal file
7
apps/dev/.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
node_modules/
|
||||
/test-results/
|
||||
/playwright-report/
|
||||
/playwright/.cache/
|
||||
dbschema/edgeql-js
|
||||
|
||||
*.tsbuildinfo
|
||||
4
apps/dev/.vscode/settings.json
vendored
Normal file
4
apps/dev/.vscode/settings.json
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"typescript.tsdk": "../../../node_modules/.pnpm/typescript@4.9.4/node_modules/typescript/lib",
|
||||
"typescript.enablePromptUseWorkspaceTsdk": true
|
||||
}
|
||||
5
apps/dev/next-env.d.ts
vendored
Normal file
5
apps/dev/next-env.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
/// <reference types="next" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
||||
7
apps/dev/next.config.js
Normal file
7
apps/dev/next.config.js
Normal file
@ -0,0 +1,7 @@
|
||||
/** @type {import("next").NextConfig} */
|
||||
module.exports = {
|
||||
webpack(config) {
|
||||
config.experiments = { ...config.experiments, topLevelAwait: true }
|
||||
return config
|
||||
},
|
||||
}
|
||||
6
apps/dev/src/app/handler/[...stack]/page.tsx
Normal file
6
apps/dev/src/app/handler/[...stack]/page.tsx
Normal file
@ -0,0 +1,6 @@
|
||||
import { StackHandler } from "stack";
|
||||
import { stackServerApp } from "src/stack";
|
||||
|
||||
export default function Handler(props) {
|
||||
return <StackHandler app={stackServerApp} {...props} />;
|
||||
}
|
||||
25
apps/dev/src/app/layout.tsx
Normal file
25
apps/dev/src/app/layout.tsx
Normal file
@ -0,0 +1,25 @@
|
||||
import { StackProvider } from "stack";
|
||||
import { stackServerApp } from "src/stack";
|
||||
import Provider from "src/components/Provider";
|
||||
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode,
|
||||
}) {
|
||||
return (
|
||||
<html lang="en" suppressHydrationWarning>
|
||||
<head />
|
||||
<body>
|
||||
<StackProvider
|
||||
app={stackServerApp}
|
||||
>
|
||||
<Provider>
|
||||
{children}
|
||||
</Provider>
|
||||
</StackProvider>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
43
apps/dev/src/app/page.tsx
Normal file
43
apps/dev/src/app/page.tsx
Normal file
@ -0,0 +1,43 @@
|
||||
import Link from 'next/link';
|
||||
import { stackServerApp } from 'src/stack';
|
||||
import ColorModeButton from 'src/components/ColorThemeButton';
|
||||
import SignOutButton from 'src/components/SignOutButton';
|
||||
import UserInfo from 'src/components/UserInfo';
|
||||
import UserInfoClient from 'src/components/UserInfoClient';
|
||||
|
||||
export default async function Page() {
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
|
||||
<div>
|
||||
<div>Server:</div>
|
||||
<UserInfo />
|
||||
<div style={{ marginBottom: '1rem' }}/>
|
||||
<div>Client:</div>
|
||||
<UserInfoClient />
|
||||
</div>
|
||||
|
||||
<div style={{ marginBottom: '1rem' }}/>
|
||||
<Link href="/handler/signin">
|
||||
Sign in
|
||||
</Link>
|
||||
<Link href="/handler/signup">
|
||||
Sign up
|
||||
</Link>
|
||||
<div style={{ marginBottom: '1rem' }}/>
|
||||
<SignOutButton />
|
||||
<Link href={stackServerApp.urls['signOut']}>
|
||||
Sign out (server)
|
||||
</Link>
|
||||
<div style={{ marginBottom: '1rem' }}/>
|
||||
<ColorModeButton />
|
||||
|
||||
<div style={{ marginBottom: '1rem' }}/>
|
||||
<Link href="/protected-client">
|
||||
Protected client
|
||||
</Link>
|
||||
<Link href="/protected-server">
|
||||
Protected server
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
7
apps/dev/src/app/protected-client/page.tsx
Normal file
7
apps/dev/src/app/protected-client/page.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
'use client';
|
||||
import { useUser } from "stack";
|
||||
|
||||
export default function ProtectedPage() {
|
||||
useUser({ or: 'redirect' });
|
||||
return <div>This is protected. You can see this because you are signed in</div>;
|
||||
}
|
||||
6
apps/dev/src/app/protected-server/page.tsx
Normal file
6
apps/dev/src/app/protected-server/page.tsx
Normal file
@ -0,0 +1,6 @@
|
||||
import { stackServerApp } from "src/stack";
|
||||
|
||||
export default async function ProtectedPage() {
|
||||
await stackServerApp.getUser({ or: 'redirect' });
|
||||
return <div>This is protected. You can see this because you are signed in</div>;
|
||||
}
|
||||
36
apps/dev/src/app/signin/custom-credential.tsx
Normal file
36
apps/dev/src/app/signin/custom-credential.tsx
Normal file
@ -0,0 +1,36 @@
|
||||
/* eslint-disable @typescript-eslint/no-misused-promises */
|
||||
'use client';
|
||||
import { useStackApp, validateEmail } from "stack";
|
||||
import { useState } from "react";
|
||||
|
||||
export default function CustomCredentialSignIn() {
|
||||
const [email, setEmail] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
const [error, setError] = useState('');
|
||||
const app = useStackApp();
|
||||
|
||||
const onSubmit = async () => {
|
||||
if (!validateEmail(email)) {
|
||||
setError('Please enter a valid email');
|
||||
return;
|
||||
}
|
||||
if (!password) {
|
||||
setError('Please enter your password');
|
||||
return;
|
||||
}
|
||||
const errorCode = await app.signInWithCredential({ email, password, redirectUrl: app.urls.userHome });
|
||||
// It is better to handle each error code separately, but for simplicity, we will just show the error code directly
|
||||
if (errorCode) {
|
||||
setError(errorCode);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
{error}
|
||||
<input type='email' placeholder="email@example.com" value={email} onChange={(e) => setEmail(e.target.value)} />
|
||||
<input type='password' placeholder="password" value={password} onChange={(e) => setPassword(e.target.value)} />
|
||||
<button onClick={onSubmit}>Sign In</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
12
apps/dev/src/app/signin/custom-oauth.tsx
Normal file
12
apps/dev/src/app/signin/custom-oauth.tsx
Normal file
@ -0,0 +1,12 @@
|
||||
/* eslint-disable @typescript-eslint/no-misused-promises */
|
||||
'use client';
|
||||
import { useStackApp } from "stack";
|
||||
|
||||
export default function CustomOAuthSignIn() {
|
||||
const app = useStackApp();
|
||||
|
||||
return <div>
|
||||
<h1>My Custom Sign In page</h1>
|
||||
<button onClick={async () => await app.signInWithOauth('google')}>Sign In with Google</button>
|
||||
</div>;
|
||||
}
|
||||
10
apps/dev/src/app/signin/page.tsx
Normal file
10
apps/dev/src/app/signin/page.tsx
Normal file
@ -0,0 +1,10 @@
|
||||
import { SignIn } from "stack";
|
||||
import { stackServerApp } from "src/stack";
|
||||
import CustomCredentialSignIn from "./custom-credential";
|
||||
import CustomOAuthSignIn from "./custom-oauth";
|
||||
|
||||
export default function Page() {
|
||||
return <SignIn fullPage redirectUrl={stackServerApp.urls.home} />;
|
||||
// return <CustomCredentialSignIn />;
|
||||
// return <CustomOAuthSignIn />;
|
||||
}
|
||||
24
apps/dev/src/components/ColorThemeButton.tsx
Normal file
24
apps/dev/src/components/ColorThemeButton.tsx
Normal file
@ -0,0 +1,24 @@
|
||||
'use client';
|
||||
import { useTheme } from "next-themes";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export default function ColorModeButton() {
|
||||
const [mounted, setMounted] = useState(false);
|
||||
const { theme, setTheme } = useTheme();
|
||||
|
||||
// useEffect only runs on the client, so now we can safely show the UI
|
||||
useEffect(() => {
|
||||
setMounted(true);
|
||||
}, []);
|
||||
|
||||
if (!mounted) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<header>
|
||||
<button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
|
||||
Toggle {theme === 'light' ? 'Dark' : 'Light'}
|
||||
</button>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
10
apps/dev/src/components/Provider.tsx
Normal file
10
apps/dev/src/components/Provider.tsx
Normal file
@ -0,0 +1,10 @@
|
||||
'use client';
|
||||
import { ThemeProvider } from 'next-themes';
|
||||
|
||||
export default function Provider({ children }) {
|
||||
return (
|
||||
<ThemeProvider>
|
||||
{children}
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
9
apps/dev/src/components/SignOutButton.tsx
Normal file
9
apps/dev/src/components/SignOutButton.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
'use client';
|
||||
|
||||
import { useUser, useStackApp } from "stack";
|
||||
import { runAsynchronously } from "stack-shared/dist/utils/promises";
|
||||
|
||||
export default function SignOutButton() {
|
||||
const user = useUser();
|
||||
return (<button onClick={() => runAsynchronously(user?.signOut())}>Sign out</button>);
|
||||
}
|
||||
19
apps/dev/src/components/UserInfo.tsx
Normal file
19
apps/dev/src/components/UserInfo.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
import { stackServerApp } from "src/stack";
|
||||
|
||||
export default async function UserInfo() {
|
||||
const user = await stackServerApp.getUser();
|
||||
const serverUser = await stackServerApp.getServerUser();
|
||||
|
||||
return <div>
|
||||
{user ? (
|
||||
<div>User Status: Logged in as {user.displayName ?? user.primaryEmail}</div>
|
||||
) : (
|
||||
<div>User Status: Not signed in</div>
|
||||
)}
|
||||
{serverUser ? (
|
||||
<div>ServerUser Status: Logged in as {serverUser.displayName ?? serverUser.primaryEmail}</div>
|
||||
) : (
|
||||
<div>ServerUser Status: Not signed in</div>
|
||||
)}
|
||||
</div>;
|
||||
}
|
||||
17
apps/dev/src/components/UserInfoClient.tsx
Normal file
17
apps/dev/src/components/UserInfoClient.tsx
Normal file
@ -0,0 +1,17 @@
|
||||
'use client';
|
||||
|
||||
import { useUser } from "stack";
|
||||
|
||||
export default function UserInfoClient() {
|
||||
const user = useUser();
|
||||
|
||||
return (
|
||||
<div>
|
||||
{user ? (
|
||||
<div>User Status: Logged in as {user.displayName ?? user.primaryEmail}</div>
|
||||
) : (
|
||||
<div>User Status: Not signed in</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
11
apps/dev/src/stack.tsx
Normal file
11
apps/dev/src/stack.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import "server-only";
|
||||
|
||||
import { StackServerApp } from "stack";
|
||||
|
||||
export const stackServerApp = new StackServerApp({
|
||||
baseUrl: "http://localhost:8101",
|
||||
tokenStore: "nextjs-cookie",
|
||||
urls: {
|
||||
signIn: "/signin",
|
||||
}
|
||||
});
|
||||
38
apps/dev/tsconfig.json
Normal file
38
apps/dev/tsconfig.json
Normal file
@ -0,0 +1,38 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "esnext",
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": false,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"incremental": true,
|
||||
"jsx": "preserve",
|
||||
"baseUrl": ".",
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
],
|
||||
"strictNullChecks": true
|
||||
},
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
".next/types/**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
]
|
||||
}
|
||||
@ -4,7 +4,7 @@
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"docusaurus": "docusaurus",
|
||||
"dev": "pnpm start",
|
||||
"dev": "docusaurus start --port 8104 --no-open",
|
||||
"start": "docusaurus start",
|
||||
"build": "docusaurus build",
|
||||
"swizzle": "docusaurus swizzle",
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
packages:
|
||||
- packages/*
|
||||
- apps/*
|
||||
- docs
|
||||
|
||||
Loading…
Reference in New Issue
Block a user