mirror of
https://github.com/lumehq/lume.git
synced 2025-04-01 16:38:14 +02:00
wip: integrate alby
This commit is contained in:
parent
1553f5ced2
commit
a33c9d3517
src-tauri
src
@ -16,7 +16,8 @@ tauri-build = { version = "1.4", features = [] }
|
||||
[dependencies]
|
||||
serde_json = "1.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
tauri = { version = "1.4", features = [
|
||||
tauri = { version = "1.4", features = [ "window-create",
|
||||
"macos-private-api",
|
||||
"fs-read-dir",
|
||||
"fs-read-file",
|
||||
"window-start-dragging",
|
||||
|
@ -67,7 +67,10 @@
|
||||
"center": true,
|
||||
"setResizable": true,
|
||||
"setSize": true,
|
||||
"startDragging": true
|
||||
"startDragging": true,
|
||||
"create": true,
|
||||
"close": true,
|
||||
"print": true
|
||||
},
|
||||
"clipboard": {
|
||||
"all": false,
|
||||
@ -124,7 +127,15 @@
|
||||
"security": {
|
||||
"csp": {
|
||||
"content-security-policy": "upgrade-insecure-requests"
|
||||
}
|
||||
},
|
||||
"dangerousRemoteDomainIpcAccess": [
|
||||
{
|
||||
"scheme": "https",
|
||||
"domain": "nwc.getalby.com",
|
||||
"windows": ["alby"],
|
||||
"enableTauriAPI": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"macOSPrivateApi": true
|
||||
}
|
||||
|
135
src/shared/alby.tsx
Normal file
135
src/shared/alby.tsx
Normal file
@ -0,0 +1,135 @@
|
||||
import { webln } from '@getalby/sdk';
|
||||
import * as Dialog from '@radix-ui/react-dialog';
|
||||
import { message } from '@tauri-apps/api/dialog';
|
||||
import { WebviewWindow } from '@tauri-apps/api/window';
|
||||
import { useState } from 'react';
|
||||
|
||||
import { useStorage } from '@libs/storage/provider';
|
||||
|
||||
import {
|
||||
AlbyIcon,
|
||||
ArrowRightCircleIcon,
|
||||
CancelIcon,
|
||||
LoaderIcon,
|
||||
StarsIcon,
|
||||
} from '@shared/icons';
|
||||
|
||||
export function AlbyConnectButton() {
|
||||
const { db } = useStorage();
|
||||
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [isLoading, setIsloading] = useState(false);
|
||||
|
||||
const initAlby = async () => {
|
||||
try {
|
||||
setIsloading(true);
|
||||
|
||||
const provider = webln.NostrWebLNProvider.withNewSecret();
|
||||
const walletConnectURL = provider.getNostrWalletConnectUrl(true);
|
||||
|
||||
// get auth url
|
||||
const authURL = provider.getAuthorizationUrl({ name: 'Lume' });
|
||||
|
||||
// open auth window
|
||||
const webview = new WebviewWindow('alby', {
|
||||
title: 'Connect Alby',
|
||||
url: authURL.href,
|
||||
center: true,
|
||||
theme: 'light',
|
||||
width: 400,
|
||||
height: 650,
|
||||
});
|
||||
|
||||
webview.listen('tauri://close-requested', async (e) => {
|
||||
console.log(e);
|
||||
await db.secureSave('wallet-connect-url', walletConnectURL);
|
||||
setIsloading(false);
|
||||
webview.close();
|
||||
});
|
||||
} catch (e) {
|
||||
setIsloading(false);
|
||||
await message(e.toString(), { title: 'Connect Alby', type: 'error' });
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog.Root open={isOpen} onOpenChange={setIsOpen}>
|
||||
<div className="relative w-full rounded-xl bg-gradient-to-r from-orange-400 via-red-200 to-yellow-200 p-px">
|
||||
<StarsIcon className="absolute -left-4 -top-3 z-50 h-10 w-10 text-white" />
|
||||
<div className="flex w-full flex-col rounded-xl bg-white/10 backdrop-blur-xl">
|
||||
<div className="absolute right-2 top-2">
|
||||
<button type="button">
|
||||
<CancelIcon className="h-4 w-4 text-black/50" />
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex h-14 w-full flex-col items-center justify-center">
|
||||
<h5 className="text-center text-sm font-semibold leading-tight text-black/50">
|
||||
New feature
|
||||
</h5>
|
||||
<h3 className="transform font-medium leading-tight text-black">
|
||||
Send bitcoin tip with Alby
|
||||
</h3>
|
||||
</div>
|
||||
<Dialog.Trigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
className="inline-flex h-10 w-full shrink-0 items-center justify-center gap-1 rounded-b-xl border-t border-orange-200 bg-white text-sm font-semibold text-orange-400 hover:bg-orange-50"
|
||||
>
|
||||
Connect your Alby account <AlbyIcon className="h-7 w-7" />
|
||||
</button>
|
||||
</Dialog.Trigger>
|
||||
</div>
|
||||
</div>
|
||||
<Dialog.Portal className="relative z-10">
|
||||
<Dialog.Overlay className="fixed inset-0 z-50 bg-black/80 backdrop-blur-2xl" />
|
||||
<Dialog.Content className="fixed inset-0 z-50 flex min-h-full items-center justify-center">
|
||||
<div className="relative h-min w-full max-w-xl rounded-xl bg-white/10 backdrop-blur-xl">
|
||||
<div className="h-min w-full shrink-0 border-b border-white/10 bg-white/5 px-5 py-5">
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="flex items-center justify-between">
|
||||
<Dialog.Title className="text-lg font-semibold leading-none text-white">
|
||||
Alby integration (Beta)
|
||||
</Dialog.Title>
|
||||
<Dialog.Close className="inline-flex h-6 w-6 items-center justify-center rounded-md backdrop-blur-xl hover:bg-white/10">
|
||||
<CancelIcon className="h-4 w-4 text-white/50" />
|
||||
</Dialog.Close>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-3 px-5 py-5">
|
||||
<div className="flex flex-col gap-2">
|
||||
<p className="text-sm text-white/50">
|
||||
When you click "Connect", a new window will open in your
|
||||
default browser. You will need to click the "Connect Wallet"
|
||||
button to grant Lume permission to integrate with your Alby account.
|
||||
</p>
|
||||
<p className="text-sm text-white/50">
|
||||
All information will be encrypted and stored on the local machine.
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => initAlby()}
|
||||
className="inline-flex h-11 w-full items-center justify-between gap-2 rounded-lg bg-fuchsia-500 px-6 font-medium leading-none text-white hover:bg-fuchsia-600 focus:outline-none disabled:opacity-50"
|
||||
>
|
||||
{isLoading ? (
|
||||
<>
|
||||
<span className="w-5" />
|
||||
<span>Connecting...</span>
|
||||
<LoaderIcon className="h-5 w-5 animate-spin text-white" />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<span className="w-5" />
|
||||
<span>Connect</span>
|
||||
<ArrowRightCircleIcon className="h-5 w-5" />
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog.Content>
|
||||
</Dialog.Portal>
|
||||
</Dialog.Root>
|
||||
);
|
||||
}
|
74
src/shared/icons/alby.tsx
Normal file
74
src/shared/icons/alby.tsx
Normal file
@ -0,0 +1,74 @@
|
||||
import { SVGProps } from 'react';
|
||||
|
||||
export function AlbyIcon(props: JSX.IntrinsicAttributes & SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="400"
|
||||
height="578"
|
||||
fill="none"
|
||||
viewBox="0 0 400 578"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="#000"
|
||||
d="M201.283 577.511c54.122 0 97.998-8.1 97.998-18.092 0-9.992-43.876-18.092-97.998-18.092-54.123 0-97.998 8.1-97.998 18.092 0 9.992 43.875 18.092 97.998 18.092z"
|
||||
opacity="0.1"
|
||||
></path>
|
||||
<path
|
||||
fill="#fff"
|
||||
stroke="#000"
|
||||
strokeWidth="15.077"
|
||||
d="M295.75 471.344c50.627 0 73.67-112.102 73.67-154.608 0-33.13-22.86-53.208-52.913-53.208-29.866 0-54.113 12.843-54.414 28.747-.001 41.971-7.388 179.069 33.657 179.069zM110.837 471.344c-50.627 0-73.67-112.102-73.67-154.608 0-33.13 22.86-53.208 52.913-53.208 29.866 0 54.113 12.843 54.414 28.747.001 41.971 7.388 179.069-33.657 179.069z"
|
||||
></path>
|
||||
<path
|
||||
fill="#FFDF6F"
|
||||
stroke="#000"
|
||||
strokeWidth="15"
|
||||
d="M68.83 303.262v-.002c-.054-.519.052-.82.16-1.016.127-.232.368-.508.773-.738.84-.477 2.014-.563 3.108.076 37.603 22.042 80.976 34.678 128.13 34.678 47.163 0 91.339-12.881 129.184-35.307 1.087-.645 2.26-.565 3.102-.091.407.229.65.504.779.737.109.197.216.499.163 1.019-5.854 58.014-37.322 105.977-79.618 128.054-13.969 7.293-23.576 19.962-32.013 31.089l-.452.597-.002.002c-6.857 9.046-13.063 17.147-20.648 23.116-7.584-5.969-13.791-14.07-20.648-23.116l-.001-.002-.452-.597c-8.437-11.127-18.043-23.796-32.013-31.089-42.135-21.992-73.523-69.677-79.551-127.41z"
|
||||
></path>
|
||||
<path
|
||||
fill="#000"
|
||||
stroke="#000"
|
||||
strokeWidth="15.077"
|
||||
d="M201.786 346.338c73.274 0 132.674-19.8 132.674-44.225s-59.4-44.225-132.674-44.225-132.674 19.8-132.674 44.225 59.4 44.225 132.674 44.225z"
|
||||
></path>
|
||||
<path
|
||||
stroke="#000"
|
||||
strokeLinecap="round"
|
||||
strokeWidth="15.077"
|
||||
d="M95.245 376.491s65.44 22.112 107.546 22.112c42.105 0 107.546-22.112 107.546-22.112"
|
||||
></path>
|
||||
<path
|
||||
fill="#000"
|
||||
d="M77 143c-16.569 0-30-13.431-30-30 0-16.569 13.431-30 30-30 16.569 0 30 13.431 30 30 0 16.569-13.431 30-30 30z"
|
||||
></path>
|
||||
<path stroke="#000" strokeWidth="15" d="M72 108.5l56 56"></path>
|
||||
<path
|
||||
fill="#000"
|
||||
d="M322 143c16.569 0 30-13.431 30-30 0-16.569-13.431-30-30-30-16.569 0-30 13.431-30 30 0 16.569 13.431 30 30 30z"
|
||||
></path>
|
||||
<path stroke="#000" strokeWidth="15" d="M327.5 108.5l-56 56"></path>
|
||||
<path
|
||||
fill="#FFDF6F"
|
||||
fillRule="evenodd"
|
||||
d="M85.516 292.019c-16.17-7.698-25.58-24.983-22.427-42.612C76.618 173.747 133 117 200.5 117c67.663 0 124.155 57.023 137.509 132.958 3.106 17.66-6.381 34.937-22.605 42.572C280.687 308.868 241.91 318 201 318c-41.335 0-80.493-9.323-115.484-25.981z"
|
||||
clipRule="evenodd"
|
||||
></path>
|
||||
<path
|
||||
fill="#000"
|
||||
d="M70.472 250.728C83.544 177.62 137.582 124.5 200.5 124.5v-15c-72.082 0-130.809 60.375-144.794 138.587l14.766 2.641zM200.5 124.5c63.069 0 117.218 53.379 130.122 126.757l14.774-2.598C331.592 170.166 272.758 109.5 200.5 109.5v15zm111.71 161.244C278.472 301.621 240.783 310.5 201 310.5v15c42.037 0 81.902-9.386 117.597-26.183l-6.387-13.573zM201 310.5c-40.196 0-78.255-9.064-112.26-25.253l-6.448 13.544C118.269 315.918 158.526 325.5 201 325.5v-15zm129.622-59.243c2.49 14.159-5.091 28.219-18.412 34.487l6.387 13.573c19.128-9.002 30.52-29.497 26.799-50.658l-14.774 2.598zm-274.916-3.17c-3.778 21.124 7.524 41.629 26.586 50.704l6.447-13.544c-13.276-6.32-20.795-20.387-18.267-34.519l-14.766-2.641z"
|
||||
></path>
|
||||
<path
|
||||
fill="#000"
|
||||
fillRule="evenodd"
|
||||
d="M114.365 273.209c-13.015-5.301-20.736-19.149-16.226-32.459C112.047 199.704 152.618 170 200.5 170c47.882 0 88.453 29.704 102.361 70.75 4.51 13.31-3.211 27.158-16.226 32.459C260.053 284.035 230.973 290 200.5 290c-30.473 0-59.553-5.965-86.135-16.791z"
|
||||
clipRule="evenodd"
|
||||
></path>
|
||||
<path
|
||||
fill="#fff"
|
||||
d="M235 254c13.807 0 25-8.954 25-20s-11.193-20-25-20-25 8.954-25 20 11.193 20 25 20zM163.432 254.012c13.807 0 25-8.954 25-20s-11.193-20-25-20-25 8.954-25 20 11.193 20 25 20z"
|
||||
></path>
|
||||
</svg>
|
||||
);
|
||||
}
|
@ -61,3 +61,5 @@ export * from './mention';
|
||||
export * from './groupFeeds';
|
||||
export * from './article';
|
||||
export * from './follows';
|
||||
export * from './alby';
|
||||
export * from './stars';
|
||||
|
19
src/shared/icons/stars.tsx
Normal file
19
src/shared/icons/stars.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
import { SVGProps } from 'react';
|
||||
|
||||
export function StarsIcon(props: JSX.IntrinsicAttributes & SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="30"
|
||||
height="30"
|
||||
fill="none"
|
||||
viewBox="0 0 30 30"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M13.379 11.638a.999.999 0 00.759-.759l.886-3.986c.232-1.044 1.72-1.044 1.952 0l.886 3.986c.084.38.38.675.759.76l3.986.885c1.044.232 1.044 1.72 0 1.952l-3.986.886a.999.999 0 00-.759.76l-.886 3.985c-.232 1.044-1.72 1.044-1.952 0l-.886-3.986a.999.999 0 00-.759-.759l-3.986-.886c-1.044-.232-1.044-1.72 0-1.952l3.986-.886zM8.06 19.82a.999.999 0 00.76-.759l.27-1.22c.098-.438.722-.438.819 0l.271 1.22c.084.379.38.675.759.759l1.22.271c.438.097.438.721 0 .818l-1.22.271a.999.999 0 00-.759.759l-.271 1.22c-.097.438-.721.438-.818 0l-.271-1.22a.999.999 0 00-.76-.759l-1.22-.271c-.437-.097-.437-.721.001-.818l1.22-.271z"
|
||||
></path>
|
||||
</svg>
|
||||
);
|
||||
}
|
@ -7,6 +7,7 @@ import { ChatsList } from '@app/chats/components/list';
|
||||
import { useStorage } from '@libs/storage/provider';
|
||||
|
||||
import { ActiveAccount } from '@shared/accounts/active';
|
||||
import { AlbyConnectButton } from '@shared/alby';
|
||||
import { ComposerModal } from '@shared/composer';
|
||||
import { Frame } from '@shared/frame';
|
||||
import { BellIcon, NavArrowDownIcon, SpaceIcon } from '@shared/icons';
|
||||
@ -97,7 +98,10 @@ export function Navigation() {
|
||||
</div>
|
||||
</Collapsible.Root>
|
||||
</div>
|
||||
<div className="shrink-0">
|
||||
<div className="relative shrink-0">
|
||||
<div className="border-l-2 border-transparent pb-2 pl-4 pr-2">
|
||||
<AlbyConnectButton />
|
||||
</div>
|
||||
<ActiveAccount />
|
||||
</div>
|
||||
</Frame>
|
||||
|
@ -126,7 +126,7 @@ export function useNostr() {
|
||||
|
||||
let since: number;
|
||||
if (dbEventsEmpty || db.account.last_login_at === 0) {
|
||||
since = nHoursAgo(24);
|
||||
since = db.account.network.length > 400 ? nHoursAgo(12) : nHoursAgo(24);
|
||||
} else {
|
||||
since = db.account.last_login_at;
|
||||
}
|
||||
@ -164,10 +164,10 @@ export function useNostr() {
|
||||
);
|
||||
}
|
||||
|
||||
return { status: 'ok', data: [], message: 'prefetch completed' };
|
||||
return { status: 'ok', message: 'prefetch completed' };
|
||||
} catch (e) {
|
||||
console.error('prefetch events failed, error: ', e);
|
||||
return { status: 'failed', data: [], message: e };
|
||||
return { status: 'failed', message: e };
|
||||
}
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user