mirror of
https://github.com/lumehq/lume.git
synced 2025-09-27 00:26:19 +02:00
continue polish, prepare launch v1.0.0
This commit is contained in:
@@ -10,8 +10,8 @@ export function User({ pubkey }: { pubkey: string }) {
|
||||
return (
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="relative h-11 w-11 shrink-0 rounded-md bg-zinc-800 animate-pulse" />
|
||||
<div className="flex w-full flex-1 flex-col items-start text-start">
|
||||
<span className="w-full h-3 rounded bg-zinc-800 animate-pulse" />
|
||||
<div className="flex w-full flex-1 flex-col items-start gap-1 text-start">
|
||||
<span className="w-full h-4 rounded bg-zinc-800 animate-pulse" />
|
||||
<span className="w-1/2 h-3 rounded bg-zinc-800 animate-pulse" />
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -1,4 +1,5 @@
|
||||
import { User } from "@app/auth/components/user";
|
||||
import { Button } from "@shared/button";
|
||||
import { LoaderIcon } from "@shared/icons";
|
||||
import { RelayContext } from "@shared/relayProvider";
|
||||
import { useActiveAccount } from "@stores/accounts";
|
||||
@@ -47,7 +48,7 @@ export function Page() {
|
||||
{loading ? "Creating..." : "Continue with"}
|
||||
</h1>
|
||||
</div>
|
||||
<div className="w-full rounded-lg border border-zinc-800 bg-zinc-900 p-4">
|
||||
<div className="w-full rounded-xl border-t border-zinc-800/50 bg-zinc-900 p-4">
|
||||
{!account ? (
|
||||
<div className="w-full">
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -61,17 +62,13 @@ export function Page() {
|
||||
) : (
|
||||
<div className="flex flex-col gap-3">
|
||||
<User pubkey={account.pubkey} />
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => submit()}
|
||||
className="inline-flex items-center justify-center h-11 w-full bg-fuchsia-500 rounded-md font-medium text-zinc-100 hover:bg-fuchsia-600"
|
||||
>
|
||||
<Button preset="large" onClick={() => submit()}>
|
||||
{loading ? (
|
||||
<LoaderIcon className="h-4 w-4 animate-spin text-black dark:text-zinc-100" />
|
||||
) : (
|
||||
"Continue →"
|
||||
)}
|
||||
</button>
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import { NDKEvent, NDKPrivateKeySigner } from "@nostr-dev-kit/ndk";
|
||||
import { ArrowRightCircleIcon } from "@shared/icons/arrowRightCircle";
|
||||
import { Link } from "@shared/link";
|
||||
import { RelayContext } from "@shared/relayProvider";
|
||||
import { User } from "@shared/user";
|
||||
import { useActiveAccount } from "@stores/accounts";
|
||||
@@ -95,12 +96,12 @@ export function Page() {
|
||||
<span>Publish</span>
|
||||
<ArrowRightCircleIcon className="w-5 h-5" />
|
||||
</button>
|
||||
<a
|
||||
<Link
|
||||
href="/"
|
||||
className="inline-flex h-10 w-full items-center justify-center gap-2 rounded-lg px-6 text-sm font-medium text-zinc-200"
|
||||
>
|
||||
Skip for now
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -1,4 +1,5 @@
|
||||
import { Image } from "@shared/image";
|
||||
import { NetworkStatusIndicator } from "@shared/networkStatusIndicator";
|
||||
import { RelayContext } from "@shared/relayProvider";
|
||||
import { useActiveAccount } from "@stores/accounts";
|
||||
import { useChannels } from "@stores/channels";
|
||||
@@ -64,12 +65,13 @@ export function ActiveAccount({ data }: { data: any }) {
|
||||
});
|
||||
|
||||
return (
|
||||
<button type="button" className="relative h-11 w-11 overflow-hidden">
|
||||
<button type="button" className="relative inline-block h-9 w-9">
|
||||
<Image
|
||||
src={user?.image || DEFAULT_AVATAR}
|
||||
alt={data.npub}
|
||||
className="h-11 w-11 rounded-md object-cover"
|
||||
className="h-9 w-9 rounded object-cover"
|
||||
/>
|
||||
<NetworkStatusIndicator />
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
@@ -1,5 +1,4 @@
|
||||
import { Image } from "@shared/image";
|
||||
|
||||
import { DEFAULT_AVATAR } from "@stores/constants";
|
||||
import { useProfile } from "@utils/hooks/useProfile";
|
||||
|
||||
@@ -7,11 +6,11 @@ export function InactiveAccount({ data }: { data: any }) {
|
||||
const { user } = useProfile(data.npub);
|
||||
|
||||
return (
|
||||
<div className="relative h-11 w-11 shrink rounded-md">
|
||||
<div className="relative h-9 w-9 shrink-0">
|
||||
<Image
|
||||
src={user?.image || DEFAULT_AVATAR}
|
||||
alt={data.npub}
|
||||
className="h-11 w-11 rounded-lg object-cover"
|
||||
className="h-9 w-9 rounded object-cover"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
@@ -1,17 +1,6 @@
|
||||
import { ArrowLeftIcon, ArrowRightIcon } from "@shared/icons";
|
||||
import useSWR from "swr";
|
||||
|
||||
const fetcher = async () => {
|
||||
const { platform } = await import("@tauri-apps/api/os");
|
||||
return platform();
|
||||
};
|
||||
|
||||
export function AppHeader() {
|
||||
const { data: platform } = useSWR(
|
||||
typeof window !== "undefined" ? "platform" : null,
|
||||
fetcher,
|
||||
);
|
||||
|
||||
export function AppHeader({ reverse }: { reverse?: boolean }) {
|
||||
const goBack = () => {
|
||||
window.history.back();
|
||||
};
|
||||
@@ -23,8 +12,8 @@ export function AppHeader() {
|
||||
return (
|
||||
<div
|
||||
data-tauri-drag-region
|
||||
className={`flex h-11 w-full px-3 border-b border-zinc-900 items-center ${
|
||||
platform === "darwin" ? "justify-end" : "justify-start"
|
||||
className={`shrink-0 flex h-11 w-full px-3 border-b border-zinc-900 items-center ${
|
||||
reverse ? "justify-start" : "justify-end"
|
||||
}`}
|
||||
>
|
||||
<div className="flex gap-2.5">
|
||||
|
@@ -1,14 +1,8 @@
|
||||
import { DEFAULT_AVATAR } from "@stores/constants";
|
||||
import { ClassAttributes, ImgHTMLAttributes, JSX } from "react";
|
||||
|
||||
export function Image(
|
||||
props: JSX.IntrinsicAttributes &
|
||||
ClassAttributes<HTMLImageElement> &
|
||||
ImgHTMLAttributes<HTMLImageElement>,
|
||||
fallback = undefined,
|
||||
) {
|
||||
export function Image(props, fallback?) {
|
||||
const addImageFallback = (event: { currentTarget: { src: string } }) => {
|
||||
event.currentTarget.src = fallback ? fallback : DEFAULT_AVATAR;
|
||||
event.currentTarget.src = fallback || DEFAULT_AVATAR;
|
||||
};
|
||||
|
||||
return (
|
||||
|
@@ -19,7 +19,7 @@ export function DefaultLayout({ children }: { children: React.ReactNode }) {
|
||||
}`}
|
||||
>
|
||||
<div className="relative flex flex-row shrink-0">
|
||||
<Navigation />
|
||||
<Navigation reverse={platform !== "darwin"} />
|
||||
</div>
|
||||
<div className="w-full h-full">{children}</div>
|
||||
</div>
|
||||
|
@@ -2,7 +2,6 @@ import { getAccounts, getActiveAccount } from "@libs/storage";
|
||||
import { ActiveAccount } from "@shared/accounts/active";
|
||||
import { InactiveAccount } from "@shared/accounts/inactive";
|
||||
import { BellIcon, PlusIcon } from "@shared/icons";
|
||||
import { APP_VERSION } from "@stores/constants";
|
||||
import useSWR from "swr";
|
||||
|
||||
const allFetcher = () => getAccounts();
|
||||
@@ -13,62 +12,29 @@ export function MultiAccounts() {
|
||||
const { data: activeAccount }: any = useSWR("activeAccount", fetcher);
|
||||
|
||||
return (
|
||||
<div className="flex shrink-0 w-[68px] h-full flex-col items-center justify-between border-r border-zinc-900 pb-4 pt-11">
|
||||
<div className="flex flex-col items-center">
|
||||
<div className="flex flex-col gap-2">
|
||||
<>
|
||||
{!activeAccount ? (
|
||||
<div className="group relative flex h-10 w-10 shrink animate-pulse items-center justify-center rounded-lg bg-zinc-900" />
|
||||
) : (
|
||||
<ActiveAccount data={activeAccount} />
|
||||
)}
|
||||
</>
|
||||
<div>
|
||||
<button
|
||||
type="button"
|
||||
className="group relative flex h-11 w-11 shrink items-center justify-center rounded-md bg-zinc-900 hover:bg-zinc-800"
|
||||
>
|
||||
<BellIcon
|
||||
width={16}
|
||||
height={16}
|
||||
className="text-zinc-400 group-hover:text-zinc-100"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="my-2 h-px w-2/3 bg-zinc-800" />
|
||||
<div className="flex flex-col gap-3">
|
||||
<>
|
||||
{!accounts ? (
|
||||
<div className="group relative flex h-10 w-10 shrink animate-pulse items-center justify-center rounded-lg bg-zinc-900" />
|
||||
) : (
|
||||
accounts.map(
|
||||
(account: { is_active: number; pubkey: string }) => (
|
||||
<InactiveAccount key={account.pubkey} data={account} />
|
||||
),
|
||||
)
|
||||
)}
|
||||
</>
|
||||
<button
|
||||
type="button"
|
||||
className="group relative flex h-10 w-10 shrink items-center justify-center rounded-md border border-dashed border-transparent hover:border-zinc-600"
|
||||
>
|
||||
<PlusIcon
|
||||
width={16}
|
||||
height={16}
|
||||
className="text-zinc-400 group-hover:text-zinc-100"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-0.5 text-center">
|
||||
<span className="text-base font-black uppercase leading-tight text-zinc-600">
|
||||
Lume
|
||||
</span>
|
||||
<span className="text-base font-medium text-zinc-700">
|
||||
v{APP_VERSION}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 rounded-xl p-2 border-t border-zinc-800/50 bg-zinc-900/80 backdrop-blur-md">
|
||||
{!activeAccount ? (
|
||||
<div className="group relative flex h-9 w-9 shrink animate-pulse items-center justify-center rounded-lg bg-zinc-900" />
|
||||
) : (
|
||||
<ActiveAccount data={activeAccount} />
|
||||
)}
|
||||
{!accounts ? (
|
||||
<div className="group relative flex h-9 w-9 shrink animate-pulse items-center justify-center rounded-lg bg-zinc-900" />
|
||||
) : (
|
||||
accounts.map((account: { is_active: number; pubkey: string }) => (
|
||||
<InactiveAccount key={account.pubkey} data={account} />
|
||||
))
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
className="group relative flex h-9 w-9 shrink items-center justify-center rounded border border-dashed border-zinc-600 hover:border-zinc-400"
|
||||
>
|
||||
<PlusIcon
|
||||
width={16}
|
||||
height={16}
|
||||
className="text-zinc-400 group-hover:text-zinc-100"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@@ -5,15 +5,17 @@ import { ActiveLink } from "@shared/activeLink";
|
||||
import { AppHeader } from "@shared/appHeader";
|
||||
import { Composer } from "@shared/composer/modal";
|
||||
import { NavArrowDownIcon, SpaceIcon, TrendingIcon } from "@shared/icons";
|
||||
import { useComposer } from "@stores/composer";
|
||||
|
||||
export function Navigation() {
|
||||
const toggle = useComposer((state: any) => state.toggleModal);
|
||||
import { MultiAccounts } from "@shared/multiAccounts";
|
||||
|
||||
export function Navigation({ reverse }: { reverse?: boolean }) {
|
||||
return (
|
||||
<div className="flex w-[232px] flex-col gap-3 border-r border-zinc-900">
|
||||
<AppHeader />
|
||||
<div className="flex flex-col gap-5 overflow-y-auto scrollbar-hide">
|
||||
<div
|
||||
className={`relative flex w-[232px] flex-col gap-3 ${
|
||||
reverse ? "border-l" : "border-r"
|
||||
} border-zinc-900`}
|
||||
>
|
||||
<AppHeader reverse={reverse} />
|
||||
<div className="pb-20 flex flex-col gap-5 overflow-y-auto scrollbar-hide">
|
||||
<div className="inlin-lflex h-8 px-3.5">
|
||||
<Composer />
|
||||
</div>
|
||||
@@ -104,6 +106,9 @@ export function Navigation() {
|
||||
)}
|
||||
</Disclosure>
|
||||
</div>
|
||||
<div className="absolute bottom-2 left-0 px-8 w-full">
|
||||
<MultiAccounts />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@@ -4,22 +4,10 @@ export function NetworkStatusIndicator() {
|
||||
const isOnline = useNetworkStatus();
|
||||
|
||||
return (
|
||||
<div className="inline-flex items-center gap-1 rounded-md px-1.5 py-1 hover:bg-zinc-900">
|
||||
<div className="relative flex h-1.5 w-1.5">
|
||||
<span
|
||||
className={`absolute inline-flex h-full w-full animate-ping rounded-full opacity-75 ${
|
||||
isOnline ? "bg-green-400" : "bg-red-400"
|
||||
}`}
|
||||
/>
|
||||
<span
|
||||
className={`relative inline-flex h-1.5 w-1.5 rounded-full ${
|
||||
isOnline ? "bg-green-400" : "bg-amber-400"
|
||||
}`}
|
||||
/>
|
||||
</div>
|
||||
<p className="text-base font-medium text-zinc-500">
|
||||
{isOnline ? "Online" : "Offline"}
|
||||
</p>
|
||||
</div>
|
||||
<span
|
||||
className={`absolute right-0 top-0 block h-2 w-2 -translate-y-1/2 translate-x-1/2 transform rounded-full ${
|
||||
isOnline ? "bg-green-400" : "bg-red-400"
|
||||
} ring-2 ring-zinc-900`}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@@ -7,7 +7,7 @@ export function MentionUser({ pubkey }: { pubkey: string }) {
|
||||
|
||||
return (
|
||||
<Link
|
||||
href={`/user?pubkey=${pubkey}`}
|
||||
href={`/app/user?pubkey=${pubkey}`}
|
||||
className="text-fuchsia-500 hover:text-fuchsia-600 no-underline font-normal"
|
||||
>
|
||||
@{user?.name || user?.displayName || shortenKey(pubkey)}
|
||||
|
@@ -29,6 +29,7 @@ export function LinkPreview({ urls }: { urls: string[] }) {
|
||||
src={data["og:image"]}
|
||||
alt={urls[0]}
|
||||
className="w-full h-44 object-cover rounded-t-lg bg-white"
|
||||
fallback="https://void.cat/d/XTmrMkpid8DGLjv1AzdvcW"
|
||||
/>
|
||||
)}
|
||||
<div className="flex flex-col gap-2 px-3 py-3">
|
||||
|
@@ -73,6 +73,7 @@ export function User({
|
||||
src={user?.image || DEFAULT_AVATAR}
|
||||
alt={pubkey}
|
||||
className="h-11 w-11 shrink-0 rounded-lg object-cover"
|
||||
fallback={DEFAULT_AVATAR}
|
||||
/>
|
||||
<div className="flex-1 flex flex-col gap-2">
|
||||
<div className="inline-flex flex-col gap-1">
|
||||
|
Reference in New Issue
Block a user