diff --git a/apps/desktop/src/app.css b/apps/desktop/src/app.css index fcc160cb..4c25b06a 100644 --- a/apps/desktop/src/app.css +++ b/apps/desktop/src/app.css @@ -14,7 +14,7 @@ } .shadow-toolbar { - box-shadow: 0 0 #0000,0 0 #0000,0 8px 24px 0 rgba(0,0,0,.2),0 2px 8px 0 rgba(0,0,0,.08),inset 0 0 0 1px rgba(0,0,0,.2),inset 0 0 0 2px hsla(0,0%,100%,.14) + box-shadow: 0 0 #0000, 0 0 #0000, 0 8px 24px 0 rgba(0, 0, 0, .2), 0 2px 8px 0 rgba(0, 0, 0, .08), inset 0 0 0 1px rgba(0, 0, 0, .2), inset 0 0 0 2px hsla(0, 0%, 100%, .14) } } @@ -42,3 +42,7 @@ input::-ms-clear { .border { background-clip: padding-box; } + +media-controller { + @apply w-full; +} \ No newline at end of file diff --git a/packages/ark/src/components/note/preview/video.tsx b/packages/ark/src/components/note/preview/video.tsx index 3fced92d..5a82a1ed 100644 --- a/packages/ark/src/components/note/preview/video.tsx +++ b/packages/ark/src/components/note/preview/video.tsx @@ -5,7 +5,6 @@ import { MediaPlayButton, MediaTimeDisplay, MediaTimeRange, - MediaVolumeRange, } from "media-chrome/dist/react"; export function VideoPreview({ url }: { url: string }) { @@ -24,7 +23,6 @@ export function VideoPreview({ url }: { url: string }) { <MediaTimeRange /> <MediaTimeDisplay showDuration /> <MediaMuteButton /> - <MediaVolumeRange /> </MediaControlBar> </MediaController> </div> diff --git a/packages/ark/src/components/user/followButton.tsx b/packages/ark/src/components/user/followButton.tsx index d7dc3672..20bf6ada 100644 --- a/packages/ark/src/components/user/followButton.tsx +++ b/packages/ark/src/components/user/followButton.tsx @@ -13,6 +13,7 @@ export function UserFollowButton({ const [followed, setFollowed] = useState(false); const toggleFollow = async () => { + setLoading(true); if (!followed) { const add = await ark.createContact(target); if (add) setFollowed(true); @@ -20,6 +21,7 @@ export function UserFollowButton({ const remove = await ark.deleteContact(target); if (remove) setFollowed(false); } + setLoading(false); }; useEffect(() => { @@ -37,7 +39,12 @@ export function UserFollowButton({ }, []); return ( - <button type="button" onClick={toggleFollow} className={cn("", className)}> + <button + type="button" + disabled={loading} + onClick={toggleFollow} + className={cn("", className)} + > {loading ? ( <LoaderIcon className="size-4 animate-spin" /> ) : followed ? ( diff --git a/packages/ark/src/components/user/name.tsx b/packages/ark/src/components/user/name.tsx index c08a3832..f9f1c232 100644 --- a/packages/ark/src/components/user/name.tsx +++ b/packages/ark/src/components/user/name.tsx @@ -8,7 +8,7 @@ export function UserName({ className }: { className?: string }) { return ( <div className={cn( - "h-4 w-20 bg-black/20 dark:bg-white/20 rounded animate-pulse", + "h-4 w-20 self-center bg-black/20 dark:bg-white/20 rounded animate-pulse", className, )} /> diff --git a/packages/ark/src/provider.tsx b/packages/ark/src/provider.tsx index a9c2abfd..99a06d4e 100644 --- a/packages/ark/src/provider.tsx +++ b/packages/ark/src/provider.tsx @@ -91,6 +91,7 @@ export const LumeProvider = ({ children }: PropsWithChildren<object>) => { const explicitRelayUrls = normalizeRelayUrlSet([ "wss://nostr.mutinywallet.com/", "wss://bostr.nokotaro.com/", + "wss://purplepag.es/", ]); const outboxRelayUrls = normalizeRelayUrlSet(["wss://purplepag.es/"]); @@ -227,7 +228,7 @@ export const LumeProvider = ({ children }: PropsWithChildren<object>) => { return ( <div data-tauri-drag-region - className="relative flex items-center justify-center w-screen h-screen bg-neutral-50 dark:bg-neutral-950" + className="relative flex items-center justify-center w-screen h-screen" > <div className="flex flex-col items-start max-w-2xl gap-1"> <h5 className="font-semibold uppercase">TIP:</h5> diff --git a/packages/lume-column-timeline/src/home.tsx b/packages/lume-column-timeline/src/home.tsx index 41274a9b..5a7ae8f0 100644 --- a/packages/lume-column-timeline/src/home.tsx +++ b/packages/lume-column-timeline/src/home.tsx @@ -50,18 +50,7 @@ export function HomeRoute({ colKey }: { colKey: string }) { if (!lastEvent) return; return lastEvent.created_at - 1; }, - initialData: () => { - const queryCacheData = queryClient.getQueryState([colKey]) - ?.data as NDKEvent[]; - if (queryCacheData) { - return { - pageParams: [undefined, 1], - pages: [queryCacheData], - }; - } - }, select: (data) => data?.pages.flatMap((page) => page), - staleTime: 120 * 1000, refetchOnWindowFocus: false, refetchOnMount: false, }); @@ -115,6 +104,17 @@ export function HomeRoute({ colKey }: { colKey: string }) { <div className="w-full flex h-16 items-center justify-center gap-2 px-3 py-1.5"> <LoaderIcon className="size-5 animate-spin" /> </div> + ) : !data.length ? ( + <div className="px-3 mt-3"> + <EmptyFeed /> + <Link + to="/suggest" + className="mt-3 w-full gap-2 inline-flex items-center justify-center text-sm font-medium rounded-lg h-9 bg-blue-500 hover:bg-blue-600 text-white" + > + <SearchIcon className="size-5" /> + Find accounts to follow + </Link> + </div> ) : ( data.map((item) => renderItem(item)) )} diff --git a/packages/ui/src/onboarding/finish.tsx b/packages/ui/src/onboarding/finish.tsx index e4966ac6..228c58ba 100644 --- a/packages/ui/src/onboarding/finish.tsx +++ b/packages/ui/src/onboarding/finish.tsx @@ -1,5 +1,5 @@ -import { useArk } from "@lume/ark"; import { CheckIcon, LoaderIcon } from "@lume/icons"; +import { useStorage } from "@lume/storage"; import { onboardingAtom } from "@lume/utils"; import { useQueryClient } from "@tanstack/react-query"; import { motion } from "framer-motion"; @@ -7,6 +7,7 @@ import { useSetAtom } from "jotai"; import { useState } from "react"; export function OnboardingFinishScreen() { + const storage = useStorage(); const queryClient = useQueryClient(); const setOnboarding = useSetAtom(onboardingAtom); @@ -15,8 +16,9 @@ export function OnboardingFinishScreen() { const finish = async () => { setLoading(true); - await queryClient.refetchQueries({ queryKey: ["timeline-9999"] }); - await queryClient.refetchQueries({ queryKey: ["foryou-9998"] }); + if (storage.interests) { + await queryClient.invalidateQueries({ queryKey: ["foryou-9998"] }); + } setLoading(false); setOnboarding({ open: false, newUser: false }); diff --git a/packages/ui/src/onboarding/interest.tsx b/packages/ui/src/onboarding/interest.tsx index 95bc1296..8b661a9c 100644 --- a/packages/ui/src/onboarding/interest.tsx +++ b/packages/ui/src/onboarding/interest.tsx @@ -35,9 +35,10 @@ export function OnboardingInterestScreen() { JSON.stringify({ hashtags }), ); - setLoading(false); - - if (save) return navigate("/finish"); + if (save) { + storage.interests = { hashtags, users: [], words: [] }; + return navigate("/finish"); + } } catch (e) { setLoading(false); toast.error(String(e)); diff --git a/packages/ui/src/routes/suggest.tsx b/packages/ui/src/routes/suggest.tsx index af252098..1630953c 100644 --- a/packages/ui/src/routes/suggest.tsx +++ b/packages/ui/src/routes/suggest.tsx @@ -1,15 +1,6 @@ -import { User, useArk } from "@lume/ark"; -import { - ArrowLeftIcon, - ArrowRightIcon, - CancelIcon, - LoaderIcon, - PlusIcon, -} from "@lume/icons"; -import { cn } from "@lume/utils"; +import { User } from "@lume/ark"; +import { ArrowLeftIcon, ArrowRightIcon, LoaderIcon } from "@lume/icons"; import { useQuery, useQueryClient } from "@tanstack/react-query"; -import { nip19 } from "nostr-tools"; -import { useState } from "react"; import { useNavigate } from "react-router-dom"; import { toast } from "sonner"; import { WindowVirtualizer } from "virtua"; @@ -34,7 +25,6 @@ const LUME_USERS = [ ]; export function SuggestRoute({ queryKey }: { queryKey: string[] }) { - const ark = useArk(); const queryClient = useQueryClient(); const navigate = useNavigate(); @@ -51,40 +41,11 @@ export function SuggestRoute({ queryKey }: { queryKey: string[] }) { }, }); - const [loading, setLoading] = useState(false); - const [follows, setFollows] = useState<string[]>([]); - - // toggle follow state - const toggleFollow = (pubkey: string) => { - const arr = follows.includes(pubkey) - ? follows.filter((i) => i !== pubkey) - : [...follows, pubkey]; - setFollows(arr); - }; - const submit = async () => { try { - setLoading(true); - - if (!follows.length) return navigate("/"); - - const publish = await ark.newContactList({ - tags: follows.map((item) => { - if (item.startsWith("npub1")) - return ["p", nip19.decode(item).data as string]; - return ["p", item]; - }), - }); - - if (publish) { - await queryClient.refetchQueries({ queryKey: ["timeline-9999"] }); - } - - setLoading(false); - - return navigate("/"); + await queryClient.refetchQueries({ queryKey }); + return navigate("/", { replace: true }); } catch (e) { - setLoading(false); toast.error(String(e)); } }; @@ -135,30 +96,12 @@ export function SuggestRoute({ queryKey }: { queryKey: string[] }) { <User.Avatar className="size-10 shrink-0 rounded-lg" /> <User.Name className="max-w-[15rem] truncate font-semibold leadning-tight" /> </div> - <button - type="button" - onClick={() => toggleFollow(item.pubkey)} - className={cn( - "inline-flex h-8 shrink-0 pl-2 pr-2.5 items-center justify-center gap-1 rounded-lg text-sm font-medium", - follows.includes(item.pubkey) - ? "text-red-500 bg-red-100 hover:text-white hover:bg-red-500" - : "text-blue-500 bg-blue-100 hover:text-white hover:bg-blue-500", - )} - > - {follows.includes(item.pubkey) ? ( - <> - <CancelIcon className="size-4" /> - Unfollow - </> - ) : ( - <> - <PlusIcon className="size-4" /> - Follow - </> - )} - </button> + <User.Button + target={item.pubkey} + className="w-20 h-8 text-sm font-medium bg-neutral-100 dark:bg-neutral-900 hover:bg-neutral-200 dark:hover:bg-neutral-800 rounded-lg inline-flex items-center justify-center" + /> </div> - <User.About className="break-p text-neutral-800 dark:text-neutral-400 max-w-none select-text whitespace-pre-line" /> + <User.About className="mt-1 line-clamp-3 text-neutral-800 dark:text-neutral-400 max-w-none select-text" /> </div> </User.Root> </User.Provider> @@ -170,10 +113,9 @@ export function SuggestRoute({ queryKey }: { queryKey: string[] }) { <button type="button" onClick={submit} - disabled={loading} - className="inline-flex items-center justify-center gap-2 px-6 font-medium shadow-xl shadow-neutral-500/50 text-white transform bg-blue-500 rounded-full active:translate-y-1 w-36 h-11 hover:bg-blue-600 focus:outline-none disabled:cursor-not-allowed" + className="inline-flex items-center justify-center gap-2 px-6 font-medium shadow-xl dark:shadow-none shadow-neutral-500/50 text-white transform bg-blue-500 rounded-full active:translate-y-1 w-44 h-11 hover:bg-blue-600 focus:outline-none disabled:cursor-not-allowed" > - Save & Go Back + Save & Go back </button> </div> </div> diff --git a/packages/utils/src/constants.ts b/packages/utils/src/constants.ts index c1e711a5..520e94ae 100644 --- a/packages/utils/src/constants.ts +++ b/packages/utils/src/constants.ts @@ -26,7 +26,7 @@ export const NOSTR_EVENTS = [ "Nostr:nevent1", ]; -// const BITCOINS = ['lnbc', 'bc1p', 'bc1q']; +export const BITCOINS = ['lnbc', 'bc1p', 'bc1q']; export const IMAGES = ["jpg", "jpeg", "gif", "png", "webp", "avif", "tiff"]; @@ -45,37 +45,6 @@ export const VIDEOS = [ export const AUDIOS = ["mp3", "ogg", "wav"]; -export const HASHTAGS = [ - { hashtag: "#food" }, - { hashtag: "#gaming" }, - { hashtag: "#nsfw" }, - { hashtag: "#bitcoin" }, - { hashtag: "#nostr" }, - { hashtag: "#nostrdesign" }, - { hashtag: "#security" }, - { hashtag: "#zap" }, - { hashtag: "#LFG" }, - { hashtag: "#zapchain" }, - { hashtag: "#shitcoin" }, - { hashtag: "#plebchain" }, - { hashtag: "#nodes" }, - { hashtag: "#hodl" }, - { hashtag: "#stacksats" }, - { hashtag: "#nokyc" }, - { hashtag: "#meme" }, - { hashtag: "#memes" }, - { hashtag: "#memestr" }, - { hashtag: "#nostriches" }, - { hashtag: "#dev" }, - { hashtag: "#anime" }, - { hashtag: "#waifu" }, - { hashtag: "#manga" }, - { hashtag: "#lume" }, - { hashtag: "#snort" }, - { hashtag: "#damus" }, - { hashtag: "#primal" }, -]; - export const COL_TYPES = { default: 0, user: 1, @@ -173,7 +142,6 @@ export const TOPICS = [ "#pcgaming", "#nintendo", "#switch", - "#pubg", "#esports", "#gameoftheyear", "#darksoul", @@ -326,7 +294,6 @@ export const TOPICS = [ "#fashion", "#travel", "#photoshoot", - "#nature", "#naturephotography", "#smile", "#style", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 55152cd1..f127e1be 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -419,58 +419,6 @@ importers: specifier: ^5.3.3 version: 5.3.3 - packages/lume-column-activity: - dependencies: - '@lume/ark': - specifier: workspace:^ - version: link:../ark - '@lume/icons': - specifier: workspace:^ - version: link:../icons - '@lume/ui': - specifier: workspace:^ - version: link:../ui - '@lume/utils': - specifier: workspace:^ - version: link:../utils - '@nostr-dev-kit/ndk': - specifier: ^2.3.3 - version: 2.3.3(typescript@5.3.3) - '@tanstack/react-query': - specifier: ^5.17.19 - version: 5.17.19(react@18.2.0) - react: - specifier: ^18.2.0 - version: 18.2.0 - react-router-dom: - specifier: ^6.21.3 - version: 6.21.3(react-dom@18.2.0)(react@18.2.0) - sonner: - specifier: ^1.3.1 - version: 1.3.1(react-dom@18.2.0)(react@18.2.0) - virtua: - specifier: ^0.21.1 - version: 0.21.1(react-dom@18.2.0)(react@18.2.0) - devDependencies: - '@lume/tailwindcss': - specifier: workspace:^ - version: link:../tailwindcss - '@lume/tsconfig': - specifier: workspace:^ - version: link:../tsconfig - '@lume/types': - specifier: workspace:^ - version: link:../types - '@types/react': - specifier: ^18.2.48 - version: 18.2.48 - tailwind: - specifier: ^4.0.0 - version: 4.0.0 - typescript: - specifier: ^5.3.3 - version: 5.3.3 - packages/lume-column-antenas: dependencies: '@lume/ark':