feat: polish
This commit is contained in:
@@ -569,4 +569,17 @@ export class Ark {
|
||||
fileDropEnabled: true,
|
||||
});
|
||||
}
|
||||
|
||||
public open_settings() {
|
||||
return new WebviewWindow("settings", {
|
||||
title: "Settings",
|
||||
url: "/settings",
|
||||
minWidth: 600,
|
||||
width: 800,
|
||||
height: 500,
|
||||
hiddenTitle: true,
|
||||
titleBarStyle: "overlay",
|
||||
fileDropEnabled: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
import { SVGProps } from 'react';
|
||||
import { SVGProps } from "react";
|
||||
|
||||
export function LoaderIcon(props: JSX.IntrinsicAttributes & SVGProps<SVGSVGElement>) {
|
||||
export function LoaderIcon(
|
||||
props: JSX.IntrinsicAttributes & SVGProps<SVGSVGElement>,
|
||||
) {
|
||||
return (
|
||||
<svg {...props} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||
<title id="loading">Loading</title>
|
||||
<svg
|
||||
{...props}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<circle
|
||||
className="opacity-25"
|
||||
cx="12"
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
import { NOSTR_MENTIONS } from "@lume/utils";
|
||||
import { nanoid } from "nanoid";
|
||||
import { ReactNode, useMemo } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import reactStringReplace from "react-string-replace";
|
||||
import { User } from "../user";
|
||||
import { Hashtag } from "./mentions/hashtag";
|
||||
import { MentionUser } from "./mentions/user";
|
||||
import { useEvent } from "@lume/ark";
|
||||
|
||||
export function NoteChild({
|
||||
@@ -18,66 +12,6 @@ export function NoteChild({
|
||||
const { t } = useTranslation();
|
||||
const { isLoading, isError, data } = useEvent(eventId);
|
||||
|
||||
const richContent = useMemo(() => {
|
||||
if (!data) return "";
|
||||
|
||||
let parsedContent: string | ReactNode[] =
|
||||
data.content.substring(0, 160) + "...";
|
||||
|
||||
const text = data.content;
|
||||
const words = text.split(/( |\n)/);
|
||||
|
||||
const hashtags = words.filter((word) => word.startsWith("#"));
|
||||
const mentions = words.filter((word) =>
|
||||
NOSTR_MENTIONS.some((el) => word.startsWith(el)),
|
||||
);
|
||||
|
||||
try {
|
||||
if (hashtags.length) {
|
||||
for (const hashtag of hashtags) {
|
||||
const regex = new RegExp(`(|^)${hashtag}\\b`, "g");
|
||||
parsedContent = reactStringReplace(parsedContent, regex, () => {
|
||||
return <Hashtag key={nanoid()} tag={hashtag} />;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (mentions.length) {
|
||||
for (const mention of mentions) {
|
||||
parsedContent = reactStringReplace(
|
||||
parsedContent,
|
||||
mention,
|
||||
(match, i) => <MentionUser key={match + i} pubkey={mention} />,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
parsedContent = reactStringReplace(
|
||||
parsedContent,
|
||||
/(https?:\/\/\S+)/g,
|
||||
(match, i) => {
|
||||
const url = new URL(match);
|
||||
return (
|
||||
<a
|
||||
key={match + i}
|
||||
href={url.toString()}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="content-break font-normal text-blue-500 hover:text-blue-600"
|
||||
>
|
||||
{url.toString()}
|
||||
</a>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
return parsedContent;
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
return parsedContent;
|
||||
}
|
||||
}, [data]);
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="relative flex gap-3">
|
||||
@@ -102,8 +36,8 @@ export function NoteChild({
|
||||
<div className="relative flex gap-3">
|
||||
<div className="relative flex-1 rounded-xl bg-neutral-100 p-3 dark:bg-neutral-900">
|
||||
<div className="absolute right-0 top-[18px] h-3 w-3 -translate-y-1/2 translate-x-1/2 rotate-45 transform bg-neutral-100 dark:bg-neutral-900" />
|
||||
<div className="content-break mt-6 select-text leading-normal text-neutral-900 dark:text-neutral-100">
|
||||
{richContent}
|
||||
<div className="content-break mt-6 line-clamp-3 select-text leading-normal text-neutral-900 dark:text-neutral-100">
|
||||
{data.content}
|
||||
</div>
|
||||
</div>
|
||||
<User.Provider pubkey={data.pubkey}>
|
||||
|
||||
@@ -10,19 +10,18 @@ import {
|
||||
import { NIP89 } from "./nip89";
|
||||
import { useNoteContext } from "./provider";
|
||||
import { ReactNode, useMemo } from "react";
|
||||
import reactStringReplace from "react-string-replace";
|
||||
import { nanoid } from "nanoid";
|
||||
import { MentionUser } from "./mentions/user";
|
||||
import { MentionNote } from "./mentions/note";
|
||||
import { Hashtag } from "./mentions/hashtag";
|
||||
import { VideoPreview } from "./preview/video";
|
||||
import { stripHtml } from "string-strip-html";
|
||||
import { ImagePreview } from "./preview/image";
|
||||
import reactStringReplace from "react-string-replace";
|
||||
|
||||
export function NoteContent({ className }: { className?: string }) {
|
||||
const event = useNoteContext();
|
||||
const content = useMemo(() => {
|
||||
const text = stripHtml(event.content.trim()).result;
|
||||
const text = event.content.trim();
|
||||
const words = text.split(/( |\n)/);
|
||||
|
||||
// @ts-ignore, kaboom !!!
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
import { NOSTR_MENTIONS } from "@lume/utils";
|
||||
import { ReactNode, useMemo } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import reactStringReplace from "react-string-replace";
|
||||
import { User } from "../../user";
|
||||
import { Hashtag } from "./hashtag";
|
||||
import { MentionUser } from "./user";
|
||||
import { useArk, useEvent } from "@lume/ark";
|
||||
import { LinkIcon } from "@lume/icons";
|
||||
import { stripHtml } from "string-strip-html";
|
||||
|
||||
export function MentionNote({
|
||||
eventId,
|
||||
@@ -16,72 +10,11 @@ export function MentionNote({
|
||||
eventId: string;
|
||||
openable?: boolean;
|
||||
}) {
|
||||
const ark = useArk();
|
||||
|
||||
const { t } = useTranslation();
|
||||
const { isLoading, isError, data } = useEvent(eventId);
|
||||
|
||||
const ark = useArk();
|
||||
const content = useMemo(() => {
|
||||
if (!data) return "";
|
||||
|
||||
const text = stripHtml(data.content.trim()).result;
|
||||
const words = text.split(/( |\n)/);
|
||||
|
||||
// @ts-ignore, kaboom !!!
|
||||
let parsedContent: ReactNode[] = text;
|
||||
|
||||
const hashtags = words.filter((word) => word.startsWith("#"));
|
||||
const mentions = words.filter((word) =>
|
||||
NOSTR_MENTIONS.some((el) => word.startsWith(el)),
|
||||
);
|
||||
|
||||
try {
|
||||
if (hashtags.length) {
|
||||
for (const hashtag of hashtags) {
|
||||
parsedContent = reactStringReplace(
|
||||
parsedContent,
|
||||
hashtag,
|
||||
(match, i) => {
|
||||
return <Hashtag key={match + i} tag={hashtag} />;
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (mentions.length) {
|
||||
for (const mention of mentions) {
|
||||
parsedContent = reactStringReplace(
|
||||
parsedContent,
|
||||
mention,
|
||||
(match, i) => <MentionUser key={match + i} pubkey={mention} />,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
parsedContent = reactStringReplace(
|
||||
parsedContent,
|
||||
/(https?:\/\/\S+)/g,
|
||||
(match, i) => {
|
||||
const url = new URL(match);
|
||||
return (
|
||||
<a
|
||||
key={match + i}
|
||||
href={url.toString()}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="content-break inline-block w-full truncate font-normal text-blue-500 hover:text-blue-600"
|
||||
>
|
||||
{url.toString()}
|
||||
</a>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
return parsedContent;
|
||||
} catch (e) {
|
||||
return text;
|
||||
}
|
||||
}, [data]);
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div
|
||||
@@ -120,7 +53,7 @@ export function MentionNote({
|
||||
</User.Root>
|
||||
</User.Provider>
|
||||
<div className="line-clamp-4 select-text whitespace-normal text-balance leading-normal">
|
||||
{content}
|
||||
{data.content}
|
||||
</div>
|
||||
{openable ? (
|
||||
<div className="flex h-10 items-center justify-between">
|
||||
|
||||
Reference in New Issue
Block a user