Skip to content

Commit

Permalink
feat(rwa): layoutv2 (#2657)
Browse files Browse the repository at this point in the history
  • Loading branch information
sstraatemans authored Nov 11, 2024
1 parent 3ee6a4c commit 0bb3f10
Show file tree
Hide file tree
Showing 23 changed files with 610 additions and 158 deletions.
6 changes: 2 additions & 4 deletions packages/apps/rwa-demo/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@ const withVanillaExtract = createVanillaExtractPlugin();

/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
swcMinify: true,
transpilePackages: ['@kadena/kode-ui'],
env: {},
async redirects() {
return [];
},
};

module.exports = withVanillaExtract(nextConfig);
6 changes: 6 additions & 0 deletions packages/apps/rwa-demo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,17 @@
"test:watch": "vitest --coverage"
},
"dependencies": {
"@kadena/client": "^1.15.0",
"@kadena/kode-icons": "workspace:*",
"@kadena/kode-ui": "workspace:*",
"@kadena/spirekey-sdk": "^1.0.0",
"@vanilla-extract/css": "1.14.2",
"@vanilla-extract/css-utils": "^0.1.3",
"@vanilla-extract/next-plugin": "2.4.0",
"@vanilla-extract/recipes": "0.5.1",
"@vanilla-extract/sprinkles": "1.6.1",
"next": "14.2.2",
"next-themes": "^0.2.1",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
Expand All @@ -31,6 +36,7 @@
"@types/react": "^18.2.79",
"@types/react-dom": "^18.2.25",
"@vanilla-extract/vite-plugin": "4.0.7",
"@vanilla-extract/webpack-plugin": "2.3.7",
"@vitejs/plugin-react": "^4.3.1",
"@vitest/coverage-v8": "^1.6.0",
"eslint": "^8.45.0",
Expand Down
31 changes: 31 additions & 0 deletions packages/apps/rwa-demo/src/app/(app)/KLogo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import type { FC } from 'react';

export const KLogo: FC<{ height: number; className?: string }> = (props) => (
<svg
data-style="kdacolor"
viewBox="0 0 32 32"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<g clipPath="url(#clip0_509_65640)">
<path
d="M28.4352 28L19.739 27.9956L8.89978 19.5354L13.3083 16L28.4352 28Z"
fill="#4A9079"
/>
<path
d="M28.4352 4H19.7434L8.89978 12.4646L13.3083 16L28.4352 4Z"
fill="#4A9079"
/>
<path
d="M8.89675 27.9957L3.5 23.7317V8.26851L8.89675 4.00452V27.9957Z"
fill="#4A9079"
/>
</g>
<defs>
<clipPath id="clip0_509_65640">
<rect width="32" height="32" fill="white" />
</clipPath>
</defs>
</svg>
);
96 changes: 96 additions & 0 deletions packages/apps/rwa-demo/src/app/(app)/SideBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { useAccount } from '@/hooks/account';
import {
MonoApps,
MonoDarkMode,
MonoLightMode,
MonoLogout,
} from '@kadena/kode-icons';
import {
Button,
ContextMenu,
ContextMenuItem,
Themes,
useTheme,
} from '@kadena/kode-ui';
import {
SideBarItem,
SideBarItemsInline,
SideBar as SideBarLayout,
} from '@kadena/kode-ui/patterns';
import Link from 'next/link';
import { useRouter } from 'next/navigation';
import type { FC } from 'react';
import { useEffect } from 'react';
import { KLogo } from './KLogo';

export const SideBar: FC = () => {
const { theme, setTheme } = useTheme();
const { logout, account, isMounted } = useAccount();
const router = useRouter();

const toggleTheme = (): void => {
const newTheme = theme === Themes.dark ? Themes.light : Themes.dark;
setTheme(newTheme);
};

const handleLogout = () => {
logout();
router.push('/login');
};

useEffect(() => {
if (!isMounted) return;
if (!account) {
router.push('/login');
}
}, [isMounted]);

return (
<SideBarLayout
logo={
<>
<Link href="/">
<KLogo height={40} />
</Link>
</>
}
navigation={
<>
<SideBarItem
visual={<MonoApps />}
label="Dashboard"
component={Link}
href="/"
/>
</>
}
context={
<>
<SideBarItemsInline>
<ContextMenu trigger={<Button variant="outlined">Profile</Button>}>
<ContextMenuItem
endVisual={<MonoLogout />}
label="Logout"
onClick={handleLogout}
/>
</ContextMenu>
<SideBarItem
visual={theme === 'dark' ? <MonoDarkMode /> : <MonoLightMode />}
onPress={toggleTheme}
label="Change theme"
>
<Button
isCompact
variant="transparent"
onPress={() => toggleTheme()}
startVisual={
theme === 'dark' ? <MonoDarkMode /> : <MonoLightMode />
}
/>
</SideBarItem>
</SideBarItemsInline>
</>
}
></SideBarLayout>
);
};
28 changes: 28 additions & 0 deletions packages/apps/rwa-demo/src/app/(app)/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
'use client';
import { SideBarLayout } from '@kadena/kode-ui/patterns';

import { Link } from '@kadena/kode-ui';
import React from 'react';
import { KLogo } from './KLogo';
import { SideBar } from './SideBar';

const RootLayout = ({
children,
}: Readonly<{
children: React.ReactNode;
}>) => {
return (
<SideBarLayout
logo={
<Link href="/">
<KLogo height={40} />
</Link>
}
sidebar={<SideBar />}
>
{children}
</SideBarLayout>
);
};

export default RootLayout;
7 changes: 7 additions & 0 deletions packages/apps/rwa-demo/src/app/(app)/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
'use client';

const Home = () => {
return <div>Hello world</div>;
};

export default Home;
21 changes: 21 additions & 0 deletions packages/apps/rwa-demo/src/app/(loggedout)/login/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
'use client';
import { useAccount } from '@/hooks/account';
import { Button } from '@kadena/kode-ui';
import { useRouter } from 'next/navigation';

const Home = () => {
const { login } = useAccount();
const router = useRouter();
const handleConnect = async () => {
await login();
router.push('/');
};

return (
<div>
<Button onPress={handleConnect}>Connect</Button>
</div>
);
};

export default Home;
27 changes: 27 additions & 0 deletions packages/apps/rwa-demo/src/app/Providers.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { AccountProvider } from '@/components/AccountProvider/AccountProvider';
import { MediaContextProvider } from '@kadena/kode-ui';
import { LayoutProvider } from '@kadena/kode-ui/patterns';
import { darkThemeClass } from '@kadena/kode-ui/styles';
import { ThemeProvider } from 'next-themes';
import type { FC, PropsWithChildren } from 'react';

export const Providers: FC<PropsWithChildren> = ({ children }) => {
return (
<MediaContextProvider>
<ThemeProvider
attribute="class"
forcedTheme="dark"
value={{
light: 'light',
dark: darkThemeClass,
}}
enableSystem={true}
enableColorScheme={true} // When enabled, we can't make the background of the embedded iframe transparent
>
<LayoutProvider>
<AccountProvider>{children}</AccountProvider>
</LayoutProvider>
</ThemeProvider>
</MediaContextProvider>
);
};
21 changes: 15 additions & 6 deletions packages/apps/rwa-demo/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { Metadata } from 'next';
'use client';

export const metadata: Metadata = {
title: 'Create Next App',
description: 'Generated by create next app',
};
import { mediaProviderStyles } from '@kadena/kode-ui';
import React from 'react';

import { Providers } from './Providers';

const RootLayout = ({
children,
Expand All @@ -12,7 +12,16 @@ const RootLayout = ({
}>) => {
return (
<html lang="en">
<body>{children}</body>
<head>
<style
key="fresnel-css"
dangerouslySetInnerHTML={{ __html: mediaProviderStyles }}
type="text/css"
/>
</head>
<body>
<Providers>{children}</Providers>
</body>
</html>
);
};
Expand Down
5 changes: 0 additions & 5 deletions packages/apps/rwa-demo/src/app/page.tsx

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
'use client';
import { env } from '@/utils/env';
import { getAccountCookieName } from '@/utils/getAccountCookieName';

import type { ConnectedAccount } from '@kadena/spirekey-sdk';
import { connect } from '@kadena/spirekey-sdk';
import { useRouter } from 'next/navigation';
import type { FC, PropsWithChildren } from 'react';
import { createContext, useCallback, useEffect, useState } from 'react';

interface IAccountError {
message: string;
}

export interface IAccountContext {
account?: ConnectedAccount;
error?: IAccountError;
isMounted: boolean;
login: () => void;
logout: () => void;
}

export const AccountContext = createContext<IAccountContext>({
account: undefined,
isMounted: false,
login: () => {},
logout: () => {},
});

export const AccountProvider: FC<PropsWithChildren> = ({ children }) => {
const [account, setAccount] = useState<ConnectedAccount>();
const [isMounted, setIsMounted] = useState(false);
const router = useRouter();

const login = useCallback(async () => {
try {
setIsMounted(true);
const acc = await connect(env.NETWORKID, env.CHAINID);
setAccount(acc);
localStorage.setItem(getAccountCookieName(), JSON.stringify(acc));
} catch (e) {
localStorage.removeItem(getAccountCookieName());
}
}, [router]);

const logout = useCallback(() => {
localStorage.removeItem(getAccountCookieName());
setAccount(undefined);
router.replace('/');
}, []);

useEffect(() => {
const storage = localStorage.getItem(getAccountCookieName());
if (storage) {
try {
setAccount(JSON.parse(storage));
} catch (e) {
localStorage.removeItem(getAccountCookieName());
}
}

setIsMounted(true);
}, []);

return (
<AccountContext.Provider value={{ account, login, logout, isMounted }}>
{children}
</AccountContext.Provider>
);
};
1 change: 1 addition & 0 deletions packages/apps/rwa-demo/src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const ACCOUNT_COOKIE_NAME = 'spirekey';
6 changes: 6 additions & 0 deletions packages/apps/rwa-demo/src/hooks/account.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import type { IAccountContext } from '@/components/AccountProvider/AccountProvider';
import { AccountContext } from '@/components/AccountProvider/AccountProvider';

import { useContext } from 'react';

export const useAccount = (): IAccountContext => useContext(AccountContext);
24 changes: 24 additions & 0 deletions packages/apps/rwa-demo/src/utils/env.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { ChainId } from '@kadena/client';

const URL = process.env.NEXT_PUBLIC_URL;
const WALLET_URL = process.env.NEXT_PUBLIC_WALLET_URL;
const CHAINID = process.env.NEXT_PUBLIC_CHAINID;
const NETWORKID = process.env.NEXT_PUBLIC_NETWORKID;
const NETWORKNAME = process.env.NEXT_PUBLIC_NETWORKNAME;
const CHAINWEBAPIURL = process.env.NEXT_PUBLIC_CHAINWEBAPIURL;

if (!WALLET_URL) console.error('NEXT_PUBLIC_WALLET_URL is not set');
if (!URL) console.error('NEXT_PUBLIC_URL is not set');
if (!CHAINID) console.error('NEXT_PUBLIC_CHAINID is not set');
if (!NETWORKID) console.error('NEXT_PUBLIC_NETWORKID is not set');
if (!NETWORKNAME) console.error('NEXT_PUBLIC_NETWORKNAME is not set');
if (!CHAINWEBAPIURL) console.error('NEXT_PUBLIC_CHAINWEBAPIURL is not set');

export const env = {
WALLET_URL,
URL,
CHAINID: (CHAINID ?? '1') as ChainId,
NETWORKID: NETWORKID ?? 'testnet04',
NETWORKNAME,
CHAINWEBAPIURL: CHAINWEBAPIURL,
};
Loading

0 comments on commit 0bb3f10

Please sign in to comment.