feat(ui): update ui consistent

This commit is contained in:
reya 2023-12-19 10:13:52 +07:00
parent ec2ac2dce3
commit d9e8d05db7
26 changed files with 669 additions and 517 deletions

View File

@ -34,7 +34,7 @@
"@radix-ui/react-switch": "^1.0.3", "@radix-ui/react-switch": "^1.0.3",
"@radix-ui/react-toolbar": "^1.0.4", "@radix-ui/react-toolbar": "^1.0.4",
"@radix-ui/react-tooltip": "^1.0.7", "@radix-ui/react-tooltip": "^1.0.7",
"@tanstack/react-query": "^5.14.0", "@tanstack/react-query": "^5.14.1",
"@tauri-apps/api": "2.0.0-alpha.11", "@tauri-apps/api": "2.0.0-alpha.11",
"@tauri-apps/cli": "2.0.0-alpha.17", "@tauri-apps/cli": "2.0.0-alpha.17",
"@tauri-apps/plugin-autostart": "2.0.0-alpha.3", "@tauri-apps/plugin-autostart": "2.0.0-alpha.3",
@ -84,18 +84,18 @@
"tippy.js": "^6.3.7", "tippy.js": "^6.3.7",
"tiptap-markdown": "^0.8.8", "tiptap-markdown": "^0.8.8",
"use-react-workers": "^0.3.0", "use-react-workers": "^0.3.0",
"virtua": "^0.17.5" "virtua": "^0.17.6"
}, },
"devDependencies": { "devDependencies": {
"@tailwindcss/forms": "^0.5.7", "@tailwindcss/forms": "^0.5.7",
"@tailwindcss/typography": "^0.5.10", "@tailwindcss/typography": "^0.5.10",
"@trivago/prettier-plugin-sort-imports": "^4.3.0", "@trivago/prettier-plugin-sort-imports": "^4.3.0",
"@types/html-to-text": "^9.0.4", "@types/html-to-text": "^9.0.4",
"@types/node": "^20.10.4", "@types/node": "^20.10.5",
"@types/react": "^18.2.45", "@types/react": "^18.2.45",
"@types/react-dom": "^18.2.18", "@types/react-dom": "^18.2.18",
"@typescript-eslint/eslint-plugin": "^6.14.0", "@typescript-eslint/eslint-plugin": "^6.15.0",
"@typescript-eslint/parser": "^6.14.0", "@typescript-eslint/parser": "^6.15.0",
"@vitejs/plugin-react-swc": "^3.5.0", "@vitejs/plugin-react-swc": "^3.5.0",
"autoprefixer": "^10.4.16", "autoprefixer": "^10.4.16",
"clsx": "^2.0.0", "clsx": "^2.0.0",
@ -114,7 +114,7 @@
"prop-types": "^15.8.1", "prop-types": "^15.8.1",
"tailwind-merge": "^1.14.0", "tailwind-merge": "^1.14.0",
"tailwind-scrollbar": "^3.0.5", "tailwind-scrollbar": "^3.0.5",
"tailwindcss": "^3.3.6", "tailwindcss": "^3.3.7",
"typescript": "^5.3.3", "typescript": "^5.3.3",
"vite": "^5.0.10", "vite": "^5.0.10",
"vite-tsconfig-paths": "^4.2.2" "vite-tsconfig-paths": "^4.2.2"

File diff suppressed because it is too large Load Diff

52
src-tauri/Cargo.lock generated
View File

@ -327,9 +327,9 @@ dependencies = [
[[package]] [[package]]
name = "async-task" name = "async-task"
version = "4.5.0" version = "4.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4eb2cdb97421e01129ccb49169d8279ed21e829929144f4a22a6e54ac549ca1" checksum = "e1d90cd0b264dfdd8eb5bad0a2c217c1f88fa96a8573f40e7b12de23fb468f46"
[[package]] [[package]]
name = "async-trait" name = "async-trait"
@ -646,9 +646,9 @@ dependencies = [
[[package]] [[package]]
name = "cargo_toml" name = "cargo_toml"
version = "0.17.1" version = "0.17.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d1ece59890e746567b467253aea0adbe8a21784d0b025d8a306f66c391c2957" checksum = "8a969e13a7589e9e3e4207e153bae624ade2b5622fb4684a4923b23ec3d57719"
dependencies = [ dependencies = [
"serde", "serde",
"toml 0.8.2", "toml 0.8.2",
@ -2208,9 +2208,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
[[package]] [[package]]
name = "hyper" name = "hyper"
version = "0.14.27" version = "0.14.28"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80"
dependencies = [ dependencies = [
"bytes", "bytes",
"futures-channel", "futures-channel",
@ -2223,7 +2223,7 @@ dependencies = [
"httpdate", "httpdate",
"itoa 1.0.10", "itoa 1.0.10",
"pin-project-lite", "pin-project-lite",
"socket2 0.4.10", "socket2 0.5.5",
"tokio", "tokio",
"tower-service", "tower-service",
"tracing", "tracing",
@ -3937,9 +3937,9 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
[[package]] [[package]]
name = "reqwest" name = "reqwest"
version = "0.11.22" version = "0.11.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41"
dependencies = [ dependencies = [
"base64", "base64",
"bytes", "bytes",
@ -5064,7 +5064,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-plugin-autostart" name = "tauri-plugin-autostart"
version = "2.0.0-alpha.5" version = "2.0.0-alpha.5"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#68cb23f9c0722343a79096044122a811fd8cc059" source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#b1c6a7885e6aa036ec08b332bffa82b99a794e85"
dependencies = [ dependencies = [
"auto-launch", "auto-launch",
"log", "log",
@ -5077,7 +5077,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-plugin-cli" name = "tauri-plugin-cli"
version = "2.0.0-alpha.5" version = "2.0.0-alpha.5"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#68cb23f9c0722343a79096044122a811fd8cc059" source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#b1c6a7885e6aa036ec08b332bffa82b99a794e85"
dependencies = [ dependencies = [
"clap", "clap",
"log", "log",
@ -5090,7 +5090,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-plugin-clipboard-manager" name = "tauri-plugin-clipboard-manager"
version = "2.0.0-alpha.5" version = "2.0.0-alpha.5"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#68cb23f9c0722343a79096044122a811fd8cc059" source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#b1c6a7885e6aa036ec08b332bffa82b99a794e85"
dependencies = [ dependencies = [
"arboard", "arboard",
"log", "log",
@ -5104,7 +5104,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-plugin-dialog" name = "tauri-plugin-dialog"
version = "2.0.0-alpha.5" version = "2.0.0-alpha.5"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#68cb23f9c0722343a79096044122a811fd8cc059" source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#b1c6a7885e6aa036ec08b332bffa82b99a794e85"
dependencies = [ dependencies = [
"glib 0.16.9", "glib 0.16.9",
"log", "log",
@ -5121,7 +5121,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-plugin-fs" name = "tauri-plugin-fs"
version = "2.0.0-alpha.5" version = "2.0.0-alpha.5"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#68cb23f9c0722343a79096044122a811fd8cc059" source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#b1c6a7885e6aa036ec08b332bffa82b99a794e85"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"glob", "glob",
@ -5134,7 +5134,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-plugin-http" name = "tauri-plugin-http"
version = "2.0.0-alpha.6" version = "2.0.0-alpha.6"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#68cb23f9c0722343a79096044122a811fd8cc059" source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#b1c6a7885e6aa036ec08b332bffa82b99a794e85"
dependencies = [ dependencies = [
"data-url", "data-url",
"glob", "glob",
@ -5151,7 +5151,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-plugin-notification" name = "tauri-plugin-notification"
version = "2.0.0-alpha.6" version = "2.0.0-alpha.6"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#68cb23f9c0722343a79096044122a811fd8cc059" source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#b1c6a7885e6aa036ec08b332bffa82b99a794e85"
dependencies = [ dependencies = [
"log", "log",
"notify-rust", "notify-rust",
@ -5169,7 +5169,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-plugin-os" name = "tauri-plugin-os"
version = "2.0.0-alpha.5" version = "2.0.0-alpha.5"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#68cb23f9c0722343a79096044122a811fd8cc059" source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#b1c6a7885e6aa036ec08b332bffa82b99a794e85"
dependencies = [ dependencies = [
"gethostname 0.4.3", "gethostname 0.4.3",
"log", "log",
@ -5185,7 +5185,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-plugin-process" name = "tauri-plugin-process"
version = "2.0.0-alpha.5" version = "2.0.0-alpha.5"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#68cb23f9c0722343a79096044122a811fd8cc059" source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#b1c6a7885e6aa036ec08b332bffa82b99a794e85"
dependencies = [ dependencies = [
"tauri", "tauri",
] ]
@ -5193,7 +5193,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-plugin-shell" name = "tauri-plugin-shell"
version = "2.0.0-alpha.5" version = "2.0.0-alpha.5"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#68cb23f9c0722343a79096044122a811fd8cc059" source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#b1c6a7885e6aa036ec08b332bffa82b99a794e85"
dependencies = [ dependencies = [
"encoding_rs", "encoding_rs",
"log", "log",
@ -5210,7 +5210,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-plugin-sql" name = "tauri-plugin-sql"
version = "2.0.0-alpha.5" version = "2.0.0-alpha.5"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#68cb23f9c0722343a79096044122a811fd8cc059" source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#b1c6a7885e6aa036ec08b332bffa82b99a794e85"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"log", "log",
@ -5226,7 +5226,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-plugin-store" name = "tauri-plugin-store"
version = "2.0.0-alpha.5" version = "2.0.0-alpha.5"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#68cb23f9c0722343a79096044122a811fd8cc059" source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#b1c6a7885e6aa036ec08b332bffa82b99a794e85"
dependencies = [ dependencies = [
"log", "log",
"serde", "serde",
@ -5254,7 +5254,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-plugin-updater" name = "tauri-plugin-updater"
version = "2.0.0-alpha.5" version = "2.0.0-alpha.5"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#68cb23f9c0722343a79096044122a811fd8cc059" source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#b1c6a7885e6aa036ec08b332bffa82b99a794e85"
dependencies = [ dependencies = [
"base64", "base64",
"dirs-next", "dirs-next",
@ -5280,7 +5280,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-plugin-upload" name = "tauri-plugin-upload"
version = "2.0.0-alpha.5" version = "2.0.0-alpha.5"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#68cb23f9c0722343a79096044122a811fd8cc059" source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#b1c6a7885e6aa036ec08b332bffa82b99a794e85"
dependencies = [ dependencies = [
"futures-util", "futures-util",
"log", "log",
@ -5297,7 +5297,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-plugin-window-state" name = "tauri-plugin-window-state"
version = "2.0.0-alpha.5" version = "2.0.0-alpha.5"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#68cb23f9c0722343a79096044122a811fd8cc059" source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#b1c6a7885e6aa036ec08b332bffa82b99a794e85"
dependencies = [ dependencies = [
"bincode", "bincode",
"bitflags 2.4.1", "bitflags 2.4.1",
@ -6430,9 +6430,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
[[package]] [[package]]
name = "winnow" name = "winnow"
version = "0.5.28" version = "0.5.30"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c830786f7720c2fd27a1a0e27a709dbd3c4d009b56d098fc742d4f4eab91fe2" checksum = "9b5c3db89721d50d0e2a673f5043fc4722f76dcc352d7b1ab8b8288bed4ed2c5"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]

View File

@ -122,6 +122,69 @@ export default function App() {
}, },
], ],
}, },
{
path: 'settings',
element: <SettingsLayout />,
children: [
{
index: true,
async lazy() {
const { UserSettingScreen } = await import('@app/settings');
return { Component: UserSettingScreen };
},
},
{
path: 'edit-profile',
async lazy() {
const { EditProfileScreen } = await import(
'@app/settings/editProfile'
);
return { Component: EditProfileScreen };
},
},
{
path: 'edit-contact',
async lazy() {
const { EditContactScreen } = await import(
'@app/settings/editContact'
);
return { Component: EditContactScreen };
},
},
{
path: 'general',
async lazy() {
const { GeneralSettingScreen } = await import(
'@app/settings/general'
);
return { Component: GeneralSettingScreen };
},
},
{
path: 'backup',
async lazy() {
const { BackupSettingScreen } = await import('@app/settings/backup');
return { Component: BackupSettingScreen };
},
},
{
path: 'advanced',
async lazy() {
const { AdvancedSettingScreen } = await import(
'@app/settings/advanced'
);
return { Component: AdvancedSettingScreen };
},
},
{
path: 'about',
async lazy() {
const { AboutScreen } = await import('@app/settings/about');
return { Component: AboutScreen };
},
},
],
},
], ],
}, },
], ],
@ -203,62 +266,6 @@ export default function App() {
}, },
], ],
}, },
{
path: 'settings',
element: <SettingsLayout platform={ark.platform} />,
errorElement: <ErrorScreen />,
children: [
{
index: true,
async lazy() {
const { UserSettingScreen } = await import('@app/settings');
return { Component: UserSettingScreen };
},
},
{
path: 'edit-profile',
async lazy() {
const { EditProfileScreen } = await import('@app/settings/editProfile');
return { Component: EditProfileScreen };
},
},
{
path: 'edit-contact',
async lazy() {
const { EditContactScreen } = await import('@app/settings/editContact');
return { Component: EditContactScreen };
},
},
{
path: 'general',
async lazy() {
const { GeneralSettingScreen } = await import('@app/settings/general');
return { Component: GeneralSettingScreen };
},
},
{
path: 'backup',
async lazy() {
const { BackupSettingScreen } = await import('@app/settings/backup');
return { Component: BackupSettingScreen };
},
},
{
path: 'advanced',
async lazy() {
const { AdvancedSettingScreen } = await import('@app/settings/advanced');
return { Component: AdvancedSettingScreen };
},
},
{
path: 'about',
async lazy() {
const { AboutScreen } = await import('@app/settings/about');
return { Component: AboutScreen };
},
},
],
},
]); ]);
return ( return (

View File

@ -1,5 +1,5 @@
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { useArk } from '@libs/ark/provider'; import { useArk } from '@libs/ark';
import { NoteChildUser } from './childUser'; import { NoteChildUser } from './childUser';
export function NoteChild({ eventId, isRoot }: { eventId: string; isRoot?: boolean }) { export function NoteChild({ eventId, isRoot }: { eventId: string; isRoot?: boolean }) {

View File

@ -2,7 +2,7 @@ import * as Avatar from '@radix-ui/react-avatar';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { minidenticon } from 'minidenticons'; import { minidenticon } from 'minidenticons';
import { useMemo } from 'react'; import { useMemo } from 'react';
import { useArk } from '@libs/ark/provider'; import { useArk } from '@libs/ark';
import { displayNpub } from '@utils/formater'; import { displayNpub } from '@utils/formater';
export function NoteChildUser({ pubkey, subtext }: { pubkey: string; subtext: string }) { export function NoteChildUser({ pubkey, subtext }: { pubkey: string; subtext: string }) {

View File

@ -1,10 +1,22 @@
import { twMerge } from 'tailwind-merge';
import { useRichContent } from '@utils/hooks/useRichContent'; import { useRichContent } from '@utils/hooks/useRichContent';
export function NoteContent({ content }: { content: string }) { export function NoteContent({
content,
className,
}: {
content: string;
className?: string;
}) {
const { parsedContent } = useRichContent(content); const { parsedContent } = useRichContent(content);
return ( return (
<div className="break-p select-text whitespace-pre-line leading-normal"> <div
className={twMerge(
'break-p select-text whitespace-pre-line leading-normal',
className
)}
>
{parsedContent} {parsedContent}
</div> </div>
); );

View File

@ -1,5 +1,6 @@
import { NoteChild } from './child'; import { NoteChild } from './child';
import { NoteContent } from './content'; import { NoteContent } from './content';
import { NoteMenu } from './menu';
import { NoteReaction } from './reaction'; import { NoteReaction } from './reaction';
import { NoteReply } from './reply'; import { NoteReply } from './reply';
import { NoteRepost } from './repost'; import { NoteRepost } from './repost';
@ -10,6 +11,7 @@ import { NoteZap } from './zap';
export const Note = { export const Note = {
Root: NoteRoot, Root: NoteRoot,
User: NoteUser, User: NoteUser,
Menu: NoteMenu,
Content: NoteContent, Content: NoteContent,
Reply: NoteReply, Reply: NoteReply,
Repost: NoteRepost, Repost: NoteRepost,

View File

@ -1,5 +1,5 @@
import { NDKEvent } from '@nostr-dev-kit/ndk'; import { NDKEvent } from '@nostr-dev-kit/ndk';
import { useArk } from '@libs/ark/provider'; import { useArk } from '@libs/ark';
import { Note } from '..'; import { Note } from '..';
export function TextNote({ event }: { event: NDKEvent }) { export function TextNote({ event }: { event: NDKEvent }) {
@ -8,9 +8,12 @@ export function TextNote({ event }: { event: NDKEvent }) {
return ( return (
<Note.Root> <Note.Root>
<Note.User pubkey={event.pubkey} time={event.created_at} /> <div className="flex h-14 items-center justify-between gap-2 px-3">
<Note.User pubkey={event.pubkey} time={event.created_at} className="w-full" />
<Note.Menu eventId={event.id} pubkey={event.pubkey} />
</div>
{thread ? ( {thread ? (
<div className="w-full px-3"> <div className="mb-2 w-full px-3">
<div className="flex h-min w-full flex-col gap-3 rounded-lg bg-neutral-100 p-3 dark:bg-neutral-900"> <div className="flex h-min w-full flex-col gap-3 rounded-lg bg-neutral-100 p-3 dark:bg-neutral-900">
{thread.rootEventId ? ( {thread.rootEventId ? (
<Note.Child eventId={thread.rootEventId} isRoot /> <Note.Child eventId={thread.rootEventId} isRoot />
@ -25,7 +28,7 @@ export function TextNote({ event }: { event: NDKEvent }) {
</div> </div>
</div> </div>
) : null} ) : null}
<Note.Content content={event.content} /> <Note.Content content={event.content} className="px-3" />
<div className="flex h-14 items-center justify-between px-3"> <div className="flex h-14 items-center justify-between px-3">
<div /> <div />
<div className="inline-flex items-center gap-10"> <div className="inline-flex items-center gap-10">

View File

@ -0,0 +1,64 @@
import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
import { writeText } from '@tauri-apps/plugin-clipboard-manager';
import { nip19 } from 'nostr-tools';
import { EventPointer } from 'nostr-tools/lib/types/nip19';
import { useState } from 'react';
import { Link } from 'react-router-dom';
import { HorizontalDotsIcon } from '@shared/icons';
export function NoteMenu({ eventId, pubkey }: { eventId: string; pubkey: string }) {
const [open, setOpen] = useState(false);
const copyID = async () => {
await writeText(nip19.neventEncode({ id: eventId, author: pubkey } as EventPointer));
setOpen(false);
};
const copyLink = async () => {
await writeText(
'https://njump.me/' +
nip19.neventEncode({ id: eventId, author: pubkey } as EventPointer)
);
setOpen(false);
};
return (
<DropdownMenu.Root open={open} onOpenChange={setOpen}>
<DropdownMenu.Trigger asChild>
<button type="button" className="inline-flex h-6 w-6 items-center justify-center">
<HorizontalDotsIcon className="h-4 w-4 text-neutral-800 hover:text-blue-500 dark:text-neutral-200" />
</button>
</DropdownMenu.Trigger>
<DropdownMenu.Portal>
<DropdownMenu.Content className="flex w-[200px] flex-col overflow-hidden rounded-xl border border-neutral-200 bg-neutral-100 focus:outline-none dark:border-neutral-800 dark:bg-neutral-900">
<DropdownMenu.Item asChild>
<button
type="button"
onClick={() => copyLink()}
className="inline-flex h-10 items-center px-4 text-sm text-neutral-900 hover:bg-neutral-200 focus:outline-none dark:text-neutral-100 dark:hover:bg-neutral-800"
>
Copy shareable link
</button>
</DropdownMenu.Item>
<DropdownMenu.Item asChild>
<button
type="button"
onClick={() => copyID()}
className="inline-flex h-10 items-center px-4 text-sm text-neutral-900 hover:bg-neutral-200 focus:outline-none dark:text-neutral-100 dark:hover:bg-neutral-800"
>
Copy ID
</button>
</DropdownMenu.Item>
<DropdownMenu.Item asChild>
<Link
to={`/users/${pubkey}`}
className="inline-flex h-10 items-center px-4 text-sm text-neutral-900 hover:bg-neutral-200 focus:outline-none dark:text-neutral-100 dark:hover:bg-neutral-800"
>
View profile
</Link>
</DropdownMenu.Item>
</DropdownMenu.Content>
</DropdownMenu.Portal>
</DropdownMenu.Root>
);
}

View File

@ -10,7 +10,7 @@ export function NoteRoot({
}) { }) {
return ( return (
<div className={twMerge('h-min w-full p-3', className)}> <div className={twMerge('h-min w-full p-3', className)}>
<div className="relative flex flex-col gap-2 overflow-hidden rounded-xl bg-neutral-50 dark:bg-neutral-950"> <div className="relative flex flex-col overflow-hidden rounded-xl bg-neutral-50 dark:bg-neutral-950">
{children} {children}
</div> </div>
</div> </div>

View File

@ -2,6 +2,7 @@ import * as Avatar from '@radix-ui/react-avatar';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { minidenticon } from 'minidenticons'; import { minidenticon } from 'minidenticons';
import { useMemo } from 'react'; import { useMemo } from 'react';
import { twMerge } from 'tailwind-merge';
import { useArk } from '@libs/ark'; import { useArk } from '@libs/ark';
import { RepostIcon } from '@shared/icons'; import { RepostIcon } from '@shared/icons';
import { displayNpub, formatCreatedAt } from '@utils/formater'; import { displayNpub, formatCreatedAt } from '@utils/formater';
@ -10,10 +11,12 @@ export function NoteUser({
pubkey, pubkey,
time, time,
variant = 'text', variant = 'text',
className,
}: { }: {
pubkey: string; pubkey: string;
time: number; time: number;
variant?: 'text' | 'repost'; variant?: 'text' | 'repost';
className?: string;
}) { }) {
const ark = useArk(); const ark = useArk();
const createdAt = useMemo(() => formatCreatedAt(time), [time]); const createdAt = useMemo(() => formatCreatedAt(time), [time]);
@ -48,7 +51,7 @@ export function NoteUser({
if (variant === 'repost') { if (variant === 'repost') {
if (isLoading) { if (isLoading) {
return ( return (
<div className="flex gap-3"> <div className={twMerge('flex gap-3', className)}>
<div className="inline-flex w-10 items-center justify-center"> <div className="inline-flex w-10 items-center justify-center">
<RepostIcon className="h-5 w-5 text-blue-500" /> <RepostIcon className="h-5 w-5 text-blue-500" />
</div> </div>
@ -61,7 +64,7 @@ export function NoteUser({
} }
return ( return (
<div className="flex gap-2"> <div className={twMerge('flex gap-2', className)}>
<div className="inline-flex w-10 items-center justify-center"> <div className="inline-flex w-10 items-center justify-center">
<RepostIcon className="h-5 w-5 text-blue-500" /> <RepostIcon className="h-5 w-5 text-blue-500" />
</div> </div>
@ -95,7 +98,7 @@ export function NoteUser({
if (isLoading) { if (isLoading) {
return ( return (
<div className="flex items-center gap-3"> <div className={twMerge('flex items-center gap-3', className)}>
<Avatar.Root className="h-9 w-9 shrink-0"> <Avatar.Root className="h-9 w-9 shrink-0">
<Avatar.Image <Avatar.Image
src={fallbackAvatar} src={fallbackAvatar}
@ -113,7 +116,7 @@ export function NoteUser({
} }
return ( return (
<div className="flex items-center gap-3"> <div className={twMerge('flex items-center gap-3', className)}>
<Avatar.Root className="h-9 w-9 shrink-0"> <Avatar.Root className="h-9 w-9 shrink-0">
<Avatar.Image <Avatar.Image
src={user?.picture || user?.image} src={user?.picture || user?.image}
@ -130,13 +133,11 @@ export function NoteUser({
/> />
</Avatar.Fallback> </Avatar.Fallback>
</Avatar.Root> </Avatar.Root>
<div className="flex h-6 flex-1 items-start gap-2"> <div className="flex h-6 flex-1 items-start justify-between gap-2">
<div className="max-w-[15rem] truncate font-semibold text-neutral-950 dark:text-neutral-50"> <div className="max-w-[15rem] truncate font-semibold text-neutral-950 dark:text-neutral-50">
{user?.name || user?.display_name || user?.displayName || fallbackName} {user?.name || user?.display_name || user?.displayName || fallbackName}
</div> </div>
<div className="ml-auto inline-flex items-center gap-3"> <div className="text-neutral-500 dark:text-neutral-400">{createdAt}</div>
<div className="text-neutral-500 dark:text-neutral-400">{createdAt}</div>
</div>
</div> </div>
</div> </div>
); );

View File

@ -4,9 +4,9 @@ import { ReactNode } from 'react';
import { import {
ArrowLeftIcon, ArrowLeftIcon,
ArrowRightIcon, ArrowRightIcon,
HomeIcon,
HorizontalDotsIcon, HorizontalDotsIcon,
RefreshIcon, RefreshIcon,
ThreadIcon,
TrashIcon, TrashIcon,
} from '@shared/icons'; } from '@shared/icons';
import { useWidget } from '@utils/hooks/useWidget'; import { useWidget } from '@utils/hooks/useWidget';
@ -19,14 +19,14 @@ export function WidgetHeader({
}: { }: {
id: string; id: string;
title: string; title: string;
queryKey?: string; queryKey?: string[];
icon?: ReactNode; icon?: ReactNode;
}) { }) {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const { removeWidget } = useWidget(); const { removeWidget } = useWidget();
const refresh = async () => { const refresh = async () => {
if (queryKey) await queryClient.refetchQueries({ queryKey: [queryKey] }); if (queryKey) await queryClient.refetchQueries({ queryKey });
}; };
const moveLeft = async () => { const moveLeft = async () => {
@ -46,7 +46,7 @@ export function WidgetHeader({
<div className="inline-flex items-center gap-4"> <div className="inline-flex items-center gap-4">
<div className="h-5 w-1 rounded-full bg-blue-500" /> <div className="h-5 w-1 rounded-full bg-blue-500" />
<div className="inline-flex items-center gap-2"> <div className="inline-flex items-center gap-2">
{icon ? icon : <HomeIcon className="h-5 w-5" />} {icon ? icon : <ThreadIcon className="h-5 w-5" />}
<div className="text-sm font-medium">{title}</div> <div className="text-sm font-medium">{title}</div>
</div> </div>
</div> </div>

View File

@ -18,7 +18,7 @@ export function ActiveAccount() {
encodeURIComponent(minidenticon(ark.account.pubkey, 90, 50)); encodeURIComponent(minidenticon(ark.account.pubkey, 90, 50));
return ( return (
<div className="flex flex-col gap-1 rounded-lg bg-neutral-100 p-1 ring-1 ring-transparent hover:bg-neutral-200 hover:ring-blue-500 dark:bg-neutral-900 dark:hover:bg-neutral-800"> <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">
<Link to="/settings/" className="relative inline-block"> <Link to="/settings/" className="relative inline-block">
<Avatar.Root> <Avatar.Root>
<Avatar.Image <Avatar.Image

View File

@ -0,0 +1,18 @@
export function DepotIcon(props: JSX.IntrinsicElements['svg']) {
return (
<svg
{...props}
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24"
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
>
<path d="M20 5.7V12m0-6.3c0 1.491-3.582 2.7-8 2.7S4 7.191 4 5.7m16 0C20 4.209 16.418 3 12 3S4 4.209 4 5.7M20 12v6.131C20 19.716 16.418 21 12 21s-8-1.284-8-2.869V12m16 0c0 1.491-3.582 2.7-8 2.7S4 13.491 4 12m0 0V5.7M16 11h.01M16 17h.01" />
</svg>
);
}

View File

@ -85,3 +85,5 @@ export * from './light';
export * from './dark'; export * from './dark';
export * from './system'; export * from './system';
export * from './announcement'; export * from './announcement';
export * from './depot';
export * from './search';

View File

@ -1,19 +1,18 @@
import { SVGProps } from 'react'; export function NwcIcon(props: JSX.IntrinsicElements['svg']) {
export function NwcIcon(props: JSX.IntrinsicAttributes & SVGProps<SVGSVGElement>) {
return ( return (
<svg <svg
{...props}
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24" width="24"
height="24" height="24"
fill="none" fill="none"
viewBox="0 0 24 24" stroke="currentColor"
{...props} strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
> >
<path <path d="M2 14.5V11c0-2.8 0-4.2.545-5.27A5 5 0 0 1 4.73 3.545C5.8 3 7.2 3 10 3h3.5c1.398 0 2.097 0 2.648.228a3 3 0 0 1 1.624 1.624c.207.5.226 1.123.228 2.28M2 14.5c0 1.33 0 2.495.38 3.413a5 5 0 0 0 2.707 2.706c.696.289 1.534.359 2.913.376M2 14.5c0-2.33 0-3.495.38-4.413A5 5 0 0 1 5.088 7.38C6.005 7 7.17 7 9.5 7h5c1.634 0 2.695 0 3.5.131M14 12h3m1-4.869c.343.056.639.136.913.25a5 5 0 0 1 2.706 2.706c.289.696.359 1.534.376 2.913m-3.03 3h.037A2.999 2.999 0 0 1 22 19c0 1.657-1.342 3-2.998 3h-.037m-3.93-6h-.037A2.999 2.999 0 0 0 12 19c0 1.657 1.342 3 2.998 3h.037m.962-3h1.999" />
fill="currentColor"
d="M14.002 2.401c0-1.484-1.925-2.066-2.748-.832L3.188 13.668c-.665.997.05 2.332 1.248 2.332h5.566V21.6c0 1.484 1.925 2.067 2.748.832l8.066-12.099C21.48 9.335 20.766 8 19.568 8h-5.566V2.401z"
></path>
</svg> </svg>
); );
} }

View File

@ -1,15 +1,18 @@
import { SVGProps } from 'react'; export function PlusIcon(props: JSX.IntrinsicElements['svg']) {
export function PlusIcon(props: JSX.IntrinsicAttributes & SVGProps<SVGSVGElement>) {
return ( return (
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" {...props}> <svg
<path {...props}
d="M12 3.75V12M12 12V20.25M12 12H3.75M12 12H20.25" xmlns="http://www.w3.org/2000/svg"
stroke="currentColor" viewBox="0 0 24 24"
strokeWidth={1.5} width="24"
strokeLinecap="round" height="24"
strokeLinejoin="round" fill="none"
/> stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
>
<path d="M12 19v-7m0 0V5m0 7H5m7 0h7" />
</svg> </svg>
); );
} }

View File

@ -1,21 +1,18 @@
import { SVGProps } from 'react'; export function RelayIcon(props: JSX.IntrinsicElements['svg']) {
export function RelayIcon(props: JSX.IntrinsicAttributes & SVGProps<SVGSVGElement>) {
return ( return (
<svg <svg
{...props}
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24" width="24"
height="24" height="24"
fill="none" fill="none"
viewBox="0 0 24 24" stroke="currentColor"
{...props} strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
> >
<path <path d="M7 12h10M7 12c-.464 0-.697 0-.892.022a3.5 3.5 0 0 0-3.086 3.086C3 15.303 3 15.536 3 16s0 .697.022.892a3.5 3.5 0 0 0 3.086 3.086C6.303 20 6.536 20 7 20h10c.464 0 .697 0 .892-.022a3.5 3.5 0 0 0 3.086-3.086C21 16.697 21 16.464 21 16s0-.697-.022-.892a3.5 3.5 0 0 0-3.086-3.086C17.697 12 17.464 12 17 12M7 12c-.464 0-.697 0-.892-.022a3.5 3.5 0 0 1-3.086-3.086C3 8.697 3 8.464 3 8s0-.697.022-.892a3.5 3.5 0 0 1 3.086-3.086C6.303 4 6.536 4 7 4h10c.464 0 .697 0 .892.022a3.5 3.5 0 0 1 3.086 3.086C21 7.303 21 7.536 21 8s0 .697-.022.892a3.5 3.5 0 0 1-3.086 3.086C17.697 12 17.464 12 17 12m-4-4h.01M17 8h.01M13 16h.01M17 16h.01" />
fill="currentColor"
fillRule="evenodd"
d="M4 5a3 3 0 013-3h10a3 3 0 013 3v11c0 .889-.386 1.687-1 2.236V20a2 2 0 01-2 2H7a2 2 0 01-2-2v-1.75-.014c-.614-.55-1-1.348-1-2.236V5zm3-1a1 1 0 00-1 1v11a1 1 0 001 1h10a1 1 0 001-1V5a1 1 0 00-1-1H7zm0 2a1 1 0 011-1h8a1 1 0 011 1v6a1 1 0 01-1 1H8a1 1 0 01-1-1V6zm6 9a1 1 0 011-1h2a1 1 0 110 2h-2a1 1 0 01-1-1z"
clipRule="evenodd"
></path>
</svg> </svg>
); );
} }

View File

@ -0,0 +1,18 @@
export function SearchIcon(props: JSX.IntrinsicElements['svg']) {
return (
<svg
{...props}
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24"
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
>
<path d="m21 21-3.49-3.49m0 0A8.5 8.5 0 1 0 5.49 5.49a8.5 8.5 0 0 0 12.02 12.02Z" />
</svg>
);
}

View File

@ -1,19 +1,18 @@
import { SVGProps } from 'react'; export function ThreadIcon(props: JSX.IntrinsicElements['svg']) {
export function ThreadIcon(props: JSX.IntrinsicAttributes & SVGProps<SVGSVGElement>) {
return ( return (
<svg <svg
{...props}
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24" width="24"
height="24" height="24"
fill="none" fill="none"
viewBox="0 0 24 24" stroke="currentColor"
{...props} strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
> >
<path <path d="M16.193 18.866c.143 0 .306.012.632.036l1.938.138c.771.055 1.157.083 1.446-.054.253-.12.457-.324.577-.577.137-.289.11-.675.054-1.446l-.138-1.938a10.8 10.8 0 0 1-.036-.632c-.002-.232-.005-.15.013-.38.01-.143.088-.685.24-1.768A8.1 8.1 0 0 0 5.642 7.5m8.159 8.1a5.4 5.4 0 1 0-10.733.856c.096.6.144.9.152.992.012.139.011.108.01.247 0 .093-.008.204-.023.428l-.1 1.385c-.036.515-.055.772.037.965a.81.81 0 0 0 .385.384c.192.092.45.073.964.037l1.385-.1a6.97 6.97 0 0 1 .428-.024c.14 0 .108-.001.247.011.093.008.393.056.992.152a5.387 5.387 0 0 0 4.893-1.745 5.38 5.38 0 0 0 1.363-3.588Z" />
fill="currentColor"
d="M12 19v1a1 1 0 001-1h-1zm8-9a1 1 0 102 0h-2zm0 4a1 1 0 10-2 0h2zm-2 6a1 1 0 102 0h-2zm-2-4a1 1 0 100 2v-2zm6 2a1 1 0 100-2v2zM4 17V7H2v10h2zm8 1H5v2h7v-2zm8-11v3h2V7h-2zM5 6h7V4H5v2zm7 0h7V4h-7v2zm1 13V5h-2v14h2zm5-5v3h2v-3h-2zm0 3v3h2v-3h-2zm-2 1h3v-2h-3v2zm3 0h3v-2h-3v2zm3-11a3 3 0 00-3-3v2a1 1 0 011 1h2zM4 7a1 1 0 011-1V4a3 3 0 00-3 3h2zM2 17a3 3 0 003 3v-2a1 1 0 01-1-1H2z"
></path>
</svg> </svg>
); );
} }

View File

@ -1,114 +1,92 @@
import { Platform } from '@tauri-apps/plugin-os'; import { NavLink, Outlet } from 'react-router-dom';
import { NavLink, Outlet, useNavigate } from 'react-router-dom';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
import { import {
AdvancedSettingsIcon, AdvancedSettingsIcon,
ArrowLeftIcon,
InfoIcon, InfoIcon,
SecureIcon, SecureIcon,
SettingsIcon, SettingsIcon,
UserIcon, UserIcon,
} from '@shared/icons'; } from '@shared/icons';
import { WindowTitleBar } from '@shared/titlebar';
export function SettingsLayout({ platform }: { platform: Platform }) {
const navigate = useNavigate();
export function SettingsLayout() {
return ( return (
<div className="flex h-screen w-screen flex-col bg-neutral-50 dark:bg-neutral-950"> <div className="flex h-full min-h-0 w-full flex-col gap-8 overflow-y-auto">
{platform !== 'macos' ? ( <div className="flex h-24 w-full items-center justify-center border-b border-neutral-200 px-2 dark:border-neutral-900">
<WindowTitleBar platform={platform} /> <div className="flex items-center gap-0.5">
) : ( <NavLink
<div data-tauri-drag-region className="h-9 shrink-0" /> to="/settings/"
)} end
<div className="flex h-full min-h-0 w-full flex-col gap-8 overflow-y-auto"> className={({ isActive }) =>
<div className="flex h-20 w-full items-center justify-between border-b border-neutral-200 px-2 pb-2 dark:border-neutral-900"> twMerge(
<div> 'flex w-20 shrink-0 flex-col items-center justify-center rounded-lg px-2 py-2 text-neutral-700 hover:bg-neutral-100 dark:text-neutral-300 dark:hover:bg-neutral-900',
<button isActive
type="button" ? 'bg-neutral-100 text-blue-500 hover:bg-neutral-100 dark:bg-neutral-900 dark:hover:bg-neutral-900'
onClick={() => navigate(-1)} : ''
className="inline-flex h-12 w-12 items-center justify-center rounded-xl" )
> }
<ArrowLeftIcon className="h-5 w-5" /> >
</button> <UserIcon className="h-6 w-6" />
</div> <p className="text-sm font-medium">User</p>
<div className="flex items-center gap-0.5"> </NavLink>
<NavLink <NavLink
to="/settings/" to="/settings/general"
end className={({ isActive }) =>
className={({ isActive }) => twMerge(
twMerge( 'flex w-20 shrink-0 flex-col items-center justify-center rounded-lg px-2 py-2 text-neutral-700 hover:bg-neutral-100 dark:text-neutral-300 dark:hover:bg-neutral-900',
'flex w-20 shrink-0 flex-col items-center justify-center rounded-lg px-2 py-2 text-neutral-700 hover:bg-neutral-100 dark:text-neutral-300 dark:hover:bg-neutral-900', isActive
isActive ? 'bg-neutral-100 text-blue-500 hover:bg-neutral-100 dark:bg-neutral-900 dark:hover:bg-neutral-900'
? 'bg-neutral-50 text-blue-500 hover:bg-neutral-100 dark:bg-neutral-950 dark:hover:bg-neutral-900' : ''
: '' )
) }
} >
> <SettingsIcon className="h-6 w-6" />
<UserIcon className="h-6 w-6" /> <p className="text-sm font-medium">General</p>
<p className="text-sm font-medium">User</p> </NavLink>
</NavLink> <NavLink
<NavLink to="/settings/backup"
to="/settings/general" className={({ isActive }) =>
className={({ isActive }) => twMerge(
twMerge( 'flex w-20 shrink-0 flex-col items-center justify-center rounded-lg px-2 py-2 text-neutral-700 hover:bg-neutral-100 dark:text-neutral-300 dark:hover:bg-neutral-900',
'flex w-20 shrink-0 flex-col items-center justify-center rounded-lg px-2 py-2 text-neutral-700 hover:bg-neutral-100 dark:text-neutral-300 dark:hover:bg-neutral-900', isActive
isActive ? 'bg-neutral-100 text-blue-500 hover:bg-neutral-100 dark:bg-neutral-900 dark:hover:bg-neutral-900'
? 'bg-neutral-50 text-blue-500 hover:bg-neutral-100 dark:bg-neutral-950 dark:hover:bg-neutral-900' : ''
: '' )
) }
} >
> <SecureIcon className="h-6 w-6" />
<SettingsIcon className="h-6 w-6" /> <p className="text-sm font-medium">Backup</p>
<p className="text-sm font-medium">General</p> </NavLink>
</NavLink> <NavLink
<NavLink to="/settings/advanced"
to="/settings/backup" className={({ isActive }) =>
className={({ isActive }) => twMerge(
twMerge( 'flex w-20 shrink-0 flex-col items-center justify-center rounded-lg px-2 py-2 text-neutral-700 hover:bg-neutral-100 dark:text-neutral-300 dark:hover:bg-neutral-900',
'flex w-20 shrink-0 flex-col items-center justify-center rounded-lg px-2 py-2 text-neutral-700 hover:bg-neutral-100 dark:text-neutral-300 dark:hover:bg-neutral-900', isActive
isActive ? 'bg-neutral-100 text-blue-500 hover:bg-neutral-100 dark:bg-neutral-900 dark:hover:bg-neutral-900'
? 'bg-neutral-50 text-blue-500 hover:bg-neutral-100 dark:bg-neutral-950 dark:hover:bg-neutral-900' : ''
: '' )
) }
} >
> <AdvancedSettingsIcon className="h-6 w-6" />
<SecureIcon className="h-6 w-6" /> <p className="text-sm font-medium">Advanced</p>
<p className="text-sm font-medium">Backup</p> </NavLink>
</NavLink> <NavLink
<NavLink to="/settings/about"
to="/settings/advanced" className={({ isActive }) =>
className={({ isActive }) => twMerge(
twMerge( 'flex w-20 shrink-0 flex-col items-center justify-center rounded-lg px-2 py-2 text-neutral-700 hover:bg-neutral-100 dark:text-neutral-300 dark:hover:bg-neutral-900',
'flex w-20 shrink-0 flex-col items-center justify-center rounded-lg px-2 py-2 text-neutral-700 hover:bg-neutral-100 dark:text-neutral-300 dark:hover:bg-neutral-900', isActive
isActive ? 'bg-neutral-100 text-blue-500 hover:bg-neutral-100 dark:bg-neutral-900 dark:hover:bg-neutral-900'
? 'bg-neutral-50 text-blue-500 hover:bg-neutral-100 dark:bg-neutral-950 dark:hover:bg-neutral-900' : ''
: '' )
) }
} >
> <InfoIcon className="h-6 w-6" />
<AdvancedSettingsIcon className="h-6 w-6" /> <p className="text-sm font-medium">About</p>
<p className="text-sm font-medium">Advanced</p> </NavLink>
</NavLink>
<NavLink
to="/settings/about"
className={({ isActive }) =>
twMerge(
'flex w-20 shrink-0 flex-col items-center justify-center rounded-lg px-2 py-2 text-neutral-700 hover:bg-neutral-100 dark:text-neutral-300 dark:hover:bg-neutral-900',
isActive
? 'bg-neutral-50 text-blue-500 hover:bg-neutral-100 dark:bg-neutral-950 dark:hover:bg-neutral-900'
: ''
)
}
>
<InfoIcon className="h-6 w-6" />
<p className="text-sm font-medium">About</p>
</NavLink>
</div>
<div />
</div> </div>
<Outlet />
</div> </div>
<Outlet />
</div> </div>
); );
} }

View File

@ -1,12 +1,16 @@
import { Link, NavLink } from 'react-router-dom'; import { Link, NavLink } from 'react-router-dom';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
import { ActiveAccount } from '@shared/accounts/active'; import { ActiveAccount } from '@shared/accounts/active';
import { ChatsIcon, ComposeIcon, HomeIcon, NwcIcon, RelayIcon } from '@shared/icons'; import {
import { compactNumber } from '@utils/formater'; DepotIcon,
HomeIcon,
NwcIcon,
PlusIcon,
RelayIcon,
SearchIcon,
} from '@shared/icons';
export function Navigation() { export function Navigation() {
const newMessages = 0;
return ( return (
<div className="flex h-full w-full flex-col justify-between p-3"> <div className="flex h-full w-full flex-col justify-between p-3">
<div className="flex flex-1 flex-col gap-5"> <div className="flex flex-1 flex-col gap-5">
@ -19,7 +23,7 @@ export function Navigation() {
<> <>
<div <div
className={twMerge( className={twMerge(
'inline-flex aspect-square h-auto w-full items-center justify-center rounded-lg', 'inline-flex aspect-square h-auto w-full items-center justify-center rounded-xl',
isActive isActive
? 'bg-black/10 text-black dark:bg-white/10 dark:text-white' ? 'bg-black/10 text-black dark:bg-white/10 dark:text-white'
: 'text-black/50 dark:text-neutral-400' : 'text-black/50 dark:text-neutral-400'
@ -27,33 +31,14 @@ export function Navigation() {
> >
<HomeIcon className="h-6 w-6" /> <HomeIcon className="h-6 w-6" />
</div> </div>
<div className="text-sm font-medium text-black dark:text-white">Home</div>
</>
)}
</NavLink>
<NavLink
to="/chats"
preventScrollReset={true}
className="inline-flex flex-col items-center justify-center"
>
{({ isActive }) => (
<>
<div <div
className={twMerge( className={twMerge(
'relative inline-flex aspect-square h-auto w-full items-center justify-center rounded-lg', 'text-sm text-black dark:text-white',
isActive isActive ? 'font-semibold' : 'font-medium'
? 'bg-black/10 text-black dark:bg-white/10 dark:text-white'
: 'text-black/50 dark:text-neutral-400'
)} )}
> >
<ChatsIcon className="h-6 w-6" /> Home
{newMessages > 0 ? (
<div className="absolute right-0 top-0 inline-flex h-5 w-5 items-center justify-center rounded-full bg-blue-500 text-[9px] font-medium text-white">
{compactNumber.format(newMessages)}
</div>
) : null}
</div> </div>
<div className="text-sm font-medium text-black dark:text-white">Chats</div>
</> </>
)} )}
</NavLink> </NavLink>
@ -66,7 +51,7 @@ export function Navigation() {
<> <>
<div <div
className={twMerge( className={twMerge(
'inline-flex aspect-square h-auto w-full items-center justify-center rounded-lg', 'inline-flex aspect-square h-auto w-full items-center justify-center rounded-xl',
isActive isActive
? 'bg-black/10 text-black dark:bg-white/10 dark:text-white' ? 'bg-black/10 text-black dark:bg-white/10 dark:text-white'
: 'text-black/50 dark:text-neutral-400' : 'text-black/50 dark:text-neutral-400'
@ -74,7 +59,14 @@ export function Navigation() {
> >
<RelayIcon className="h-6 w-6" /> <RelayIcon className="h-6 w-6" />
</div> </div>
<div className="text-sm font-medium text-black dark:text-white">Relays</div> <div
className={twMerge(
'text-sm text-black dark:text-white',
isActive ? 'font-semibold' : 'font-medium'
)}
>
Relays
</div>
</> </>
)} )}
</NavLink> </NavLink>
@ -87,15 +79,50 @@ export function Navigation() {
<> <>
<div <div
className={twMerge( className={twMerge(
'inline-flex aspect-square h-auto w-full items-center justify-center rounded-lg', 'inline-flex aspect-square h-auto w-full items-center justify-center rounded-xl',
isActive isActive
? 'bg-black/10 text-black dark:bg-white/10 dark:text-white' ? 'bg-black/10 text-black dark:bg-white/10 dark:text-white'
: 'text-black/50 dark:text-neutral-400' : 'text-black/50 dark:text-neutral-400'
)} )}
> >
<RelayIcon className="h-6 w-6" /> <DepotIcon className="h-6 w-6" />
</div>
<div
className={twMerge(
'text-sm text-black dark:text-white',
isActive ? 'font-semibold' : 'font-medium'
)}
>
Depot
</div>
</>
)}
</NavLink>
<NavLink
to="/nwc"
preventScrollReset={true}
className="inline-flex flex-col items-center justify-center"
>
{({ isActive }) => (
<>
<div
className={twMerge(
'inline-flex aspect-square h-auto w-full items-center justify-center rounded-xl',
isActive
? 'bg-black/10 text-black dark:bg-white/10 dark:text-white'
: 'text-black/50 dark:text-neutral-400'
)}
>
<NwcIcon className="h-6 w-6" />
</div>
<div
className={twMerge(
'text-sm text-black dark:text-white',
isActive ? 'font-semibold' : 'font-medium'
)}
>
Wallet
</div> </div>
<div className="text-sm font-medium text-black dark:text-white">Depot</div>
</> </>
)} )}
</NavLink> </NavLink>
@ -103,15 +130,15 @@ export function Navigation() {
<div className="flex shrink-0 flex-col gap-3 p-1"> <div className="flex shrink-0 flex-col gap-3 p-1">
<Link <Link
to="/new/" to="/new/"
className="flex aspect-square h-auto w-full items-center justify-center rounded-lg bg-neutral-100 text-black hover:bg-blue-500 hover:text-white dark:bg-neutral-900 dark:text-white dark:hover:bg-blue-500" className="flex aspect-square h-auto w-full items-center justify-center rounded-xl bg-black/10 text-black hover:bg-blue-500 hover:text-white dark:bg-white/10 dark:text-white dark:hover:bg-blue-500"
> >
<ComposeIcon className="h-5 w-5" /> <PlusIcon className="h-5 w-5" />
</Link> </Link>
<Link <Link
to="/nwc" to="/nwc"
className="flex aspect-square h-auto w-full items-center justify-center rounded-lg bg-neutral-100 hover:bg-blue-500 hover:text-white dark:bg-neutral-900 dark:hover:bg-blue-500" className="flex aspect-square h-auto w-full items-center justify-center rounded-xl bg-black/10 hover:bg-blue-500 hover:text-white dark:bg-white/10 dark:hover:bg-blue-500"
> >
<NwcIcon className="h-5 w-5" /> <SearchIcon className="h-5 w-5" />
</Link> </Link>
<ActiveAccount /> <ActiveAccount />
</div> </div>

View File

@ -69,6 +69,7 @@ export function NewsfeedWidget() {
<Widget.Root> <Widget.Root>
<Widget.Header <Widget.Header
id="9999" id="9999"
queryKey={['newsfeed']}
title="Timeline" title="Timeline"
icon={<TimelineIcon className="h-5 w-5" />} icon={<TimelineIcon className="h-5 w-5" />}
/> />

View File

@ -126,6 +126,7 @@ export function NotificationWidget() {
<Widget.Root> <Widget.Root>
<Widget.Header <Widget.Header
id="9998" id="9998"
queryKey={['notification']}
title="Notification" title="Notification"
icon={<AnnouncementIcon className="h-5 w-5" />} icon={<AnnouncementIcon className="h-5 w-5" />}
/> />
@ -138,8 +139,8 @@ export function NotificationWidget() {
</div> </div>
</div> </div>
) : allEvents.length < 1 ? ( ) : allEvents.length < 1 ? (
<div className="flex h-[400px] w-full flex-col items-center justify-center"> <div className="my-3 flex w-full items-center justify-center gap-2">
<p className="mb-2 text-4xl">🎉</p> <div>🎉</div>
<p className="text-center font-medium text-neutral-900 dark:text-neutral-100"> <p className="text-center font-medium text-neutral-900 dark:text-neutral-100">
Hmm! Nothing new yet. Hmm! Nothing new yet.
</p> </p>