mirror of
https://github.com/luminous-devs/lume.git
synced 2024-10-02 18:00:47 +00:00
wip
This commit is contained in:
parent
bc4c3b9803
commit
770a63de63
@ -4,7 +4,7 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Lume</title>
|
<title>Lume</title>
|
||||||
</head>
|
</head>
|
||||||
<body class="relative cursor-default select-none overflow-hidden font-sans antialiased h-screen w-screen text-neutral-950 dark:text-neutral-50">
|
<body class="relative cursor-default select-none overflow-hidden font-sans antialiased h-screen w-screen text-neutral-950 dark:text-neutral-50 selection:bg-blue-50 selection:text-blue-500 dark:selection:bg-blue-950 dark:selection:text-blue-50">
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
<script type="module" src="/src/main.jsx"></script>
|
<script type="module" src="/src/main.jsx"></script>
|
||||||
</body>
|
</body>
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@evilmartians/harmony": "^1.1.0",
|
"@evilmartians/harmony": "^1.1.0",
|
||||||
"@fontsource-variable/inter": "^5.0.13",
|
|
||||||
"@getalby/sdk": "^2.4.0",
|
"@getalby/sdk": "^2.4.0",
|
||||||
"@nostr-dev-kit/ndk": "^1.3.2",
|
"@nostr-dev-kit/ndk": "^1.3.2",
|
||||||
"@nostr-dev-kit/ndk-cache-dexie": "^1.3.2",
|
"@nostr-dev-kit/ndk-cache-dexie": "^1.3.2",
|
||||||
@ -55,12 +54,12 @@
|
|||||||
"@tiptap/react": "^2.1.11",
|
"@tiptap/react": "^2.1.11",
|
||||||
"@tiptap/starter-kit": "^2.1.11",
|
"@tiptap/starter-kit": "^2.1.11",
|
||||||
"@tiptap/suggestion": "^2.1.11",
|
"@tiptap/suggestion": "^2.1.11",
|
||||||
"@vidstack/react": "^1.1.9",
|
|
||||||
"dayjs": "^1.11.10",
|
"dayjs": "^1.11.10",
|
||||||
"destr": "^2.0.1",
|
"destr": "^2.0.1",
|
||||||
"html-to-text": "^9.0.5",
|
"html-to-text": "^9.0.5",
|
||||||
"light-bolt11-decoder": "^3.0.0",
|
"light-bolt11-decoder": "^3.0.0",
|
||||||
"lru-cache": "^10.0.1",
|
"lru-cache": "^10.0.1",
|
||||||
|
"media-chrome": "^1.4.3",
|
||||||
"million": "^2.6.4",
|
"million": "^2.6.4",
|
||||||
"minidenticons": "^4.2.0",
|
"minidenticons": "^4.2.0",
|
||||||
"nostr-fetch": "^0.13.0",
|
"nostr-fetch": "^0.13.0",
|
||||||
|
@ -8,9 +8,6 @@ dependencies:
|
|||||||
'@evilmartians/harmony':
|
'@evilmartians/harmony':
|
||||||
specifier: ^1.1.0
|
specifier: ^1.1.0
|
||||||
version: 1.1.0
|
version: 1.1.0
|
||||||
'@fontsource-variable/inter':
|
|
||||||
specifier: ^5.0.13
|
|
||||||
version: 5.0.13
|
|
||||||
'@getalby/sdk':
|
'@getalby/sdk':
|
||||||
specifier: ^2.4.0
|
specifier: ^2.4.0
|
||||||
version: 2.4.0
|
version: 2.4.0
|
||||||
@ -116,9 +113,6 @@ dependencies:
|
|||||||
'@tiptap/suggestion':
|
'@tiptap/suggestion':
|
||||||
specifier: ^2.1.11
|
specifier: ^2.1.11
|
||||||
version: 2.1.11(@tiptap/core@2.1.11)(@tiptap/pm@2.1.11)
|
version: 2.1.11(@tiptap/core@2.1.11)(@tiptap/pm@2.1.11)
|
||||||
'@vidstack/react':
|
|
||||||
specifier: ^1.1.9
|
|
||||||
version: 1.1.9(@types/react@18.2.27)(react@18.2.0)
|
|
||||||
dayjs:
|
dayjs:
|
||||||
specifier: ^1.11.10
|
specifier: ^1.11.10
|
||||||
version: 1.11.10
|
version: 1.11.10
|
||||||
@ -134,6 +128,9 @@ dependencies:
|
|||||||
lru-cache:
|
lru-cache:
|
||||||
specifier: ^10.0.1
|
specifier: ^10.0.1
|
||||||
version: 10.0.1
|
version: 10.0.1
|
||||||
|
media-chrome:
|
||||||
|
specifier: ^1.4.3
|
||||||
|
version: 1.4.3
|
||||||
million:
|
million:
|
||||||
specifier: ^2.6.4
|
specifier: ^2.6.4
|
||||||
version: 2.6.4
|
version: 2.6.4
|
||||||
@ -824,10 +821,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==}
|
resolution: {integrity: sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@fontsource-variable/inter@5.0.13:
|
|
||||||
resolution: {integrity: sha512-mb2WyZ2rHeqIG8aqGJIvLBOmo4sg2x7SHlsE6PUhwxbOicVzO59EZwSGtzNO3FmchuDPFVAxzcXYcR5B6jE6Qw==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/@getalby/sdk@2.4.0:
|
/@getalby/sdk@2.4.0:
|
||||||
resolution: {integrity: sha512-aIGNwLRF9coj6koxfq7P4GtFZbFjQbnIheix39x9176PwFw4dXOdGXHPXnqioJTmeq80y+vX1yd+u/f03YGoeg==}
|
resolution: {integrity: sha512-aIGNwLRF9coj6koxfq7P4GtFZbFjQbnIheix39x9176PwFw4dXOdGXHPXnqioJTmeq80y+vX1yd+u/f03YGoeg==}
|
||||||
engines: {node: '>=14'}
|
engines: {node: '>=14'}
|
||||||
@ -2917,18 +2910,6 @@ packages:
|
|||||||
eslint-visitor-keys: 3.4.3
|
eslint-visitor-keys: 3.4.3
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@vidstack/react@1.1.9(@types/react@18.2.27)(react@18.2.0):
|
|
||||||
resolution: {integrity: sha512-CYXhr0Hk/xTcYDVKy39J6VUIcJMCLzbfNe9upBQ096lnCpk3yEncsAUl73jTE3GzJ8yOPEQcdloFoJXbA4ekeg==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
peerDependencies:
|
|
||||||
'@types/react': ^18.0.0
|
|
||||||
react: ^18.0.0
|
|
||||||
dependencies:
|
|
||||||
'@types/react': 18.2.27
|
|
||||||
media-captions: 1.0.0
|
|
||||||
react: 18.2.0
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/@vitejs/plugin-react-swc@3.4.0(vite@4.4.11):
|
/@vitejs/plugin-react-swc@3.4.0(vite@4.4.11):
|
||||||
resolution: {integrity: sha512-m7UaA4Uvz82N/0EOVpZL4XsFIakRqrFKeSNxa1FBLSXGvWrWRBwmZb4qxk+ZIVAZcW3c3dn5YosomDgx62XWcQ==}
|
resolution: {integrity: sha512-m7UaA4Uvz82N/0EOVpZL4XsFIakRqrFKeSNxa1FBLSXGvWrWRBwmZb4qxk+ZIVAZcW3c3dn5YosomDgx62XWcQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -3110,7 +3091,7 @@ packages:
|
|||||||
postcss: ^8.1.0
|
postcss: ^8.1.0
|
||||||
dependencies:
|
dependencies:
|
||||||
browserslist: 4.22.1
|
browserslist: 4.22.1
|
||||||
caniuse-lite: 1.0.30001546
|
caniuse-lite: 1.0.30001547
|
||||||
fraction.js: 4.3.6
|
fraction.js: 4.3.6
|
||||||
normalize-range: 0.1.2
|
normalize-range: 0.1.2
|
||||||
picocolors: 1.0.0
|
picocolors: 1.0.0
|
||||||
@ -3162,8 +3143,8 @@ packages:
|
|||||||
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
|
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
dependencies:
|
dependencies:
|
||||||
caniuse-lite: 1.0.30001546
|
caniuse-lite: 1.0.30001547
|
||||||
electron-to-chromium: 1.4.546
|
electron-to-chromium: 1.4.548
|
||||||
node-releases: 2.0.13
|
node-releases: 2.0.13
|
||||||
update-browserslist-db: 1.0.13(browserslist@4.22.1)
|
update-browserslist-db: 1.0.13(browserslist@4.22.1)
|
||||||
|
|
||||||
@ -3191,8 +3172,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==}
|
resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==}
|
||||||
engines: {node: '>= 6'}
|
engines: {node: '>= 6'}
|
||||||
|
|
||||||
/caniuse-lite@1.0.30001546:
|
/caniuse-lite@1.0.30001547:
|
||||||
resolution: {integrity: sha512-zvtSJwuQFpewSyRrI3AsftF6rM0X80mZkChIt1spBGEvRglCrjTniXvinc8JKRoqTwXAgvqTImaN9igfSMtUBw==}
|
resolution: {integrity: sha512-W7CrtIModMAxobGhz8iXmDfuJiiKg1WADMO/9x7/CLNin5cpSbuBjooyoIUVB5eyCc36QuTVlkVa1iB2S5+/eA==}
|
||||||
|
|
||||||
/case-anything@2.1.13:
|
/case-anything@2.1.13:
|
||||||
resolution: {integrity: sha512-zlOQ80VrQ2Ue+ymH5OuM/DlDq64mEm+B9UTdHULv5osUMD6HalNTblf2b1u/m6QecjsnOkBpqVZ+XPwIVsy7Ng==}
|
resolution: {integrity: sha512-zlOQ80VrQ2Ue+ymH5OuM/DlDq64mEm+B9UTdHULv5osUMD6HalNTblf2b1u/m6QecjsnOkBpqVZ+XPwIVsy7Ng==}
|
||||||
@ -3565,8 +3546,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
|
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/electron-to-chromium@1.4.546:
|
/electron-to-chromium@1.4.548:
|
||||||
resolution: {integrity: sha512-cz9bBM26ZqoEmGHkdHXU3LP7OofVyEzRoMqfALQ9Au9WlB4rogAHzqj/NkNvw2JJjy4xuxS1me+pP2lbCD5Mfw==}
|
resolution: {integrity: sha512-R77KD6mXv37DOyKLN/eW1rGS61N6yHOfapNSX9w+y9DdPG83l9Gkuv7qkCFZ4Ta4JPhrjgQfYbv4Y3TnM1Hi2Q==}
|
||||||
|
|
||||||
/emoji-regex@9.2.2:
|
/emoji-regex@9.2.2:
|
||||||
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
|
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
|
||||||
@ -4863,9 +4844,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==}
|
resolution: {integrity: sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/media-captions@1.0.0:
|
/media-chrome@1.4.3:
|
||||||
resolution: {integrity: sha512-605d9sXW+DtJBNzzfL4N6NpOIjigN+kpzS+V1QaCiNNPB7G015/peyw6wfv9iCp8GAP6R5NPyAICZKeuqWPAQQ==}
|
resolution: {integrity: sha512-VpFqCOu2FLULW6TX4sluo44AolJXryHxr85UBdO+IuOltgYPuf7Lgp1F3OqJeRIeO8874d5mri/6xmI22CO9yA==}
|
||||||
engines: {node: '>=16'}
|
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/merge-stream@2.0.0:
|
/merge-stream@2.0.0:
|
||||||
|
@ -1,7 +1,4 @@
|
|||||||
@import 'reactflow/dist/style.css';
|
@import 'reactflow/dist/style.css';
|
||||||
@import '@vidstack/react/player/styles/default/theme.css';
|
|
||||||
@import '@vidstack/react/player/styles/default/layouts/audio.css';
|
|
||||||
@import '@vidstack/react/player/styles/default/layouts/video.css';
|
|
||||||
|
|
||||||
@tailwind base;
|
@tailwind base;
|
||||||
@tailwind components;
|
@tailwind components;
|
||||||
@ -9,12 +6,6 @@
|
|||||||
|
|
||||||
html {
|
html {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
/* Smoothing */
|
|
||||||
text-rendering: optimizeLegibility;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
font-smoothing: antialiased;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
text-shadow: rgba(0, 0, 0, .01) 0 0 1px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import '@fontsource-variable/inter/slnt.css';
|
|
||||||
import { message } from '@tauri-apps/plugin-dialog';
|
import { message } from '@tauri-apps/plugin-dialog';
|
||||||
import { fetch } from '@tauri-apps/plugin-http';
|
import { fetch } from '@tauri-apps/plugin-http';
|
||||||
import { RouterProvider, createBrowserRouter, defer, redirect } from 'react-router-dom';
|
import { RouterProvider, createBrowserRouter, defer, redirect } from 'react-router-dom';
|
||||||
|
@ -50,9 +50,10 @@ export function SplashScreen() {
|
|||||||
}, [ndk, db.account]);
|
}, [ndk, db.account]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative flex h-screen w-screen items-center justify-center bg-neutral-50 dark:bg-neutral-950">
|
<div
|
||||||
<div data-tauri-drag-region className="absolute left-0 top-0 z-10 h-16 w-full" />
|
data-tauri-drag-region
|
||||||
<div className="flex min-h-0 w-full flex-1 items-center justify-center px-8">
|
className="flex h-screen w-screen items-center justify-center bg-neutral-50 dark:bg-neutral-950"
|
||||||
|
>
|
||||||
<div className="flex flex-col items-center justify-center gap-6">
|
<div className="flex flex-col items-center justify-center gap-6">
|
||||||
<LoaderIcon className="h-6 w-6 animate-spin text-neutral-950 dark:text-neutral-50" />
|
<LoaderIcon className="h-6 w-6 animate-spin text-neutral-950 dark:text-neutral-50" />
|
||||||
<h3 className="text-lg font-medium leading-none text-neutral-950 dark:text-neutral-50">
|
<h3 className="text-lg font-medium leading-none text-neutral-950 dark:text-neutral-50">
|
||||||
@ -60,6 +61,5 @@ export function SplashScreen() {
|
|||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -28,16 +28,15 @@ export function NoteActions({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Tooltip.Provider>
|
<Tooltip.Provider>
|
||||||
<div className="-ml-1 mt-4 inline-flex w-full items-center">
|
<div className="-ml-1 mt-2 inline-flex w-full items-center">
|
||||||
<div className="inline-flex items-center gap-8">
|
<div className="inline-flex items-center gap-10">
|
||||||
<NoteReply id={id} pubkey={pubkey} root={root} />
|
<NoteReply id={id} pubkey={pubkey} root={root} />
|
||||||
<NoteReaction id={id} pubkey={pubkey} />
|
<NoteReaction id={id} pubkey={pubkey} />
|
||||||
<NoteRepost id={id} pubkey={pubkey} />
|
<NoteRepost id={id} pubkey={pubkey} />
|
||||||
<NoteZap id={id} pubkey={pubkey} />
|
<NoteZap id={id} pubkey={pubkey} />
|
||||||
</div>
|
</div>
|
||||||
{extraButtons && (
|
{extraButtons && (
|
||||||
<div className="ml-auto">
|
<div className="ml-auto inline-flex items-center gap-3">
|
||||||
<div className="inline-flex items-center gap-3">
|
|
||||||
<Tooltip.Root delayDuration={150}>
|
<Tooltip.Root delayDuration={150}>
|
||||||
<Tooltip.Trigger asChild>
|
<Tooltip.Trigger asChild>
|
||||||
<button
|
<button
|
||||||
@ -61,8 +60,6 @@ export function NoteActions({
|
|||||||
</Tooltip.Content>
|
</Tooltip.Content>
|
||||||
</Tooltip.Portal>
|
</Tooltip.Portal>
|
||||||
</Tooltip.Root>
|
</Tooltip.Root>
|
||||||
<MoreActions id={id} pubkey={pubkey} />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -25,24 +25,9 @@ export function MoreActions({ id, pubkey }: { id: string; pubkey: string }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownMenu.Root open={open} onOpenChange={setOpen}>
|
<DropdownMenu.Root open={open} onOpenChange={setOpen}>
|
||||||
<Tooltip.Root delayDuration={150}>
|
<DropdownMenu.Trigger>
|
||||||
<Tooltip.Trigger asChild>
|
<HorizontalDotsIcon className="h-5 w-5 text-neutral-800 hover:text-blue-500 dark:text-neutral-200" />
|
||||||
<DropdownMenu.Trigger asChild>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="group inline-flex h-7 w-7 items-center justify-center text-neutral-500 dark:text-neutral-300"
|
|
||||||
>
|
|
||||||
<HorizontalDotsIcon className="h-5 w-5 group-hover:text-blue-500" />
|
|
||||||
</button>
|
|
||||||
</DropdownMenu.Trigger>
|
</DropdownMenu.Trigger>
|
||||||
</Tooltip.Trigger>
|
|
||||||
<Tooltip.Portal>
|
|
||||||
<Tooltip.Content className="-left-10 inline-flex h-7 select-none items-center justify-center rounded-md bg-neutral-200 px-3.5 text-sm text-neutral-900 will-change-[transform,opacity] data-[state=delayed-open]:data-[side=bottom]:animate-slideUpAndFade data-[state=delayed-open]:data-[side=left]:animate-slideRightAndFade data-[state=delayed-open]:data-[side=right]:animate-slideLeftAndFade data-[state=delayed-open]:data-[side=top]:animate-slideDownAndFade dark:bg-neutral-800 dark:text-neutral-100">
|
|
||||||
More
|
|
||||||
<Tooltip.Arrow className="fill-neutral-200 dark:fill-neutral-800" />
|
|
||||||
</Tooltip.Content>
|
|
||||||
</Tooltip.Portal>
|
|
||||||
</Tooltip.Root>
|
|
||||||
<DropdownMenu.Portal>
|
<DropdownMenu.Portal>
|
||||||
<DropdownMenu.Content className="flex w-[200px] flex-col overflow-hidden rounded-xl border border-neutral-300 bg-neutral-200 focus:outline-none dark:border-neutral-700 dark:bg-neutral-800">
|
<DropdownMenu.Content className="flex w-[200px] flex-col overflow-hidden rounded-xl border border-neutral-300 bg-neutral-200 focus:outline-none dark:border-neutral-700 dark:bg-neutral-800">
|
||||||
<DropdownMenu.Item asChild>
|
<DropdownMenu.Item asChild>
|
||||||
|
@ -79,7 +79,7 @@ export function ChildNote({ id, root }: { id: string; root?: string }) {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="absolute bottom-0 left-[18px] h-[calc(100%-3.6rem)] w-0.5 bg-gradient-to-t from-black/20 to-black/10 dark:from-white/20 dark:to-white/10" />
|
<div className="absolute bottom-0 left-[18px] h-[calc(100%-3.6rem)] w-0.5 bg-gradient-to-t from-black/20 to-black/10 dark:from-white/20 dark:to-white/10" />
|
||||||
<div className="mb-6 flex flex-col">
|
<div className="mb-5 flex flex-col">
|
||||||
<User pubkey={data.pubkey} time={data.created_at} />
|
<User pubkey={data.pubkey} time={data.created_at} />
|
||||||
<div className="-mt-3 flex items-start gap-3">
|
<div className="-mt-3 flex items-start gap-3">
|
||||||
<div className="w-10 shrink-0" />
|
<div className="w-10 shrink-0" />
|
||||||
|
@ -26,3 +26,4 @@ export * from './mentions/boost';
|
|||||||
export * from './mentions/invoice';
|
export * from './mentions/invoice';
|
||||||
export * from './stats';
|
export * from './stats';
|
||||||
export * from './wrapper';
|
export * from './wrapper';
|
||||||
|
export * from './actions/more';
|
||||||
|
@ -29,7 +29,7 @@ export function ArticleNote(props: { event?: NDKEvent }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Link to={`/notes/article/${props.event.id}`} preventScrollReset={true}>
|
<Link to={`/notes/article/${props.event.id}`} preventScrollReset={true}>
|
||||||
<div className="mb-2 mt-2 flex flex-col rounded-lg">
|
<div className="my-2 overflow-hidden rounded-lg">
|
||||||
{metadata.image && (
|
{metadata.image && (
|
||||||
<Image
|
<Image
|
||||||
src={metadata.image}
|
src={metadata.image}
|
||||||
@ -37,16 +37,16 @@ export function ArticleNote(props: { event?: NDKEvent }) {
|
|||||||
className="h-44 w-full rounded-t-lg object-cover"
|
className="h-44 w-full rounded-t-lg object-cover"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<div className="flex flex-col gap-2 rounded-b-lg bg-white/10 px-3 py-3 backdrop-blur-xl">
|
<div className="flex flex-col gap-1 rounded-b-lg bg-neutral-200 px-3 py-3 dark:bg-neutral-800">
|
||||||
<h5 className="line-clamp-1 text-base font-medium text-white">
|
<h5 className="line-clamp-1 font-semibold text-neutral-900 dark:text-neutral-100">
|
||||||
{metadata.title}
|
{metadata.title}
|
||||||
</h5>
|
</h5>
|
||||||
{metadata.summary ? (
|
{metadata.summary ? (
|
||||||
<p className="line-clamp-3 break-all text-sm text-white/70">
|
<p className="line-clamp-3 break-all text-sm text-neutral-600 dark:text-neutral-400">
|
||||||
{metadata.summary}
|
{metadata.summary}
|
||||||
</p>
|
</p>
|
||||||
) : null}
|
) : null}
|
||||||
<span className="mt-2.5 text-sm text-white/70">
|
<span className="mt-2.5 text-sm text-neutral-500 dark:text-neutral-400">
|
||||||
{metadata.publishedAt.toString()}
|
{metadata.publishedAt.toString()}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,10 +1,15 @@
|
|||||||
import { NDKEvent } from '@nostr-dev-kit/ndk';
|
import { NDKEvent } from '@nostr-dev-kit/ndk';
|
||||||
import { MediaPlayer, MediaProvider, Poster } from '@vidstack/react';
|
|
||||||
import {
|
import {
|
||||||
DefaultAudioLayout,
|
MediaControlBar,
|
||||||
DefaultVideoLayout,
|
MediaController,
|
||||||
defaultLayoutIcons,
|
MediaMuteButton,
|
||||||
} from '@vidstack/react/player/layouts/default';
|
MediaPlayButton,
|
||||||
|
MediaSeekBackwardButton,
|
||||||
|
MediaSeekForwardButton,
|
||||||
|
MediaTimeDisplay,
|
||||||
|
MediaTimeRange,
|
||||||
|
MediaVolumeRange,
|
||||||
|
} from 'media-chrome/dist/react';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
@ -31,34 +36,25 @@ export function FileNote(props: { event?: NDKEvent }) {
|
|||||||
if (type === 'video') {
|
if (type === 'video') {
|
||||||
return (
|
return (
|
||||||
<div className="mb-2 mt-3">
|
<div className="mb-2 mt-3">
|
||||||
<MediaPlayer
|
<MediaController key={url} className="aspect-video">
|
||||||
key={url}
|
<video
|
||||||
|
slot="media"
|
||||||
src={url}
|
src={url}
|
||||||
poster={`https://thumbnail.video/api/get?url=${url}&seconds=1`}
|
poster={`https://thumbnail.video/api/get?url=${url}&seconds=1`}
|
||||||
load="idle"
|
preload="auto"
|
||||||
aspectRatio="16/9"
|
muted
|
||||||
muted={true}
|
crossOrigin=""
|
||||||
crossorigin=""
|
|
||||||
className="player"
|
|
||||||
>
|
|
||||||
<MediaProvider>
|
|
||||||
<Poster
|
|
||||||
className="vds-poster"
|
|
||||||
src={`https://thumbnail.video/api/get?url=${url}&seconds=1`}
|
|
||||||
alt="poster"
|
|
||||||
/>
|
/>
|
||||||
</MediaProvider>
|
<MediaControlBar>
|
||||||
<DefaultAudioLayout
|
<MediaPlayButton></MediaPlayButton>
|
||||||
icons={defaultLayoutIcons}
|
<MediaSeekBackwardButton></MediaSeekBackwardButton>
|
||||||
smallLayoutWhen="(width < 500) or (height < 380)"
|
<MediaSeekForwardButton></MediaSeekForwardButton>
|
||||||
noModal={true}
|
<MediaTimeRange></MediaTimeRange>
|
||||||
/>
|
<MediaTimeDisplay showDuration></MediaTimeDisplay>
|
||||||
<DefaultVideoLayout
|
<MediaMuteButton></MediaMuteButton>
|
||||||
icons={defaultLayoutIcons}
|
<MediaVolumeRange></MediaVolumeRange>
|
||||||
smallLayoutWhen="(width < 500) or (height < 380)"
|
</MediaControlBar>
|
||||||
noModal={true}
|
</MediaController>
|
||||||
/>
|
|
||||||
</MediaPlayer>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ export function TextNote(props: { content?: string }) {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<ReactMarkdown
|
<ReactMarkdown
|
||||||
className="prose prose-neutral max-w-none select-text leading-normal dark:prose-invert prose-headings:mb-1 prose-headings:mt-3 prose-p:mb-0 prose-p:mt-0 prose-p:last:mb-0 prose-a:font-normal prose-a:text-blue-500 prose-blockquote:mb-1 prose-blockquote:mt-1 prose-blockquote:border-l-[2px] prose-blockquote:border-blue-500 prose-blockquote:pl-2 prose-pre:whitespace-pre-wrap prose-pre:break-words prose-pre:break-all prose-pre:bg-white/10 prose-ol:m-0 prose-ol:mb-1 prose-ul:mb-1 prose-ul:mt-1 prose-img:mb-2 prose-img:mt-3 prose-hr:mx-0 prose-hr:my-2 hover:prose-a:text-blue-500"
|
className="prose prose-neutral max-w-none select-text leading-normal dark:prose-invert prose-headings:mb-1 prose-headings:mt-3 prose-p:mb-0 prose-p:mt-0 prose-p:last:mb-1 prose-a:font-normal prose-a:text-blue-500 prose-blockquote:mb-1 prose-blockquote:mt-1 prose-blockquote:border-l-[2px] prose-blockquote:border-blue-500 prose-blockquote:pl-2 prose-pre:whitespace-pre-wrap prose-pre:break-words prose-pre:break-all prose-pre:bg-white/10 prose-ol:m-0 prose-ol:mb-1 prose-ul:mb-1 prose-ul:mt-1 prose-img:mb-2 prose-img:mt-3 prose-hr:mx-0 prose-hr:my-2 hover:prose-a:text-blue-500"
|
||||||
remarkPlugins={[remarkGfm]}
|
remarkPlugins={[remarkGfm]}
|
||||||
disallowedElements={['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'pre', 'code']}
|
disallowedElements={['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'pre', 'code']}
|
||||||
unwrapDisallowed={true}
|
unwrapDisallowed={true}
|
||||||
@ -38,14 +38,14 @@ export function TextNote(props: { content?: string }) {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<ReactMarkdown
|
<ReactMarkdown
|
||||||
className="prose prose-neutral max-w-none select-text leading-normal dark:prose-invert prose-headings:mb-1 prose-headings:mt-3 prose-p:mb-0 prose-p:mt-0 prose-p:last:mb-0 prose-a:font-normal prose-a:text-blue-500 prose-blockquote:mb-1 prose-blockquote:mt-1 prose-blockquote:border-l-[2px] prose-blockquote:border-blue-500 prose-blockquote:pl-2 prose-pre:whitespace-pre-wrap prose-pre:break-words prose-pre:break-all prose-pre:bg-white/10 prose-ol:m-0 prose-ol:mb-1 prose-ul:mb-1 prose-ul:mt-1 prose-img:mb-2 prose-img:mt-3 prose-hr:mx-0 prose-hr:my-2 hover:prose-a:text-blue-500"
|
className="prose prose-neutral max-w-none select-text leading-normal dark:prose-invert prose-headings:mb-1 prose-headings:mt-3 prose-p:mb-0 prose-p:mt-0 prose-p:last:mb-1 prose-a:font-normal prose-a:text-blue-500 prose-blockquote:mb-1 prose-blockquote:mt-1 prose-blockquote:border-l-[2px] prose-blockquote:border-blue-500 prose-blockquote:pl-2 prose-pre:whitespace-pre-wrap prose-pre:break-words prose-pre:break-all prose-pre:bg-white/10 prose-ol:m-0 prose-ol:mb-1 prose-ul:mb-1 prose-ul:mt-1 prose-img:mb-2 prose-img:mt-3 prose-hr:mx-0 prose-hr:my-2 hover:prose-a:text-blue-500"
|
||||||
remarkPlugins={[remarkGfm]}
|
remarkPlugins={[remarkGfm]}
|
||||||
components={{
|
components={{
|
||||||
a: ({ href }) => {
|
a: ({ href }) => {
|
||||||
const cleanURL = new URL(href);
|
const cleanURL = new URL(href);
|
||||||
cleanURL.search = '';
|
cleanURL.search = '';
|
||||||
return (
|
return (
|
||||||
<Link to={href} target="_blank" className="line-clamp-1 w-full break-all">
|
<Link to={href} target="_blank" className="w-max break-all hover:underline">
|
||||||
{cleanURL.hostname + cleanURL.pathname}
|
{cleanURL.hostname + cleanURL.pathname}
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
@ -73,14 +73,12 @@ export function TextNote(props: { content?: string }) {
|
|||||||
>
|
>
|
||||||
{richContent.parsed}
|
{richContent.parsed}
|
||||||
</ReactMarkdown>
|
</ReactMarkdown>
|
||||||
<div>
|
|
||||||
{richContent.images.length > 0 && <ImagePreview urls={richContent.images} />}
|
{richContent.images.length > 0 && <ImagePreview urls={richContent.images} />}
|
||||||
{richContent.videos.length > 0 && <VideoPreview urls={richContent.videos} />}
|
{richContent.videos.length > 0 && <VideoPreview urls={richContent.videos} />}
|
||||||
{richContent.links.length > 0 && <LinkPreview urls={richContent.links} />}
|
{richContent.links.length > 0 && <LinkPreview urls={richContent.links} />}
|
||||||
{richContent.notes.length > 0 &&
|
{richContent.notes.length > 0 &&
|
||||||
richContent.notes.map((note: string) => <MentionNote key={note} id={note} />)}
|
richContent.notes.map((note: string) => <MentionNote key={note} id={note} />)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ import { download } from '@tauri-apps/plugin-upload';
|
|||||||
|
|
||||||
import { DownloadIcon } from '@shared/icons';
|
import { DownloadIcon } from '@shared/icons';
|
||||||
|
|
||||||
export function ImagePreview({ urls, truncate }: { urls: string[]; truncate?: boolean }) {
|
export function ImagePreview({ urls }: { urls: string[] }) {
|
||||||
const downloadImage = async (url: string) => {
|
const downloadImage = async (url: string) => {
|
||||||
const downloadDirPath = await downloadDir();
|
const downloadDirPath = await downloadDir();
|
||||||
const filename = url.substring(url.lastIndexOf('/') + 1);
|
const filename = url.substring(url.lastIndexOf('/') + 1);
|
||||||
@ -11,15 +11,13 @@ export function ImagePreview({ urls, truncate }: { urls: string[]; truncate?: bo
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-2">
|
<div className="my-2 flex flex-col gap-2">
|
||||||
{urls.map((url) => (
|
{urls.map((url) => (
|
||||||
<div key={url} className="group relative min-w-0 shrink-0 grow-0 basis-full">
|
<div key={url} className="group relative">
|
||||||
<img
|
<img
|
||||||
src={url}
|
src={url}
|
||||||
alt="image"
|
alt="image"
|
||||||
className={`${
|
className="h-auto w-full rounded-lg border border-neutral-200 object-cover dark:border-neutral-800"
|
||||||
truncate ? 'h-auto max-h-[300px]' : 'h-auto'
|
|
||||||
} w-full rounded-lg border border-white/10 object-cover`}
|
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
@ -7,9 +7,9 @@ export function LinkPreview({ urls }: { urls: string[] }) {
|
|||||||
const domain = new URL(urls[0]);
|
const domain = new URL(urls[0]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="rounded-lg bg-neutral-200 dark:bg-neutral-800">
|
<div className="my-2">
|
||||||
{status === 'loading' ? (
|
{status === 'loading' ? (
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col bg-neutral-200 dark:bg-neutral-800">
|
||||||
<div className="h-44 w-full animate-pulse bg-white/10 backdrop-blur-xl" />
|
<div className="h-44 w-full animate-pulse bg-white/10 backdrop-blur-xl" />
|
||||||
<div className="flex flex-col gap-2 px-3 py-3">
|
<div className="flex flex-col gap-2 px-3 py-3">
|
||||||
<div className="h-3 w-2/3 animate-pulse rounded bg-white/10 backdrop-blur-xl" />
|
<div className="h-3 w-2/3 animate-pulse rounded bg-white/10 backdrop-blur-xl" />
|
||||||
@ -24,7 +24,7 @@ export function LinkPreview({ urls }: { urls: string[] }) {
|
|||||||
to={urls[0]}
|
to={urls[0]}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
className="flex flex-col rounded-lg"
|
className="flex flex-col rounded-lg bg-neutral-200 dark:bg-neutral-800"
|
||||||
>
|
>
|
||||||
{error ? (
|
{error ? (
|
||||||
<div className="flex flex-col gap-2 px-3 py-3">
|
<div className="flex flex-col gap-2 px-3 py-3">
|
||||||
@ -42,9 +42,6 @@ export function LinkPreview({ urls }: { urls: string[] }) {
|
|||||||
src={data.image}
|
src={data.image}
|
||||||
alt={urls[0]}
|
alt={urls[0]}
|
||||||
className="h-44 w-full rounded-t-lg object-cover"
|
className="h-44 w-full rounded-t-lg object-cover"
|
||||||
loading="lazy"
|
|
||||||
decoding="async"
|
|
||||||
style={{ contentVisibility: 'auto' }}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<div className="flex flex-col gap-1 border-t border-white/5 px-3 py-3">
|
<div className="flex flex-col gap-1 border-t border-white/5 px-3 py-3">
|
||||||
|
@ -1,43 +1,34 @@
|
|||||||
import { MediaPlayer, MediaProvider, Poster } from '@vidstack/react';
|
|
||||||
import {
|
import {
|
||||||
DefaultAudioLayout,
|
MediaControlBar,
|
||||||
DefaultVideoLayout,
|
MediaController,
|
||||||
defaultLayoutIcons,
|
MediaMuteButton,
|
||||||
} from '@vidstack/react/player/layouts/default';
|
MediaPlayButton,
|
||||||
|
MediaTimeDisplay,
|
||||||
|
MediaTimeRange,
|
||||||
|
MediaVolumeRange,
|
||||||
|
} from 'media-chrome/dist/react';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
|
|
||||||
export const VideoPreview = memo(function VideoPreview({ urls }: { urls: string[] }) {
|
export const VideoPreview = memo(function VideoPreview({ urls }: { urls: string[] }) {
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-2">
|
<div className="my-2 flex flex-col gap-2">
|
||||||
{urls.map((url) => (
|
{urls.map((url) => (
|
||||||
<MediaPlayer
|
<MediaController key={url} className="aspect-video overflow-hidden rounded-lg">
|
||||||
key={url}
|
<video
|
||||||
|
slot="media"
|
||||||
src={url}
|
src={url}
|
||||||
poster={`https://thumbnail.video/api/get?url=${url}&seconds=1`}
|
poster={`https://thumbnail.video/api/get?url=${url}&seconds=1`}
|
||||||
load="idle"
|
preload="auto"
|
||||||
aspectRatio="16/9"
|
muted
|
||||||
crossorigin=""
|
|
||||||
muted={true}
|
|
||||||
className="player"
|
|
||||||
>
|
|
||||||
<MediaProvider>
|
|
||||||
<Poster
|
|
||||||
className="vds-poster"
|
|
||||||
src={`https://thumbnail.video/api/get?url=${url}&seconds=1`}
|
|
||||||
alt="poster"
|
|
||||||
/>
|
/>
|
||||||
</MediaProvider>
|
<MediaControlBar>
|
||||||
<DefaultAudioLayout
|
<MediaPlayButton></MediaPlayButton>
|
||||||
icons={defaultLayoutIcons}
|
<MediaTimeRange></MediaTimeRange>
|
||||||
smallLayoutWhen="(width < 500) or (height < 380)"
|
<MediaTimeDisplay showDuration></MediaTimeDisplay>
|
||||||
noModal={true}
|
<MediaMuteButton></MediaMuteButton>
|
||||||
/>
|
<MediaVolumeRange></MediaVolumeRange>
|
||||||
<DefaultVideoLayout
|
</MediaControlBar>
|
||||||
icons={defaultLayoutIcons}
|
</MediaController>
|
||||||
smallLayoutWhen="(width < 500) or (height < 380)"
|
|
||||||
noModal={true}
|
|
||||||
/>
|
|
||||||
</MediaPlayer>
|
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -8,6 +8,7 @@ import remarkGfm from 'remark-gfm';
|
|||||||
|
|
||||||
import { RepostIcon, WorldIcon } from '@shared/icons';
|
import { RepostIcon, WorldIcon } from '@shared/icons';
|
||||||
import { NIP05 } from '@shared/nip05';
|
import { NIP05 } from '@shared/nip05';
|
||||||
|
import { MoreActions } from '@shared/notes';
|
||||||
|
|
||||||
import { formatCreatedAt } from '@utils/createdAt';
|
import { formatCreatedAt } from '@utils/createdAt';
|
||||||
import { useProfile } from '@utils/hooks/useProfile';
|
import { useProfile } from '@utils/hooks/useProfile';
|
||||||
@ -15,11 +16,13 @@ import { displayNpub } from '@utils/shortenKey';
|
|||||||
|
|
||||||
export const User = memo(function User({
|
export const User = memo(function User({
|
||||||
pubkey,
|
pubkey,
|
||||||
|
eventId,
|
||||||
time,
|
time,
|
||||||
variant = 'default',
|
variant = 'default',
|
||||||
embedProfile,
|
embedProfile,
|
||||||
}: {
|
}: {
|
||||||
pubkey: string;
|
pubkey: string;
|
||||||
|
eventId?: string;
|
||||||
time?: number;
|
time?: number;
|
||||||
variant?:
|
variant?:
|
||||||
| 'default'
|
| 'default'
|
||||||
@ -301,33 +304,34 @@ export const User = memo(function User({
|
|||||||
<HoverCard.Root>
|
<HoverCard.Root>
|
||||||
<div className="relative z-10 flex items-start gap-3">
|
<div className="relative z-10 flex items-start gap-3">
|
||||||
<HoverCard.Trigger asChild>
|
<HoverCard.Trigger asChild>
|
||||||
<Avatar.Root className="h-10 w-10 shrink-0">
|
<Avatar.Root className="relative top-1 shrink-0">
|
||||||
<Avatar.Image
|
<Avatar.Image
|
||||||
src={user?.picture || user?.image}
|
src={user?.picture || user?.image}
|
||||||
alt={pubkey}
|
alt={pubkey}
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
decoding="async"
|
decoding="async"
|
||||||
style={{ contentVisibility: 'auto' }}
|
style={{ contentVisibility: 'auto' }}
|
||||||
className="h-10 w-10 rounded-lg object-cover"
|
className="h-10 w-10 rounded-lg bg-white object-cover"
|
||||||
/>
|
/>
|
||||||
<Avatar.Fallback delayMs={300}>
|
<Avatar.Fallback delayMs={300}>
|
||||||
<img
|
<img
|
||||||
src={svgURI}
|
src={svgURI}
|
||||||
alt={pubkey}
|
alt={pubkey}
|
||||||
className="h-10 w-10 rounded-lg border border-white/5 bg-black dark:bg-white"
|
className="h-10 w-10 rounded-lg bg-black dark:bg-white"
|
||||||
/>
|
/>
|
||||||
</Avatar.Fallback>
|
</Avatar.Fallback>
|
||||||
</Avatar.Root>
|
</Avatar.Root>
|
||||||
</HoverCard.Trigger>
|
</HoverCard.Trigger>
|
||||||
<div className="flex flex-1 items-center gap-2">
|
<div className="flex flex-1 items-start 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?.name ||
|
||||||
user?.display_name ||
|
user?.display_name ||
|
||||||
user?.displayName ||
|
user?.displayName ||
|
||||||
displayNpub(pubkey, 16)}
|
displayNpub(pubkey, 16)}
|
||||||
</div>
|
</div>
|
||||||
<div className="ml-auto text-neutral-500 dark:text-neutral-400">
|
<div className="ml-auto inline-flex items-center gap-3">
|
||||||
{createdAt}
|
<div className="text-neutral-500 dark:text-neutral-400">{createdAt}</div>
|
||||||
|
<MoreActions id={eventId} pubkey={pubkey} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -4,7 +4,7 @@ import { defineConfig } from 'vite';
|
|||||||
import viteTsconfigPaths from 'vite-tsconfig-paths';
|
import viteTsconfigPaths from 'vite-tsconfig-paths';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [million.vite({ auto: true }), react(), viteTsconfigPaths()],
|
plugins: [million.vite({ auto: true, mute: true }), react(), viteTsconfigPaths()],
|
||||||
envPrefix: ['VITE_', 'TAURI_'],
|
envPrefix: ['VITE_', 'TAURI_'],
|
||||||
build: {
|
build: {
|
||||||
target: process.env.TAURI_PLATFORM === 'windows' ? 'chrome105' : 'safari13',
|
target: process.env.TAURI_PLATFORM === 'windows' ? 'chrome105' : 'safari13',
|
||||||
|
Loading…
Reference in New Issue
Block a user