feat(depot): update onboarding screen
This commit is contained in:
65
src/app.tsx
65
src/app.tsx
@@ -1,5 +1,4 @@
|
||||
import { fetch } from '@tauri-apps/plugin-http';
|
||||
import { nip19 } from 'nostr-tools';
|
||||
import { RouterProvider, createBrowserRouter, defer, redirect } from 'react-router-dom';
|
||||
import { ErrorScreen } from '@app/error';
|
||||
import { useArk } from '@libs/ark';
|
||||
@@ -13,17 +12,6 @@ import { SettingsLayout } from '@shared/layouts/settings';
|
||||
export default function App() {
|
||||
const ark = useArk();
|
||||
|
||||
const relayLoader = async ({ params }) => {
|
||||
return defer({
|
||||
relay: fetch(`https://${params.url}`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
Accept: 'application/nostr+json',
|
||||
},
|
||||
}).then((res) => res.json()),
|
||||
});
|
||||
};
|
||||
|
||||
const router = createBrowserRouter([
|
||||
{
|
||||
element: <AppLayout platform={ark.platform} />,
|
||||
@@ -44,21 +32,6 @@ export default function App() {
|
||||
return { Component: HomeScreen };
|
||||
},
|
||||
},
|
||||
{
|
||||
path: ':address',
|
||||
loader: ({ params }) => {
|
||||
const address = params.address;
|
||||
const decode = nip19.decode(address);
|
||||
if (decode.type === 'npub') return redirect(`/users/${decode.data}`);
|
||||
if (decode.type === 'nprofile')
|
||||
return redirect(`/users/${decode.data.pubkey}`);
|
||||
if (decode.type === 'note') return redirect(`/events/${decode.data}`);
|
||||
if (decode.type === 'nrelay') return redirect(`/relays/${decode.data}`);
|
||||
if (decode.type === 'nevent')
|
||||
return redirect(`/relays/${decode.data.id}`);
|
||||
return null;
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'nwc',
|
||||
async lazy() {
|
||||
@@ -75,7 +48,16 @@ export default function App() {
|
||||
},
|
||||
{
|
||||
path: 'relays/:url',
|
||||
loader: relayLoader,
|
||||
loader: async ({ params }) => {
|
||||
return defer({
|
||||
relay: fetch(`https://${params.url}`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
Accept: 'application/nostr+json',
|
||||
},
|
||||
}).then((res) => res.json()),
|
||||
});
|
||||
},
|
||||
async lazy() {
|
||||
const { RelayScreen } = await import('@app/relays/relay');
|
||||
return { Component: RelayScreen };
|
||||
@@ -83,10 +65,29 @@ export default function App() {
|
||||
},
|
||||
{
|
||||
path: 'depot',
|
||||
async lazy() {
|
||||
const { DepotScreen } = await import('@app/depot');
|
||||
return { Component: DepotScreen };
|
||||
},
|
||||
children: [
|
||||
{
|
||||
index: true,
|
||||
loader: () => {
|
||||
const depot = ark.checkDepot();
|
||||
if (!depot) return redirect('/depot/onboarding/');
|
||||
return null;
|
||||
},
|
||||
async lazy() {
|
||||
const { DepotScreen } = await import('@app/depot');
|
||||
return { Component: DepotScreen };
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'onboarding',
|
||||
async lazy() {
|
||||
const { DepotOnboardingScreen } = await import(
|
||||
'@app/depot/onboarding'
|
||||
);
|
||||
return { Component: DepotOnboardingScreen };
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: 'new',
|
||||
|
||||
@@ -73,7 +73,7 @@ export function CreateAccountScreen() {
|
||||
|
||||
await ark.createEvent({
|
||||
kind: NDKKind.RelayList,
|
||||
tags: [ark.relays],
|
||||
tags: ark.relays.map((item) => ['r', item, '']),
|
||||
});
|
||||
|
||||
setKeys({ npub: userNpub, nsec: userNsec });
|
||||
|
||||
@@ -1,149 +1,96 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
import { useArk } from '@libs/ark';
|
||||
import { LoaderIcon } from '@shared/icons';
|
||||
import { delay } from '@utils/delay';
|
||||
|
||||
export function DepotScreen() {
|
||||
const ark = useArk();
|
||||
|
||||
const [status, setStatus] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const launch = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
await ark.launchDepot();
|
||||
await ark.createSetting('depot', '1');
|
||||
await delay(2000); // delay 2s to make sure depot is running
|
||||
|
||||
// default depot url: ws://localhost:6090
|
||||
// #TODO: user can custom depot url
|
||||
const connect = await ark.connectDepot();
|
||||
|
||||
if (connect) {
|
||||
setStatus(true);
|
||||
setLoading(false);
|
||||
}
|
||||
} catch (e) {
|
||||
toast.error(e);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const depotStatus = ark.checkDepot();
|
||||
setStatus(depotStatus);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="flex h-full w-full flex-col items-center justify-center">
|
||||
{!status ? (
|
||||
<div className="flex flex-col items-center gap-4">
|
||||
<h1 className="mb-1 text-2xl font-semibold text-neutral-400 dark:text-neutral-600">
|
||||
<span>Deploy Nostr Relay inside Lume</span>{' '}
|
||||
<span className="text-neutral-900 dark:text-neutral-100">with Depot.</span>
|
||||
</h1>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => launch()}
|
||||
className="inline-flex h-11 w-24 items-center justify-center rounded-lg bg-blue-500 font-medium text-white hover:bg-blue-600"
|
||||
>
|
||||
{loading ? <LoaderIcon className="h-4 w-4 animate-spin" /> : 'Launch'}
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="mx-auto w-full max-w-md">
|
||||
<div className="flex flex-col gap-10">
|
||||
<div className="text-center">
|
||||
<h1 className="mb-1 text-2xl font-semibold text-neutral-400 dark:text-neutral-600">
|
||||
Your Depot is running
|
||||
</h1>
|
||||
<div className="flex items-center justify-center gap-2.5">
|
||||
<span className="relative flex h-3 w-3">
|
||||
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-teal-400 opacity-75"></span>
|
||||
<span className="relative inline-flex h-3 w-3 rounded-full bg-teal-500"></span>
|
||||
</span>
|
||||
<p className="font-medium">ws://localhost:6090</p>
|
||||
</div>
|
||||
<div className="px-16 py-14">
|
||||
<div className="mx-auto w-full max-w-md">
|
||||
<div className="flex flex-col gap-10">
|
||||
<div className="text-center">
|
||||
<h1 className="mb-1 text-2xl font-semibold text-neutral-400 dark:text-neutral-600">
|
||||
Your Depot is running
|
||||
</h1>
|
||||
<div className="flex items-center justify-center gap-2.5">
|
||||
<span className="relative flex h-3 w-3">
|
||||
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-teal-400 opacity-75"></span>
|
||||
<span className="relative inline-flex h-3 w-3 rounded-full bg-teal-500"></span>
|
||||
</span>
|
||||
<p className="font-medium">ws://localhost:6090</p>
|
||||
</div>
|
||||
<div className="flex flex-col gap-6">
|
||||
<div className="flex items-center justify-between gap-6">
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold">Backup</h3>
|
||||
<p className="text-sm text-neutral-600 dark:text-neutral-400">
|
||||
Sync all your data to Depot.
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
className="inline-flex h-9 w-20 shrink-0 items-center justify-center rounded-lg bg-neutral-200 font-medium hover:bg-blue-500 hover:text-white dark:bg-neutral-800"
|
||||
>
|
||||
Sync
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex flex-col gap-6">
|
||||
<div className="flex items-center justify-between gap-6">
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold">Backup</h3>
|
||||
<p className="text-sm text-neutral-600 dark:text-neutral-400">
|
||||
Sync all your data to Depot.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-6">
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold">Expose</h3>
|
||||
<p className="text-sm text-neutral-600 dark:text-neutral-400">
|
||||
Help other users can see your depot on Internet. You also can do it by
|
||||
yourself by using other service like ngrok or localtunnel.
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
className="inline-flex h-9 w-20 shrink-0 items-center justify-center rounded-lg bg-neutral-200 font-medium hover:bg-blue-500 hover:text-white dark:bg-neutral-800"
|
||||
>
|
||||
Start
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="inline-flex h-9 w-20 shrink-0 items-center justify-center rounded-lg bg-neutral-200 font-medium hover:bg-blue-500 hover:text-white dark:bg-neutral-800"
|
||||
>
|
||||
Sync
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-6">
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold">Expose</h3>
|
||||
<p className="text-sm text-neutral-600 dark:text-neutral-400">
|
||||
Help other users can see your depot on Internet. You also can do it by
|
||||
yourself by using other service like ngrok or localtunnel.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-6">
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold">Relay Hint</h3>
|
||||
<p className="text-sm text-neutral-600 dark:text-neutral-400">
|
||||
Instruct other Nostr client find your events in this depot.
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
className="inline-flex h-9 w-20 shrink-0 items-center justify-center rounded-lg bg-neutral-200 font-medium hover:bg-blue-500 hover:text-white dark:bg-neutral-800"
|
||||
>
|
||||
Add
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="inline-flex h-9 w-20 shrink-0 items-center justify-center rounded-lg bg-neutral-200 font-medium hover:bg-blue-500 hover:text-white dark:bg-neutral-800"
|
||||
>
|
||||
Start
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-6">
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold">Relay Hint</h3>
|
||||
<p className="text-sm text-neutral-600 dark:text-neutral-400">
|
||||
Instruct other Nostr client find your events in this depot.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-6">
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold">Invite</h3>
|
||||
<p className="text-sm text-neutral-600 dark:text-neutral-400">
|
||||
By default, only you can write event to Depot, but you can invite
|
||||
other user to your Depot.
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
className="inline-flex h-9 w-20 shrink-0 items-center justify-center rounded-lg bg-neutral-200 font-medium hover:bg-blue-500 hover:text-white dark:bg-neutral-800"
|
||||
>
|
||||
Invite
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="inline-flex h-9 w-20 shrink-0 items-center justify-center rounded-lg bg-neutral-200 font-medium hover:bg-blue-500 hover:text-white dark:bg-neutral-800"
|
||||
>
|
||||
Add
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-6">
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold">Invite</h3>
|
||||
<p className="text-sm text-neutral-600 dark:text-neutral-400">
|
||||
By default, only you can write event to Depot, but you can invite other
|
||||
user to your Depot.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-6">
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold">Customize</h3>
|
||||
<p className="text-sm text-neutral-600 dark:text-neutral-400">
|
||||
Depot also provide plenty config to customize your experiences.
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
className="inline-flex h-9 w-20 shrink-0 items-center justify-center rounded-lg bg-neutral-200 font-medium hover:bg-blue-500 hover:text-white dark:bg-neutral-800"
|
||||
>
|
||||
Config
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="inline-flex h-9 w-20 shrink-0 items-center justify-center rounded-lg bg-neutral-200 font-medium hover:bg-blue-500 hover:text-white dark:bg-neutral-800"
|
||||
>
|
||||
Invite
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-6">
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold">Customize</h3>
|
||||
<p className="text-sm text-neutral-600 dark:text-neutral-400">
|
||||
Depot also provide plenty config to customize your experiences.
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
className="inline-flex h-9 w-20 shrink-0 items-center justify-center rounded-lg bg-neutral-200 font-medium hover:bg-blue-500 hover:text-white dark:bg-neutral-800"
|
||||
>
|
||||
Config
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
95
src/app/depot/onboarding.tsx
Normal file
95
src/app/depot/onboarding.tsx
Normal file
@@ -0,0 +1,95 @@
|
||||
import { resolveResource } from '@tauri-apps/api/path';
|
||||
import { readTextFile, writeTextFile } from '@tauri-apps/plugin-fs';
|
||||
import { useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { parse, stringify } from 'smol-toml';
|
||||
import { toast } from 'sonner';
|
||||
import { useArk } from '@libs/ark';
|
||||
import { LoaderIcon } from '@shared/icons';
|
||||
import { delay } from '@utils/delay';
|
||||
|
||||
export function DepotOnboardingScreen() {
|
||||
const ark = useArk();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const launchDepot = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
// get default config
|
||||
const defaultConfig = await resolveResource('resources/config.toml');
|
||||
const config = await readTextFile(defaultConfig);
|
||||
const parsedConfig = parse(config);
|
||||
|
||||
// add current user to whitelist
|
||||
parsedConfig.authorization['pubkey_whitelist'].push(ark.account.pubkey);
|
||||
|
||||
// update new config
|
||||
const newConfig = stringify(parsedConfig);
|
||||
await writeTextFile(defaultConfig, newConfig);
|
||||
|
||||
// launch depot
|
||||
await ark.launchDepot();
|
||||
await ark.createSetting('depot', '1');
|
||||
await delay(2000); // delay 2s to make sure depot is running
|
||||
|
||||
// default depot url: ws://localhost:6090
|
||||
// #TODO: user can custom depot url
|
||||
const connect = await ark.connectDepot();
|
||||
|
||||
if (connect) {
|
||||
toast.success('Your Depot is successfully launch.');
|
||||
setLoading(false);
|
||||
|
||||
navigate('/depot/');
|
||||
}
|
||||
} catch (e) {
|
||||
toast.error(e);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex h-full w-full flex-col items-center justify-center gap-10">
|
||||
<div className="flex flex-col items-center gap-8">
|
||||
<div className="text-center">
|
||||
<h1 className="mb-1 text-3xl font-semibold text-neutral-400 dark:text-neutral-600">
|
||||
Run your Personal Nostr Relay inside Lume
|
||||
</h1>
|
||||
<h2 className="text-4xl font-semibold">Your Relay, Your Control.</h2>
|
||||
</div>
|
||||
<div className="rounded-xl bg-blue-100 p-1.5 dark:bg-blue-900">
|
||||
<button
|
||||
type="button"
|
||||
onClick={launchDepot}
|
||||
className="inline-flex h-11 w-36 transform items-center justify-center gap-2 rounded-lg bg-blue-500 font-medium text-white active:translate-y-1"
|
||||
>
|
||||
{loading ? (
|
||||
<>
|
||||
<LoaderIcon className="h-5 w-5 animate-spin" />
|
||||
Launching...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
className="h-5 w-5"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M12 2.25a.75.75 0 0 1 .75.75v9a.75.75 0 0 1-1.5 0V3a.75.75 0 0 1 .75-.75ZM6.166 5.106a.75.75 0 0 1 0 1.06 8.25 8.25 0 1 0 11.668 0 .75.75 0 1 1 1.06-1.06c3.808 3.807 3.808 9.98 0 13.788-3.807 3.808-9.98 3.808-13.788 0-3.808-3.807-3.808-9.98 0-13.788a.75.75 0 0 1 1.06 0Z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
Launch
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -121,7 +121,7 @@ export function NewPostScreen() {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="flex flex-1 flex-col gap-4">
|
||||
<div className="flex h-[500px] flex-1 flex-col gap-4">
|
||||
<div className="flex-1 overflow-y-auto">
|
||||
<div ref={containerRef} style={{ height: `${height}px` }}>
|
||||
<EditorContent
|
||||
|
||||
@@ -11,7 +11,7 @@ import NDK, {
|
||||
NostrEvent,
|
||||
} from '@nostr-dev-kit/ndk';
|
||||
import { ndkAdapter } from '@nostr-fetch/adapter-ndk';
|
||||
import { configDir, resolveResource } from '@tauri-apps/api/path';
|
||||
import { appConfigDir, resolveResource } from '@tauri-apps/api/path';
|
||||
import { invoke } from '@tauri-apps/api/primitives';
|
||||
import { open } from '@tauri-apps/plugin-dialog';
|
||||
import { readBinaryFile } from '@tauri-apps/plugin-fs';
|
||||
@@ -28,12 +28,12 @@ import {
|
||||
import { nip19 } from 'nostr-tools';
|
||||
import { NDKCacheAdapterTauri } from '@libs/cache';
|
||||
import {
|
||||
Account,
|
||||
NDKCacheUser,
|
||||
NDKCacheUserProfile,
|
||||
NDKEventWithReplies,
|
||||
NIP05,
|
||||
Widget,
|
||||
type Account,
|
||||
type NDKCacheUser,
|
||||
type NDKCacheUserProfile,
|
||||
type NDKEventWithReplies,
|
||||
type NIP05,
|
||||
type WidgetProps,
|
||||
} from '@utils/types';
|
||||
|
||||
export class Ark {
|
||||
@@ -69,7 +69,7 @@ export class Ark {
|
||||
|
||||
public async launchDepot() {
|
||||
const configPath = await resolveResource('resources/config.toml');
|
||||
const dataPath = await configDir();
|
||||
const dataPath = await appConfigDir();
|
||||
|
||||
const command = Command.sidecar('bin/depot', ['-c', configPath, '-d', dataPath]);
|
||||
this.#depot = await command.spawn();
|
||||
@@ -77,11 +77,29 @@ export class Ark {
|
||||
|
||||
public async connectDepot() {
|
||||
if (!this.#depot) return;
|
||||
return this.ndk.addExplicitRelay(
|
||||
new NDKRelay('ws://localhost:6090'),
|
||||
undefined,
|
||||
true
|
||||
);
|
||||
|
||||
// connect
|
||||
this.ndk.addExplicitRelay(new NDKRelay('ws://localhost:6090'), undefined, true);
|
||||
|
||||
const relayEvent = await this.ndk.fetchEvent({
|
||||
kinds: [NDKKind.RelayList],
|
||||
authors: [this.account.pubkey],
|
||||
});
|
||||
|
||||
if (!relayEvent) {
|
||||
// create new relay list
|
||||
return await this.createEvent({
|
||||
kind: NDKKind.RelayList,
|
||||
tags: [['r', 'ws://localhost:6090', '']],
|
||||
});
|
||||
}
|
||||
|
||||
// update old relay list
|
||||
relayEvent.tags.push(['r', 'ws://localhost:6090', '']);
|
||||
return await this.createEvent({
|
||||
kind: NDKKind.RelayList,
|
||||
tags: relayEvent.tags,
|
||||
});
|
||||
}
|
||||
|
||||
public checkDepot() {
|
||||
@@ -325,7 +343,7 @@ export class Ark {
|
||||
}
|
||||
|
||||
public async getWidgets() {
|
||||
const widgets: Array<Widget> = await this.#storage.select(
|
||||
const widgets: Array<WidgetProps> = await this.#storage.select(
|
||||
'SELECT * FROM widgets WHERE account_id = $1 ORDER BY created_at DESC;',
|
||||
[this.account.id]
|
||||
);
|
||||
@@ -339,7 +357,7 @@ export class Ark {
|
||||
);
|
||||
|
||||
if (insert) {
|
||||
const widgets: Array<Widget> = await this.#storage.select(
|
||||
const widgets: Array<WidgetProps> = await this.#storage.select(
|
||||
'SELECT * FROM widgets ORDER BY id DESC LIMIT 1;'
|
||||
);
|
||||
if (widgets.length < 1) console.error('get created widget failed');
|
||||
|
||||
@@ -18,7 +18,7 @@ export function ActiveAccount() {
|
||||
encodeURIComponent(minidenticon(ark.account.pubkey, 90, 50));
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-1 rounded-lg bg-black/10 p-1 ring-1 ring-transparent hover:bg-black/20 hover:ring-blue-500 dark:bg-white/10 dark:hover:bg-white/20">
|
||||
<div className="flex flex-col gap-1 rounded-xl bg-black/10 p-1 ring-1 ring-transparent hover:bg-black/20 hover:ring-blue-500 dark:bg-white/10 dark:hover:bg-white/20">
|
||||
<Link to="/settings/" className="relative inline-block">
|
||||
<Avatar.Root>
|
||||
<Avatar.Image
|
||||
@@ -27,13 +27,13 @@ export function ActiveAccount() {
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
style={{ contentVisibility: 'auto' }}
|
||||
className="aspect-square h-auto w-full rounded-md object-cover"
|
||||
className="aspect-square h-auto w-full rounded-lg object-cover"
|
||||
/>
|
||||
<Avatar.Fallback delayMs={150}>
|
||||
<img
|
||||
src={svgURI}
|
||||
alt={ark.account.pubkey}
|
||||
className="aspect-square h-auto w-full rounded-md bg-black dark:bg-white"
|
||||
className="aspect-square h-auto w-full rounded-lg bg-black dark:bg-white"
|
||||
/>
|
||||
</Avatar.Fallback>
|
||||
</Avatar.Root>
|
||||
|
||||
@@ -4,9 +4,7 @@ import { Navigation } from '@shared/navigation';
|
||||
export function HomeLayout() {
|
||||
return (
|
||||
<div className="flex h-full w-full">
|
||||
<div className="w-[68px] shrink-0">
|
||||
<Navigation />
|
||||
</div>
|
||||
<Navigation />
|
||||
<div className="min-h-0 flex-1 rounded-tl-lg bg-white shadow-[rgba(50,_50,_105,_0.15)_0px_2px_5px_0px,_rgba(0,_0,_0,_0.05)_0px_1px_1px_0px] dark:bg-black dark:shadow-[inset_0_0_0.5px_1px_hsla(0,0%,100%,0.075),0_0_0_1px_hsla(0,0%,0%,0.05),0_0.3px_0.4px_hsla(0,0%,0%,0.02),0_0.9px_1.5px_hsla(0,0%,0%,0.045),0_3.5px_6px_hsla(0,0%,0%,0.09)]">
|
||||
<Outlet />
|
||||
</div>
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
|
||||
export function Navigation() {
|
||||
return (
|
||||
<div className="flex h-full w-full flex-col justify-between p-3">
|
||||
<div className="flex h-full w-20 shrink-0 flex-col justify-between px-4 py-3">
|
||||
<div className="flex flex-1 flex-col gap-5">
|
||||
<NavLink
|
||||
to="/"
|
||||
@@ -33,8 +33,10 @@ export function Navigation() {
|
||||
</div>
|
||||
<div
|
||||
className={twMerge(
|
||||
'text-sm text-black dark:text-white',
|
||||
isActive ? 'font-semibold' : 'font-medium'
|
||||
'text-sm',
|
||||
isActive
|
||||
? 'font-semibold text-black dark:text-white'
|
||||
: 'font-medium text-black/50 dark:text-white/50'
|
||||
)}
|
||||
>
|
||||
Home
|
||||
@@ -61,8 +63,10 @@ export function Navigation() {
|
||||
</div>
|
||||
<div
|
||||
className={twMerge(
|
||||
'text-sm text-black dark:text-white',
|
||||
isActive ? 'font-semibold' : 'font-medium'
|
||||
'text-sm',
|
||||
isActive
|
||||
? 'font-semibold text-black dark:text-white'
|
||||
: 'font-medium text-black/50 dark:text-white/50'
|
||||
)}
|
||||
>
|
||||
Relays
|
||||
@@ -89,8 +93,10 @@ export function Navigation() {
|
||||
</div>
|
||||
<div
|
||||
className={twMerge(
|
||||
'text-sm text-black dark:text-white',
|
||||
isActive ? 'font-semibold' : 'font-medium'
|
||||
'text-sm',
|
||||
isActive
|
||||
? 'font-semibold text-black dark:text-white'
|
||||
: 'font-medium text-black/50 dark:text-white/50'
|
||||
)}
|
||||
>
|
||||
Depot
|
||||
@@ -117,8 +123,10 @@ export function Navigation() {
|
||||
</div>
|
||||
<div
|
||||
className={twMerge(
|
||||
'text-sm text-black dark:text-white',
|
||||
isActive ? 'font-semibold' : 'font-medium'
|
||||
'text-sm',
|
||||
isActive
|
||||
? 'font-semibold text-black dark:text-white'
|
||||
: 'font-medium text-black/50 dark:text-white/50'
|
||||
)}
|
||||
>
|
||||
Wallet
|
||||
|
||||
Reference in New Issue
Block a user