diff --git a/.drone.yml b/.drone.yml index 412d6cd1..99e3b778 100644 --- a/.drone.yml +++ b/.drone.yml @@ -7,6 +7,8 @@ concurrency: trigger: branch: - main + event: + - push metadata: namespace: git steps: @@ -72,6 +74,8 @@ concurrency: trigger: branch: - main + event: + - push metadata: namespace: git steps: diff --git a/package.json b/package.json index 0d26662c..fa26554d 100644 --- a/package.json +++ b/package.json @@ -4,9 +4,9 @@ "packages/*" ], "scripts": { - "build": "yarn workspace @snort/shared build && yarn workspace @snort/system build && yarn workspace @snort/system-react build && yarn workspace @snort/app build", - "start": "yarn workspace @snort/shared build && yarn workspace @snort/system build && yarn workspace @snort/system-react build && yarn workspace @snort/app start", - "test": "yarn workspace @snort/shared build && yarn workspace @snort/system build && yarn workspace @snort/app test && yarn workspace @snort/system test", + "build": "yarn workspace @snort/shared build && yarn workspace @snort/system build && yarn workspace @snort/system-web build && yarn workspace @snort/system-react build && yarn workspace @snort/app build", + "start": "yarn build && yarn workspace @snort/app start", + "test": "yarn build && yarn workspace @snort/app test && yarn workspace @snort/system test", "pre:commit": "yarn workspace @snort/app intl-extract && yarn workspace @snort/app intl-compile && yarn prettier --write ." }, "prettier": { diff --git a/packages/app/package.json b/packages/app/package.json index 2ebc9af2..0a5dd253 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -13,12 +13,15 @@ "@snort/system": "workspace:*", "@snort/system-react": "workspace:*", "@snort/system-wasm": "workspace:*", + "@snort/system-web": "workspace:*", "@szhsin/react-menu": "^3.3.1", "@types/use-sync-external-store": "^0.0.4", + "@uidotdev/usehooks": "^2.3.1", "@void-cat/api": "^1.0.4", "debug": "^4.3.4", "dexie": "^3.2.4", "emojilib": "^3.0.10", + "highlight.js": "^11.8.0", "light-bolt11-decoder": "^2.1.0", "match-sorter": "^6.3.1", "qr-code-styling": "^1.6.0-rc.1", @@ -29,6 +32,7 @@ "react-router-dom": "^6.5.0", "react-textarea-autosize": "^8.4.0", "react-twitter-embed": "^4.0.4", + "recharts": "^2.8.0", "use-long-press": "^3.2.0", "use-sync-external-store": "^1.2.0", "uuid": "^9.0.0", diff --git a/packages/app/public/icons.svg b/packages/app/public/icons.svg index f7e27883..ae164d36 100644 --- a/packages/app/public/icons.svg +++ b/packages/app/public/icons.svg @@ -339,9 +339,14 @@ - - - + + + + + + + + \ No newline at end of file diff --git a/packages/app/public/snort/.well-known/assetlinks.json b/packages/app/public/snort/.well-known/assetlinks.json new file mode 100644 index 00000000..6db2507a --- /dev/null +++ b/packages/app/public/snort/.well-known/assetlinks.json @@ -0,0 +1,12 @@ +[ + { + "relation": ["delegate_permission/common.handle_all_urls"], + "target": { + "namespace": "android_app", + "package_name": "social.snort.app", + "sha256_cert_fingerprints": [ + "78:CE:8A:F7:C1:E2:30:12:77:55:BF:0E:86:E4:5C:BA:99:93:A0:D7:D7:42:F8:27:8B:C9:1B:AC:FC:8A:85:05" + ] + } + } +] diff --git a/packages/app/src/Cache/index.ts b/packages/app/src/Cache/index.ts index 63c1a0f7..ee9a9522 100644 --- a/packages/app/src/Cache/index.ts +++ b/packages/app/src/Cache/index.ts @@ -1,4 +1,6 @@ import { UserProfileCache, UserRelaysCache, RelayMetricCache } from "@snort/system"; +import { SnortSystemDb } from "@snort/system-web"; + import { EventInteractionCache } from "./EventInteractionCache"; import { ChatCache } from "./ChatCache"; import { Payments } from "./PaymentsCache"; @@ -6,9 +8,11 @@ import { GiftWrapCache } from "./GiftWrapCache"; import { NotificationsCache } from "./Notifications"; import { FollowsFeedCache } from "./FollowsFeed"; -export const UserCache = new UserProfileCache(); -export const UserRelays = new UserRelaysCache(); -export const RelayMetrics = new RelayMetricCache(); +export const SystemDb = new SnortSystemDb(); +export const UserCache = new UserProfileCache(SystemDb.users); +export const UserRelays = new UserRelaysCache(SystemDb.userRelays); +export const RelayMetrics = new RelayMetricCache(SystemDb.relayMetrics); + export const Chats = new ChatCache(); export const PaymentsCache = new Payments(); export const InteractionCache = new EventInteractionCache(); diff --git a/packages/app/src/Element/CodeBlock.css b/packages/app/src/Element/CodeBlock.css new file mode 100644 index 00000000..af8a21e8 --- /dev/null +++ b/packages/app/src/Element/CodeBlock.css @@ -0,0 +1,14 @@ +.codeblock { + overflow: auto; + position: relative; +} + +.codeblock pre { + overflow: auto; + line-height: 1.4; + font-size: var(--font-size); +} + +.hljs { + background: #f6f8fa; +} diff --git a/packages/app/src/Element/CodeBlock.tsx b/packages/app/src/Element/CodeBlock.tsx new file mode 100644 index 00000000..825c1ccb --- /dev/null +++ b/packages/app/src/Element/CodeBlock.tsx @@ -0,0 +1,24 @@ +import { useEffect } from "react"; +import "highlight.js/styles/github.css"; +import "./CodeBlock.css"; + +const CodeBlock = ({ content, language }: { content: string; language?: string }) => { + useEffect(() => { + const importHljs = async () => { + const hljs = (await import("highlight.js")).default; + hljs.highlightAll(); + }; + + importHljs(); + }); + + return ( +
+
+        {content.trim()}
+      
+
+ ); +}; + +export default CodeBlock; diff --git a/packages/app/src/Element/Event/Reactions.css b/packages/app/src/Element/Event/Reactions.css index 1ce3ca5f..f6612b25 100644 --- a/packages/app/src/Element/Event/Reactions.css +++ b/packages/app/src/Element/Event/Reactions.css @@ -1,6 +1,6 @@ .reactions-modal .modal-body { padding: 24px 32px; - background-color: #1b1b1b; + background-color: var(--gray-superdark); border-radius: 16px; position: relative; min-height: 33vh; diff --git a/packages/app/src/Element/Tabs.css b/packages/app/src/Element/Tabs.css index 9ee1a86c..d0e8b380 100644 --- a/packages/app/src/Element/Tabs.css +++ b/packages/app/src/Element/Tabs.css @@ -34,7 +34,7 @@ border-radius: 100px; font-weight: 600; font-size: 16px; - padding: 10px 16px; + padding: 6px 12px; display: flex; align-items: center; justify-items: center; diff --git a/packages/app/src/Element/Tabs.tsx b/packages/app/src/Element/Tabs.tsx index 427610f3..318afefc 100644 --- a/packages/app/src/Element/Tabs.tsx +++ b/packages/app/src/Element/Tabs.tsx @@ -31,7 +31,7 @@ export const TabElement = ({ t, tab, setTab }: TabElementProps) => { const Tabs = ({ tabs, tab, setTab }: TabsProps) => { const horizontalScroll = useHorizontalScroll(); return ( -
+
{tabs.map(t => ( ))} diff --git a/packages/app/src/Element/Text.css b/packages/app/src/Element/Text.css index 8dbbbffe..238a2682 100644 --- a/packages/app/src/Element/Text.css +++ b/packages/app/src/Element/Text.css @@ -114,6 +114,9 @@ display: block; } -.gallery:not(:first-child), img:not(:first-child), video:not(:first-child), .link-preview-container:not(:first-child) { +.gallery:not(:first-child), +img:not(:first-child), +video:not(:first-child), +.link-preview-container:not(:first-child) { margin-top: 10px; -} \ No newline at end of file +} diff --git a/packages/app/src/Element/Text.tsx b/packages/app/src/Element/Text.tsx index 31fea6dc..fb31ad9b 100644 --- a/packages/app/src/Element/Text.tsx +++ b/packages/app/src/Element/Text.tsx @@ -11,6 +11,7 @@ import { ProxyImg } from "./ProxyImg"; import { SpotlightMediaModal } from "./Deck/SpotlightMedia"; import HighlightedText from "./HighlightedText"; import { useTextTransformer } from "Hooks/useTextTransformCache"; +import CodeBlock from "./CodeBlock"; export interface TextProps { id: string; @@ -247,13 +248,20 @@ export default function Text({ chunks.push(); } if (element.type === "link" || (element.type === "media" && element.mimeType?.startsWith("unknown"))) { - chunks.push( - , - ); + if (disableMedia ?? false) { + chunks.push(); + } else { + chunks.push( + , + ); + } } if (element.type === "custom_emoji") { chunks.push(); } + if (element.type === "code_block") { + chunks.push(); + } if (element.type === "text") { chunks.push(
diff --git a/packages/app/src/Element/User/FollowButton.css b/packages/app/src/Element/User/FollowButton.css deleted file mode 100644 index 66f05526..00000000 --- a/packages/app/src/Element/User/FollowButton.css +++ /dev/null @@ -1,2 +0,0 @@ -.follow-button { -} diff --git a/packages/app/src/Element/User/FollowButton.tsx b/packages/app/src/Element/User/FollowButton.tsx index 5952b7fd..89c7059a 100644 --- a/packages/app/src/Element/User/FollowButton.tsx +++ b/packages/app/src/Element/User/FollowButton.tsx @@ -1,4 +1,3 @@ -import "./FollowButton.css"; import FormattedMessage from "Element/FormattedMessage"; import { HexKey } from "@snort/system"; @@ -20,7 +19,7 @@ export default function FollowButton(props: FollowButtonProps) { const publisher = useEventPublisher(); const { follows, relays, readonly } = useLogin(s => ({ follows: s.follows, relays: s.relays, readonly: s.readonly })); const isFollowing = follows.item.includes(pubkey); - const baseClassname = `${props.className ? ` ${props.className}` : ""}follow-button`; + const baseClassname = props.className ? `${props.className} ` : ""; async function follow(pubkey: HexKey) { if (publisher) { @@ -42,9 +41,12 @@ export default function FollowButton(props: FollowButtonProps) { return ( (isFollowing ? unfollow(pubkey) : follow(pubkey))}> + onClick={e => { + e.stopPropagation(); + isFollowing ? unfollow(pubkey) : follow(pubkey); + }}> {isFollowing ? : } ); diff --git a/packages/app/src/Element/User/ProfileImage.css b/packages/app/src/Element/User/ProfileImage.css index 29d1c906..a6f28988 100644 --- a/packages/app/src/Element/User/ProfileImage.css +++ b/packages/app/src/Element/User/ProfileImage.css @@ -43,3 +43,15 @@ a.pfp { background-color: var(--gray-superdark); transform: rotate(135deg); } + +.profile-card { + width: 360px; + border-radius: 16px; + background: var(--gray-superdark); + box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.05); +} + +.profile-card > div { + color: white; + padding: 8px 12px; +} diff --git a/packages/app/src/Element/User/ProfileImage.tsx b/packages/app/src/Element/User/ProfileImage.tsx index 7fc6d6b1..1a7b97aa 100644 --- a/packages/app/src/Element/User/ProfileImage.tsx +++ b/packages/app/src/Element/User/ProfileImage.tsx @@ -1,9 +1,11 @@ import "./ProfileImage.css"; -import React, { ReactNode } from "react"; +import React, { ReactNode, useEffect, useState } from "react"; import { Link } from "react-router-dom"; import { HexKey, UserMetadata } from "@snort/system"; import { useUserProfile } from "@snort/system-react"; +import { useHover } from "@uidotdev/usehooks"; +import { ControlledMenu } from "@szhsin/react-menu"; import { profileLink } from "SnortUtils"; import Avatar from "Element/User/Avatar"; @@ -11,6 +13,9 @@ import Nip05 from "Element/User/Nip05"; import useLogin from "Hooks/useLogin"; import Icon from "Icons/Icon"; import DisplayName from "./DisplayName"; +import Text from "Element/Text"; +import FollowButton from "Element/User/FollowButton"; +import { UserWebsiteLink } from "Element/User/UserWebsiteLink"; export interface ProfileImageProps { pubkey: HexKey; @@ -27,6 +32,7 @@ export interface ProfileImageProps { imageOverlay?: ReactNode; showFollowingMark?: boolean; icons?: ReactNode; + showProfileCard?: boolean; } export default function ProfileImage({ @@ -44,11 +50,29 @@ export default function ProfileImage({ onClick, showFollowingMark = true, icons, + showProfileCard, }: ProfileImageProps) { const user = useUserProfile(profile ? "" : pubkey) ?? profile; const nip05 = defaultNip ? defaultNip : user?.nip05; const { follows } = useLogin(); const doesFollow = follows.item.includes(pubkey); + const [ref, hovering] = useHover(); + const [showProfileMenu, setShowProfileMenu] = useState(false); + const [t, setT] = useState>(); + + useEffect(() => { + if (hovering) { + const tn = setTimeout(() => { + setShowProfileMenu(true); + }, 1000); + setT(tn); + } else { + if (t) { + clearTimeout(t); + setT(undefined); + } + } + }, [hovering]); function handleClick(e: React.MouseEvent) { if (link === "") { @@ -60,7 +84,7 @@ export default function ProfileImage({ function inner() { return ( <> -
+
setShowProfileMenu(false)}> +
+
+ +
+ {/**/} + +
+
+ + +
+ + ); + } + return null; + } + if (link === "") { return ( -
- {inner()} -
+ <> +
+ {inner()} +
+ {profileCard()} + ); } else { return ( - - {inner()} - + <> + + {inner()} + + {profileCard()} + ); } } diff --git a/packages/app/src/Element/User/ProfilePreview.css b/packages/app/src/Element/User/ProfilePreview.css index 00211cc0..67f7cc3e 100644 --- a/packages/app/src/Element/User/ProfilePreview.css +++ b/packages/app/src/Element/User/ProfilePreview.css @@ -15,7 +15,3 @@ overflow: hidden; text-overflow: ellipsis; } - -.profile-preview button { - min-width: 98px; -} diff --git a/packages/app/src/Element/User/ProfilePreview.tsx b/packages/app/src/Element/User/ProfilePreview.tsx index 1fd65517..19ba98b1 100644 --- a/packages/app/src/Element/User/ProfilePreview.tsx +++ b/packages/app/src/Element/User/ProfilePreview.tsx @@ -12,6 +12,7 @@ export interface ProfilePreviewProps { options?: { about?: boolean; linkToProfile?: boolean; + profileCards?: boolean; }; profile?: UserMetadata; actions?: ReactNode; @@ -45,6 +46,7 @@ export default function ProfilePreview(props: ProfilePreviewProps) { profile={props.profile} link={options.linkToProfile ?? true ? undefined : ""} subHeader={options.about ?
{user?.about}
: undefined} + showProfileCard={options.profileCards} /> {props.actions ?? (
diff --git a/packages/app/src/Element/User/UserWebsiteLink.css b/packages/app/src/Element/User/UserWebsiteLink.css new file mode 100644 index 00000000..0f81ef93 --- /dev/null +++ b/packages/app/src/Element/User/UserWebsiteLink.css @@ -0,0 +1,13 @@ +.user-profile-link { + display: flex; + align-items: center; + gap: 8px; +} + +.user-profile-link a { + text-decoration: none; +} + +.user-profile-link a:hover { + text-decoration: underline; +} diff --git a/packages/app/src/Element/User/UserWebsiteLink.tsx b/packages/app/src/Element/User/UserWebsiteLink.tsx new file mode 100644 index 00000000..e5dbbd7a --- /dev/null +++ b/packages/app/src/Element/User/UserWebsiteLink.tsx @@ -0,0 +1,29 @@ +import "./UserWebsiteLink.css"; +import { MetadataCache, UserMetadata } from "@snort/system"; +import Icon from "Icons/Icon"; + +export function UserWebsiteLink({ user }: { user?: MetadataCache | UserMetadata }) { + const website_url = + user?.website && !user.website.startsWith("http") ? "https://" + user.website : user?.website || ""; + + function tryFormatWebsite(url: string) { + try { + const u = new URL(url); + return `${u.hostname}${u.pathname !== "/" ? u.pathname : ""}`; + } catch { + // ignore + } + return url; + } + + if (user?.website) { + return ( + + ); + } +} diff --git a/packages/app/src/Hooks/useTextTransformCache.tsx b/packages/app/src/Hooks/useTextTransformCache.tsx index 07442043..4c562658 100644 --- a/packages/app/src/Hooks/useTextTransformCache.tsx +++ b/packages/app/src/Hooks/useTextTransformCache.tsx @@ -3,11 +3,14 @@ import { ParsedFragment, transformText } from "@snort/system"; const TextCache = new Map>(); export function transformTextCached(id: string, content: string, tags: Array>) { - const cached = TextCache.get(id); - if (cached) return cached; - const newCache = transformText(content, tags); - TextCache.set(id, newCache); - return newCache; + if (content.length > 0) { + const cached = TextCache.get(id); + if (cached) return cached; + const newCache = transformText(content, tags); + TextCache.set(id, newCache); + return newCache; + } + return []; } export function useTextTransformer(id: string, content: string, tags: Array>) { diff --git a/packages/app/src/Pages/Notifications.css b/packages/app/src/Pages/Notifications.css index e4ab399a..b5bb6904 100644 --- a/packages/app/src/Pages/Notifications.css +++ b/packages/app/src/Pages/Notifications.css @@ -52,3 +52,29 @@ max-width: 100%; max-height: 300px; /* Cap images in notifications to 300px height */ } + +.summary-icon { + padding: 4px; + border-radius: 8px; + display: flex; + align-items: center; + cursor: pointer; + color: var(--gray-light) !important; +} + +.summary-icon:not(.active):hover { + background-color: var(--gray-dark); +} + +.summary-icon.active { + background: rgba(255, 255, 255, 0.1); +} + +.summary-tooltip { + display: flex; + gap: 12px; + padding: 12px 16px; + border-radius: 16px; + background: var(--gray-superdark); + box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.05); +} diff --git a/packages/app/src/Pages/Notifications.tsx b/packages/app/src/Pages/Notifications.tsx index a3784007..fbbc835e 100644 --- a/packages/app/src/Pages/Notifications.tsx +++ b/packages/app/src/Pages/Notifications.tsx @@ -1,16 +1,17 @@ import "./Notifications.css"; -import { useEffect, useMemo, useSyncExternalStore } from "react"; +import { useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react"; import { EventExt, EventKind, NostrEvent, NostrLink, NostrPrefix, TaggedNostrEvent, parseZap } from "@snort/system"; -import { unwrap } from "@snort/shared"; +import { unixNow, unwrap } from "@snort/shared"; import { useUserProfile } from "@snort/system-react"; import { useInView } from "react-intersection-observer"; import { FormattedMessage, useIntl } from "react-intl"; import { useNavigate } from "react-router-dom"; +import { Bar, BarChart, Tooltip, XAxis, YAxis } from "recharts"; import useLogin from "Hooks/useLogin"; import { markNotificationsRead } from "Login"; import { Notifications, UserCache } from "Cache"; -import { dedupe, findTag, orderDescending } from "SnortUtils"; +import { dedupe, findTag, orderAscending, orderDescending } from "SnortUtils"; import Icon from "Icons/Icon"; import ProfileImage from "Element/User/ProfileImage"; import useModeration from "Hooks/useModeration"; @@ -20,6 +21,8 @@ import { formatShort } from "Number"; import { LiveEvent } from "Element/LiveEvent"; import ProfilePreview from "Element/User/ProfilePreview"; import { getDisplayName } from "Element/User/DisplayName"; +import { Day } from "Const"; +import Tabs, { Tab } from "Element/Tabs"; function notificationContext(ev: TaggedNostrEvent) { switch (ev.kind) { @@ -93,12 +96,175 @@ export default function NotificationsPage({ onClick }: { onClick?: (link: NostrL return (
+ + {login.publicKey && [...timeGrouped.entries()].map(([k, g]) => )}
); } +interface StatSlot { + time: string; + reactions: number; + reposts: number; + quotes: number; + mentions: number; + zaps: number; +} + +const enum NotificationSummaryPeriod { + Daily, + Weekly, +} + +const enum NotificationSummaryFilter { + Reactions = 1, + Reposts = 2, + Mentions = 4, + Zaps = 8, + All = 255, +} + +function NotificationSummary({ evs }: { evs: Array }) { + const ref = useRef(null); + const [period, setPeriod] = useState(NotificationSummaryPeriod.Daily); + const [filter, setFilter] = useState(NotificationSummaryFilter.All); + + const periodTabs = [ + { + value: NotificationSummaryPeriod.Daily, + text: , + }, + { + value: NotificationSummaryPeriod.Weekly, + text: , + }, + ] as Array; + + const hasFlag = (v: number, f: NotificationSummaryFilter) => { + return (v & f) > 0; + }; + + const getWeek = (d: Date) => { + const onejan = new Date(d.getFullYear(), 0, 1); + const today = new Date(d.getFullYear(), d.getMonth(), d.getDate()); + const dayOfYear = (today.getTime() - onejan.getTime() + 86400000) / 86400000; + return Math.ceil(dayOfYear / 7); + }; + + const stats = useMemo(() => { + return orderAscending(evs) + .filter(a => (period === NotificationSummaryPeriod.Daily ? a.created_at > unixNow() - 14 * Day : true)) + .reduce( + (acc, v) => { + const date = new Date(v.created_at * 1000); + const key = + period === NotificationSummaryPeriod.Daily + ? `${date.getMonth() + 1}/${date.getDate()}` + : getWeek(date).toString(); + acc[key] ??= { + time: key, + reactions: 0, + reposts: 0, + quotes: 0, + mentions: 0, + zaps: 0, + }; + + if (v.kind === EventKind.Reaction) { + acc[key].reactions++; + } else if (v.kind === EventKind.Repost) { + acc[key].reposts++; + } else if (v.kind === EventKind.ZapReceipt) { + acc[key].zaps++; + } + if (v.kind === EventKind.TextNote) { + acc[key].mentions++; + } + + return acc; + }, + {} as Record, + ); + }, [evs, period]); + + const filterIcon = (f: NotificationSummaryFilter, icon: string, iconActiveClass?: string) => { + const active = hasFlag(filter, f); + return ( +
setFilter(v => v ^ f)}> + +
+ ); + }; + + return ( +
+
+

+ +

+
+ {filterIcon(NotificationSummaryFilter.Reactions, "heart-solid", "text-heart")} + {filterIcon(NotificationSummaryFilter.Zaps, "zap-solid", "text-zap")} + {filterIcon(NotificationSummaryFilter.Reposts, "reverse-left", "text-repost")} + {filterIcon(NotificationSummaryFilter.Mentions, "at-sign", "text-mention")} +
+
+ a.value === period))} setTab={t => setPeriod(t.value)} /> +
+ + + + {hasFlag(filter, NotificationSummaryFilter.Reactions) && ( + + )} + {hasFlag(filter, NotificationSummaryFilter.Reposts) && ( + + )} + {hasFlag(filter, NotificationSummaryFilter.Mentions) && ( + + )} + {hasFlag(filter, NotificationSummaryFilter.Zaps) && } + { + if (active && payload && payload.length) { + return ( +
+
+ + {formatShort(payload.find(a => a.name === "reactions")?.value as number)} +
+
+ + {formatShort(payload.find(a => a.name === "zaps")?.value as number)} +
+
+ + {formatShort(payload.find(a => a.name === "reposts")?.value as number)} +
+
+ + {formatShort(payload.find(a => a.name === "mentions")?.value as number)} +
+
+ ); + } + return null; + }} + /> +
+
+
+ ); +} + function NotificationGroup({ evs, onClick }: { evs: Array; onClick?: (link: NostrLink) => void }) { const { ref, inView } = useInView({ triggerOnce: true }); const { formatMessage } = useIntl(); diff --git a/packages/app/src/Pages/Profile/ProfilePage.css b/packages/app/src/Pages/Profile/ProfilePage.css index eb4e3c5e..6c0851eb 100644 --- a/packages/app/src/Pages/Profile/ProfilePage.css +++ b/packages/app/src/Pages/Profile/ProfilePage.css @@ -138,14 +138,6 @@ gap: 8px; } -.profile .website a { - text-decoration: none; -} - -.profile .website a:hover { - text-decoration: underline; -} - .profile .link svg { color: var(--highlight); } diff --git a/packages/app/src/Pages/Profile/ProfilePage.tsx b/packages/app/src/Pages/Profile/ProfilePage.tsx index 96d2da78..81b15b6e 100644 --- a/packages/app/src/Pages/Profile/ProfilePage.tsx +++ b/packages/app/src/Pages/Profile/ProfilePage.tsx @@ -51,6 +51,7 @@ import ProfileTab, { ZapsProfileTab, } from "Pages/Profile/ProfileTab"; import DisplayName from "../../Element/User/DisplayName"; +import { UserWebsiteLink } from "Element/User/UserWebsiteLink"; interface ProfilePageProps { id?: string; @@ -80,8 +81,6 @@ export default function ProfilePage({ id: propId }: ProfilePageProps) { const showBadges = login.preferences.showBadges ?? false; const showStatus = login.preferences.showStatus ?? true; - const website_url = - user?.website && !user.website.startsWith("http") ? "https://" + user.website : user?.website || ""; // feeds const { blocked } = useModeration(); const pinned = usePinnedFeed(id); @@ -167,28 +166,10 @@ export default function ProfilePage({ id: propId }: ProfilePageProps) { ); } - function tryFormatWebsite(url: string) { - try { - const u = new URL(url); - return `${u.hostname}${u.pathname !== "/" ? u.pathname : ""}`; - } catch { - // ignore - } - return url; - } - function links() { return ( <> - {user?.website && ( - - )} - + {lnurl && (
setShowLnQr(true)}> @@ -305,7 +286,7 @@ export default function ProfilePage({ id: propId }: ProfilePageProps) { setModalImage(user?.picture || "")} className="pointer" />
{renderIcons()} - {!isMe && id && } + {!isMe && id && }
); diff --git a/packages/app/src/SnortUtils/index.ts b/packages/app/src/SnortUtils/index.ts index 65062b2a..52018793 100644 --- a/packages/app/src/SnortUtils/index.ts +++ b/packages/app/src/SnortUtils/index.ts @@ -328,6 +328,10 @@ export function orderDescending(arr: Array) { return arr.sort((a, b) => (b.created_at > a.created_at ? 1 : -1)); } +export function orderAscending(arr: Array) { + return arr.sort((a, b) => (b.created_at > a.created_at ? -1 : 1)); +} + export interface Magnet { dn?: string | string[]; tr?: string | string[]; diff --git a/packages/app/src/index.css b/packages/app/src/index.css index daabc122..4b11a8a4 100644 --- a/packages/app/src/index.css +++ b/packages/app/src/index.css @@ -15,6 +15,8 @@ --live: #f83838; --heart: #ef4444; --zap: #ff710a; + --mention: #961ee1; + --repost: #1ecbe1; --gray-superlight: #eee; --bg-secondary: #2a2a2a; --gray-light: #999; @@ -112,6 +114,21 @@ code { font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace; } +a { + color: inherit; + line-height: 1.3em; + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +a.ext { + word-break: break-all; + white-space: initial; +} + #root { overflow-x: hidden; } @@ -138,6 +155,10 @@ code { border: 1px solid var(--border-color); } +.bb { + border-bottom: 1px solid var(--border-color); +} + .bg-primary { background: var(--primary-gradient); } @@ -150,6 +171,10 @@ code { padding: 12px 16px; } +.p4 { + padding: 4px; +} + .p24 { padding: 24px; } @@ -489,21 +514,6 @@ input:disabled { max-width: -moz-available; } -a { - color: inherit; - line-height: 1.3em; - text-decoration: none; -} - -a:hover { - text-decoration: underline; -} - -a.ext { - word-break: break-all; - white-space: initial; -} - div.form { display: grid; grid-auto-flow: row; @@ -620,6 +630,38 @@ div.form-col { background-color: var(--success); } +.bg-zap { + background-color: var(--zap); +} + +.bg-heart { + background-color: var(--heart); +} + +.bg-mention { + background-color: var(--mention); +} + +.bg-repost { + background-color: var(--repost); +} + +.text-zap { + color: var(--zap); +} + +.text-heart { + color: var(--heart); +} + +.text-mention { + color: var(--mention); +} + +.text-repost { + color: var(--repost); +} + .tweet { display: flex; align-items: center; @@ -665,11 +707,6 @@ div.form-col { font-weight: 600; font-size: 26px; line-height: 36px; - margin: 12px 0 0 0; -} - -.main-content .h4 { - margin-bottom: 25px; } .main-content .profile-preview { diff --git a/packages/app/src/index.tsx b/packages/app/src/index.tsx index 8b599091..417a9395 100644 --- a/packages/app/src/index.tsx +++ b/packages/app/src/index.tsx @@ -42,7 +42,7 @@ import { SubscribeRoutes } from "Pages/subscribe"; import ZapPoolPage from "Pages/ZapPool"; import DebugPage from "Pages/Debug"; import { db } from "Db"; -import { preload, RelayMetrics, UserCache, UserRelays } from "Cache"; +import { preload, RelayMetrics, SystemDb, UserCache, UserRelays } from "Cache"; import { LoginStore } from "Login"; import { SnortDeckLayout } from "Pages/DeckLayout"; import FreeNostrAddressPage from "./Pages/FreeNostrAddressPage"; @@ -77,6 +77,7 @@ export const System = new NostrSystem({ profileCache: UserCache, relayMetrics: RelayMetrics, queryOptimizer: WasmQueryOptimizer, + db: SystemDb, authHandler: async (c, r) => { const { id } = LoginStore.snapshot(); const pub = LoginStore.getPublisher(id); diff --git a/packages/app/src/lang.json b/packages/app/src/lang.json index c6ad88b5..db331317 100644 --- a/packages/app/src/lang.json +++ b/packages/app/src/lang.json @@ -42,6 +42,9 @@ "/Xf4UW": { "defaultMessage": "Send anonymous usage metrics" }, + "/clOBU": { + "defaultMessage": "Weekly" + }, "/d6vEc": { "defaultMessage": "Make your profile easier to find and share" }, @@ -704,6 +707,10 @@ "PCSt5T": { "defaultMessage": "Preferences" }, + "PJeJFc": { + "defaultMessage": "Summary", + "description": "Notifications summary" + }, "PLSbmL": { "defaultMessage": "Your mnemonic phrase" }, @@ -1508,5 +1515,8 @@ }, "zwb6LR": { "defaultMessage": "Mint: {url}" + }, + "zxvhnE": { + "defaultMessage": "Daily" } } diff --git a/packages/app/src/translations/ar_SA.json b/packages/app/src/translations/ar_SA.json index 73a7b80a..4b3951e7 100644 --- a/packages/app/src/translations/ar_SA.json +++ b/packages/app/src/translations/ar_SA.json @@ -13,6 +13,7 @@ "/PCavi": "علنية", "/RD0e2": "يستخدم نوستر تقنية التوقيع الرقمي لنشر المنشورات دون أي تلاعب ويمكن إرسالها بأمان إلى العديد من الموصلات لتكرار تخزينها وضمان استمرارية المحتوى الخاص بك.", "/Xf4UW": "Send anonymous usage metrics", + "/clOBU": "Weekly", "/d6vEc": "اجعل ملفك الشخصي أسهل في العثور عليه ومشاركته", "/n5KSF": "{n} مللي ثانية", "00LcfG": "Load more", @@ -231,6 +232,7 @@ "P7FD0F": "مطابق لاعدادات جهازك", "P7nJT9": "الإجمالي اليوم (بالتوقيت العالمي ): {amount} ساتوشي", "PCSt5T": "التفضيلات", + "PJeJFc": "Summary", "PLSbmL": "عبارة الاسترداد الخاصة بك", "PaN7t3": "Preview on {site}", "PamNxw": "عنوان الملف غير معروف: {name}", @@ -493,5 +495,6 @@ "zjJZBd": "انت جاهز!", "zonsdq": "فشل تحميل خدمة LNURL", "zvCDao": "تظهر تلقائيا أحدث الملاحظات", - "zwb6LR": "Mint: {url}" + "zwb6LR": "Mint: {url}", + "zxvhnE": "Daily" } diff --git a/packages/app/src/translations/az_AZ.json b/packages/app/src/translations/az_AZ.json index 8a659c3b..f38205cf 100644 --- a/packages/app/src/translations/az_AZ.json +++ b/packages/app/src/translations/az_AZ.json @@ -13,6 +13,7 @@ "/PCavi": "İctimai", "/RD0e2": "Nostr, məzmununuzun lazımsız saxlanmasını təmin etmək üçün bir çox relelərə təhlükəsiz şəkildə təkrarlana bilən saxta qeydləri təmin etmək üçün rəqəmsal imza texnologiyasından istifadə edir.", "/Xf4UW": "Send anonymous usage metrics", + "/clOBU": "Weekly", "/d6vEc": "Profilinizi tapmağı və paylaşmağı asanlaşdırın", "/n5KSF": "{n} ms", "00LcfG": "Daha çox", @@ -231,6 +232,7 @@ "P7FD0F": "System (Default)", "P7nJT9": "Total today (UTC): {amount} sats", "PCSt5T": "Preferences", + "PJeJFc": "Summary", "PLSbmL": "Your mnemonic phrase", "PaN7t3": "Preview on {site}", "PamNxw": "Unknown file header: {name}", @@ -493,5 +495,6 @@ "zjJZBd": "Hazırsan!", "zonsdq": "LNURL xidmətini yükləmək alınmadı", "zvCDao": "Ən son qeydləri avtomatik göstərin", - "zwb6LR": "Mint: {url}" + "zwb6LR": "Mint: {url}", + "zxvhnE": "Daily" } diff --git a/packages/app/src/translations/de_DE.json b/packages/app/src/translations/de_DE.json index 5d04177d..a876fafa 100644 --- a/packages/app/src/translations/de_DE.json +++ b/packages/app/src/translations/de_DE.json @@ -13,6 +13,7 @@ "/PCavi": "Öffentlich", "/RD0e2": "Nostr nutzt digitale Signaturen, um manipulationssichere Notes zu erstellen, welche sicher auf viele Relais repliziert werden können, um eine redundante Speicherung deiner Inhalte zu bieten.", "/Xf4UW": "Anonyme Nutzungsmetriken senden", + "/clOBU": "Weekly", "/d6vEc": "Mach dein Profil leichter zu finden und zu teilen", "/n5KSF": "{n} ms", "00LcfG": "Mehr laden", @@ -231,6 +232,7 @@ "P7FD0F": "System (Standard)", "P7nJT9": "Gesamt heute (UTC): {amount} sats", "PCSt5T": "Einstellungen", + "PJeJFc": "Summary", "PLSbmL": "Ihre mnemonische Passphrase", "PaN7t3": "Vorschau auf {site}", "PamNxw": "Unbekannter Datei-Header: {name}", @@ -493,5 +495,6 @@ "zjJZBd": "Du bist bereit!", "zonsdq": "Fehler beim Laden des LNURL-Dienstes", "zvCDao": "Neueste Notes automatisch anzeigen", - "zwb6LR": "Mint: {url}" + "zwb6LR": "Mint: {url}", + "zxvhnE": "Daily" } diff --git a/packages/app/src/translations/en.json b/packages/app/src/translations/en.json index bfb58612..70111264 100644 --- a/packages/app/src/translations/en.json +++ b/packages/app/src/translations/en.json @@ -13,6 +13,7 @@ "/PCavi": "Public", "/RD0e2": "Nostr uses digital signature technology to provide tamper proof notes which can safely be replicated to many relays to provide redundant storage of your content.", "/Xf4UW": "Send anonymous usage metrics", + "/clOBU": "Weekly", "/d6vEc": "Make your profile easier to find and share", "/n5KSF": "{n} ms", "00LcfG": "Load more", @@ -231,6 +232,7 @@ "P7FD0F": "System (Default)", "P7nJT9": "Total today (UTC): {amount} sats", "PCSt5T": "Preferences", + "PJeJFc": "Summary", "PLSbmL": "Your mnemonic phrase", "PaN7t3": "Preview on {site}", "PamNxw": "Unknown file header: {name}", @@ -493,5 +495,6 @@ "zjJZBd": "You're ready!", "zonsdq": "Failed to load LNURL service", "zvCDao": "Automatically show latest notes", - "zwb6LR": "Mint: {url}" + "zwb6LR": "Mint: {url}", + "zxvhnE": "Daily" } diff --git a/packages/app/src/translations/es_ES.json b/packages/app/src/translations/es_ES.json index 21c921b3..d442d74b 100644 --- a/packages/app/src/translations/es_ES.json +++ b/packages/app/src/translations/es_ES.json @@ -13,6 +13,7 @@ "/PCavi": "Público", "/RD0e2": "Nostr utiliza firmas digitales para proveer de notas inmutables que pueden ser replicadas a muchos relays para que tu contenido esté distribuido redundantemente.", "/Xf4UW": "Send anonymous usage metrics", + "/clOBU": "Weekly", "/d6vEc": "Haz tu perfil más fácil de encontrar y compartir", "/n5KSF": "{n} ms", "00LcfG": "Load more", @@ -231,6 +232,7 @@ "P7FD0F": "Sistema (por defecto)", "P7nJT9": "Total hoy (UTC): {amount} sáb", "PCSt5T": "Preferencias", + "PJeJFc": "Summary", "PLSbmL": "Frase mnemotécnica", "PaN7t3": "Preview on {site}", "PamNxw": "Encabezado de archivo desconocido: {name}", @@ -493,5 +495,6 @@ "zjJZBd": "Estás listo!", "zonsdq": "Error al contactar con el servicio LNURL", "zvCDao": "Mostrar notas nuevas automáticamente", - "zwb6LR": "Mint: {url}" + "zwb6LR": "Mint: {url}", + "zxvhnE": "Daily" } diff --git a/packages/app/src/translations/fa_IR.json b/packages/app/src/translations/fa_IR.json index 38bf123a..fa9d16e8 100644 --- a/packages/app/src/translations/fa_IR.json +++ b/packages/app/src/translations/fa_IR.json @@ -13,6 +13,7 @@ "/PCavi": "عمومی", "/RD0e2": "ناستر از تکنولوژی امضای دیجیتال برای فراهم نمودن یادداشت های غیرقابل دستکاری استفاده می کند که می تواند به طور امن در رله های زیادی تکرار شود تا انبار اضافی برای محتوایتان تامین کند.", "/Xf4UW": "Send anonymous usage metrics", + "/clOBU": "Weekly", "/d6vEc": "یافتن و اشتراک گذاری نمایه خود را آسان تر کنید", "/n5KSF": "{n} میلی ثانیه", "00LcfG": "بارگیری بیشتر", @@ -231,6 +232,7 @@ "P7FD0F": "سیستم (پیش فرض)", "P7nJT9": "جمع امروز (UTC): {amount} ساتوشی", "PCSt5T": "ترجیحات", + "PJeJFc": "Summary", "PLSbmL": "عبارت بازیابی یادسپاری شما", "PaN7t3": "Preview on {site}", "PamNxw": "سرفایل ناشناس: {name}", @@ -493,5 +495,6 @@ "zjJZBd": "شما آماده هستید!", "zonsdq": "خدمات LNURL بارگیری نشد", "zvCDao": "به طور خودکار یادداشت های اخیر را نشان بده", - "zwb6LR": "Mint: {url}" + "zwb6LR": "Mint: {url}", + "zxvhnE": "Daily" } diff --git a/packages/app/src/translations/fi_FI.json b/packages/app/src/translations/fi_FI.json index 906f9bfd..74e5606f 100644 --- a/packages/app/src/translations/fi_FI.json +++ b/packages/app/src/translations/fi_FI.json @@ -13,6 +13,7 @@ "/PCavi": "Julkinen", "/RD0e2": "Nostr käyttää digitaalista allekirjoitusteknologiaa tarjotakseen väärentämättömiä viestejä, joita voidaan turvallisesti replikoida monille välittäjille tarjoten näin varastointia sisällöllesi.", "/Xf4UW": "Lähetä nimettömiä käyttötietoja", + "/clOBU": "Weekly", "/d6vEc": "Tee profiilistasi helpompi löytää ja jakaa", "/n5KSF": "{n} ms", "00LcfG": "Lataa lisää", @@ -231,6 +232,7 @@ "P7FD0F": "Järjestelmä (oletus)", "P7nJT9": "Tänään yhteensä (UTC): {amount} satsia", "PCSt5T": "Asetukset", + "PJeJFc": "Summary", "PLSbmL": "Sinun mnemonic-lauseesi", "PaN7t3": "Preview on {site}", "PamNxw": "Tuntematon tiedostotunniste: {name}", @@ -493,5 +495,6 @@ "zjJZBd": "Olet valmis!", "zonsdq": "Epäonnistunut LNURL-palvelun lataus", "zvCDao": "Näytä uusimmat viestit automaattisesti", - "zwb6LR": "Mint: {url}" + "zwb6LR": "Mint: {url}", + "zxvhnE": "Daily" } diff --git a/packages/app/src/translations/fr_FR.json b/packages/app/src/translations/fr_FR.json index 428d3c95..48ce774c 100644 --- a/packages/app/src/translations/fr_FR.json +++ b/packages/app/src/translations/fr_FR.json @@ -13,6 +13,7 @@ "/PCavi": "Publique", "/RD0e2": "Nostr utilise la technologie de signature numérique pour fournir des notes inviolables qui peuvent être répliquées en toute sécurité sur de nombreux relais pour fournir un stockage redondant de votre contenu.", "/Xf4UW": "Send anonymous usage metrics", + "/clOBU": "Weekly", "/d6vEc": "Rendez votre profil plus facile à trouver et à partager", "/n5KSF": "{n} ms", "00LcfG": "Charger plus", @@ -231,6 +232,7 @@ "P7FD0F": "Système (Défaut)", "P7nJT9": "Total aujourd'hui (UTC) : {amount} sats", "PCSt5T": "Préférences", + "PJeJFc": "Summary", "PLSbmL": "Votre phrase mnémonique", "PaN7t3": "Preview on {site}", "PamNxw": "En-tête du fichier inconnu : {name}", @@ -493,5 +495,6 @@ "zjJZBd": "Tu es prêt!", "zonsdq": "Échec du chargement du service LNURL", "zvCDao": "Afficher automatiquement les dernières notes", - "zwb6LR": "Mint: {url}" + "zwb6LR": "Mint: {url}", + "zxvhnE": "Daily" } diff --git a/packages/app/src/translations/hr_HR.json b/packages/app/src/translations/hr_HR.json index 2758ff47..e0e8c0dd 100644 --- a/packages/app/src/translations/hr_HR.json +++ b/packages/app/src/translations/hr_HR.json @@ -13,6 +13,7 @@ "/PCavi": "Javno", "/RD0e2": "Nostr koristi tehnologiju digitalnog potpisa kako bi pružio bilješke o zaštiti od neovlaštenog mijenjanja koje se mogu sigurno replicirati na mnoge releje kako bi se osigurala nepotrebna pohrana vašeg sadržaja.", "/Xf4UW": "Send anonymous usage metrics", + "/clOBU": "Weekly", "/d6vEc": "Olakšajte pronalazak i dijeljenje svog profila", "/n5KSF": "{n} mikrosekundi", "00LcfG": "Load more", @@ -231,6 +232,7 @@ "P7FD0F": "Sustav (zadano)", "P7nJT9": "Ukupno danas (UTC): {amount} sati", "PCSt5T": "Postavke", + "PJeJFc": "Summary", "PLSbmL": "Vaša mnemotehnička fraza", "PaN7t3": "Preview on {site}", "PamNxw": "Nepoznati header file-a: {name}", @@ -493,5 +495,6 @@ "zjJZBd": "Spremni ste!", "zonsdq": "Neuspješno učitavanje LNURL usluge", "zvCDao": "Automatski prikaži najnovije bilješke", - "zwb6LR": "Mint: {url}" + "zwb6LR": "Mint: {url}", + "zxvhnE": "Daily" } diff --git a/packages/app/src/translations/hu_HU.json b/packages/app/src/translations/hu_HU.json index c85f90cd..fb3281c6 100644 --- a/packages/app/src/translations/hu_HU.json +++ b/packages/app/src/translations/hu_HU.json @@ -13,6 +13,7 @@ "/PCavi": "Nyilvános", "/RD0e2": "A Nostr digitális aláírásokat használ, amivel megmásíthatatlan bejegyzéseket lehet létrehozni. Ezeket bárhány másolatban a különböző csomópontokra szétszórhatóak, ezzel biztosítva a tartalom redundanciáját.", "/Xf4UW": "Anonimizált használati adatok küldése", + "/clOBU": "Weekly", "/d6vEc": "Legyen a fiókod könnyebben megtalálható és megosztható", "/n5KSF": "{n} ms", "00LcfG": "Továbbiak betöltése", @@ -50,7 +51,7 @@ "47FYwb": "Törlés", "4IPzdn": "Elsődleges Fejlesztők", "4L2vUY": "A te új NIP-05 azonosítód:", - "4MBtMa": "Name must be between 1 and 32 characters", + "4MBtMa": "A névnek 1 és 32 karakter között kell lennie", "4OB335": "Nem tetszik", "4Vmpt4": "A Nostr Plebs-ék az egyik legelső megfelelő feltételekkel és árakkal NIP-05 azonosítást biztosító szolgáltató", "4Z3t5i": "Az imgproxy használata a képek tömörítéséhez", @@ -67,13 +68,13 @@ "6/hB3S": "Visszajátszás Megtekintése", "65BmHb": "Nem sikerült a proxyképet a(z) {host} webhelyről betölteni. Kattintson ide a közvetlen betöltéshez", "6OSOXl": "Ok: {reason}", - "6TfgXX": "{site} is an open source project built by passionate people in their free time", + "6TfgXX": "{site} egy nyílt forráskódú projekt, amit szenvedélyes emberek szabadidejükben építettek", "6Yfvvp": "Szerezz egy azonosítót", "6bgpn+": "Nem minden kliens támogatja ezt, ezért előfordulhat, hogy továbbra is a zap-eket úgy kapja, mintha a zap felosztás nem lett volna konfigurálva", "6ewQqw": "Lájkok ({n})", "6uMqL1": "Fizetetlen", "7+Domh": "Bejegyzések", - "7/h1jn": "After submitting the pin there may be a slight delay as we encrypt the key.", + "7/h1jn": "A PIN elküldése után lehet egy kis késedelem, amíg a kulcsot titkosítjuk.", "7BX/yC": "Fiók Váltó", "7hp70g": "NIP-05", "8/vBbP": "Megosztva ({n})", @@ -108,7 +109,7 @@ "BOUMjw": "Nem találtunk {twitterUsername} nevű Nostr felhasználót", "BWpuKl": "Frissítés", "BcGMo+": "A bejegyzések szöveget tartalmaznak és a legnépszerűbb felhasználási módja, hogy ”Twitter féle” üzeneteket tároljanak benne.", - "BjNwZW": "Nostr address (nip05)", + "BjNwZW": "Nostr cím (nip05)", "C1LjMx": "Lightning adomány", "C5xzTC": "Prémium", "C81/uG": "Kijelentkezés", @@ -116,7 +117,7 @@ "CHTbO3": "A számla betöltése nem sikerült", "CVWeJ6": "Felkapott Emberek", "CmZ9ls": "{n} Némított", - "CoVXRS": "Alternatively, you may choose to store your private key without a PIN by selecting 'Cancel.'", + "CoVXRS": "Alternatívaként a 'Mégse' kiválasztásával választhatja azt is, hogy a privát kulcsát PIN nélkül tárolja.", "CsCUYo": "{n} sats", "Cu/K85": "Fordítás erről {lang}", "D+KzKd": "Betöltéskor automatikusan Zap-eljen minden bejegyzést", @@ -134,7 +135,7 @@ "EWyQH5": "Globális", "Ebl/B2": "Fordítás erre {lang}", "EcZF24": "Egyedi Csomópontok", - "EcfIwB": "Username is available", + "EcfIwB": "A felhasználó név szabad", "EcglP9": "Kulcs", "EjFyoR": "On-chain adomány cím", "EnCOBJ": "Vásárlás", @@ -205,11 +206,11 @@ "MP54GY": "Pénztárca jelszava", "MRp6Ly": "Twitter felhasználónév", "MWTx65": "Alapértelmezett oldal", - "MiMipu": "Set as primary Nostr address (nip05)", + "MiMipu": "Állítsa be elsődleges Nostr címnek (nip05)", "Mrpkot": "Fizess az előfizetésért", "MuVeKe": "Nostr cím vásárlása", "MzRYWH": "{item} megveszem", - "Mzizei": "Iris.to account", + "Mzizei": "Iris.to fiók", "N2IrpM": "Jóváhagy", "NAidKb": "Értesítések", "NAuFNH": "Már van ilyen típusú előfizetésed, kérjük, újítsd meg, vagy fizess", @@ -222,17 +223,18 @@ "OEW7yJ": "Zap-ek", "OKhRC6": "Megosztás", "OLEm6z": "Ismeretlen bejelentkezési hiba", - "OQSOJF": "Get a free nostr address", + "OQSOJF": "Szerezz egy Ingyenes Nostr címet", "OQXnew": "Az előfizetésed még aktív, így nem tudod megújítani", "ORGv1Q": "Létrehozva", - "Oq/kVn": "Name-squatting and impersonation is not allowed. {site} and our partners reserve the right to terminate your handle (not your account - nobody can take that away) for violating this rule.", - "P/xrLk": "Secure your private key with a PIN, ensuring enhanced protection on {site}. You'll be prompted to enter this PIN each time you access the site.", + "Oq/kVn": "A nevspekuláció és az engedély nélküli megszemélyesítés nem engedélyezett. A {site} és partnereink fenntartják a jogot ezen szabály megsértése esetén a választott azonosítód (nem pedig a fiókod - azt senki sem veheti el) megszüntetésére.", + "P/xrLk": "Tegyed biztonságosabbá a privát kulcsodat egy PIN-kóddal, így a(z) {site}-on fokozott védelmet biztosítva. Minden alkalommal, amikor a webhelyet megnyitod, kérni fogja, hogy add meg ezt a PIN-kódot.", "P61BTu": "JSON eset", "P7FD0F": "Rendszer (Alapértelmezett)", "P7nJT9": "Összesen ma (UTC): {amount} sat", "PCSt5T": "Preferenciák", + "PJeJFc": "Summary", "PLSbmL": "Fiók helyreállító (mnemonikus) szavaid", - "PaN7t3": "Preview on {site}", + "PaN7t3": "Előnézet a(z) {site}-n", "PamNxw": "Ismeretlen fejléc: {name}", "Pe0ogR": "Téma", "PrsIg7": "A reakciók minden oldalon megjelennek, ha letiltod őket nem jelennek meg", @@ -244,7 +246,7 @@ "R/6nsx": "Előfizetés", "R81upa": "Általad követett személyek", "RDZVQL": "Ellenőrzés", - "RSr2uB": "Username must only contain lowercase letters and numbers", + "RSr2uB": "A felhasználónév csak kisbetűket és számokat tartalmazhat", "RahCRH": "Lejárt", "RfhLwC": "Írta: {author}", "RhDAoS": "Biztos hogy törölni akarod a {id}", @@ -252,7 +254,7 @@ "RoOyAh": "Csomópontok", "Rs4kCE": "Könyvjelző", "RwFaYs": "Rendezés", - "SLZGPn": "Enter a pin to encrypt your private key, you must enter this pin every time you open {site}.", + "SLZGPn": "A privát kulcs titkosításához adjon meg egy PIN-kódot. Ezt a PIN-kódot minden alkalommal meg kell adnod, amikor a(z) {site}-ot megnyitod.", "SMO+on": "Sat küldése {name}", "SOqbe9": "Lightning cím frissítése", "SP0+yi": "Előfizetés vásárlása", @@ -269,12 +271,12 @@ "UT7Nkj": "Új Beszélgetés", "UUPFlt": "Ahhoz hogy a bejegyzés tartalma megjelenjen, a felhasználóknak a tartalomra vonatkozó figyelmeztetést el kell fogadniuk.", "Up5U7K": "Tiltás", - "UrKTqQ": "You have an active iris.to account", + "UrKTqQ": "Van aktív iris.to fiókod", "VBadwB": "Hmm, nem található kulcskezelő bővítmény. próbáld meg az oldalt újratölteni.", "VN0+Fz": "Egyenleg: {amount} sats", "VOjC1i": "Válaszd ki mely szolgáltatóhoz legyenek a fájlok feltöltve", "VR5eHw": "Publikus kulcs (npub/nprofile)", - "VcwrfF": "Yes please", + "VcwrfF": "Igen, kérem", "VlJkSk": "{n} némított", "VnXp8Z": "Avatar", "VvaJst": "Tárcák megtekintése", @@ -299,7 +301,7 @@ "ZKORll": "Aktiválás", "ZLmyG9": "Közreműködők", "ZS+jRE": "Zap felosztások küldése ide", - "Zff6lu": "Username iris.to/{name} is reserved for you!", + "Zff6lu": "Az iris.to/{name} számodra fenntartva van!", "Zr5TMx": "Profil Beállítása", "a5UPxh": "Támogasd a fejlesztőket és a platform szolgáltatókat akik NIP-05 azonosító szolgáltatásokat biztosítanak", "a7TDNm": "A bejegyzések a globális és a bejegyzések fülek alatt valós időben jelennek meg", @@ -312,7 +314,7 @@ "bfvyfs": "Névtelen", "brAXSu": "Válassz felhasználónevet", "bxv59V": "Csak most", - "c+JYNI": "No thanks", + "c+JYNI": "Nem, köszönöm", "c+oiJe": "Bővítmény Telepítése", "c35bj2": "Ha kérdése van a NIP-05 azonosító rendelésével kapcsolatban, kérjük, írjon üzenetet {link}", "c3g2hL": "Újraküldés", @@ -327,7 +329,7 @@ "d6CyG5": "Előzmények", "d7d0/x": "LN cím", "dOQCL8": "Megjelenítendő név", - "deEeEI": "Register", + "deEeEI": "Regisztráció", "e61Jf3": "Hamarosan", "e7VmYP": "A privát kulcs feloldásához írd be a PIN-kódot", "e7qqly": "Mind olvasottnak jelölni", @@ -336,7 +338,7 @@ "eSzf2G": "Egyetlen {nIn} sats zap a zap-medencéhez {nOut} sats-ot foglal le.", "eXT2QQ": "Csoportbeszélgetés", "fBI91o": "Zap", - "fBlba3": "Thanks for using {site}, please consider donating if you can.", + "fBlba3": "Köszönjük, hogy a(z) {site} használod, ha teheted fontold meg az adományozást.", "fOksnD": "Nem szavazhatsz, mert az LNURL szolgáltatód a zap-eket nem támogatja", "fWZYP5": "Kiemelt", "filwqD": "Olvasás", @@ -376,9 +378,9 @@ "jzgQ2z": "{n} Reakció", "k2veDA": "Írás", "k7sKNy": "A mi saját NIP-05 azonosítási szolgáltatásunk, amelynek a használatával ennek az oldalnak a fejlesztését segítheted és ezzel egy speciális kitüntetést is szerezhetsz!", - "kEZUR8": "Register an Iris username", + "kEZUR8": "Regisztráljon egy Iris felhasználónevet", "kJYo0u": "{n,plural,one {}=0{{name} megosztotta} other{{name} és {n} mások is megosztották}}", - "kTLGM2": "{site} is designed to have a similar experience to Twitter.", + "kTLGM2": "{site} úgy lett tervezve, hogy hasonló élményt nyújtson mint a Twitter.", "kaaf1E": "most", "kuPHYE": "{n,plural,one {}=0{{name} lájkolta} other{{name} és {n} mások is lájkolták}}", "l+ikU1": "Minden a {plan}", @@ -387,7 +389,7 @@ "lD3+8a": "Fizetem", "lPWASz": "Snort nostr cím", "lTbT3s": "Pénztárca jelszava", - "lVKH7C": "What is {site} and how does it work?", + "lVKH7C": "Mi a(z) {site} és hogyan működik?", "lgg1KN": "Felhasználói felület", "ll3xBp": "Képmegosztó szolgáltató", "lnaT9F": "Követek {n}", @@ -406,7 +408,7 @@ "nN9XTz": "Oszd meg a gondolataidat {link}", "nOaArs": "Profil Beállítása", "nWQFic": "Megújítás", - "ncbgUU": "{site} is a Nostr UI, nostr is a decentralised protocol for saving and distributing \"notes\".", + "ncbgUU": "a(z) {site} a Nostr protokollnak egyik felülete. a Nostr pedig a ”bejegyzésekˇ tárolására és megosztására létrehozott decentralizált protokoll.", "nn1qb3": "Adományait nagyra értékeljük", "nwZXeh": "{n} tiltott", "o6Uy3d": "Csak a titkos privát kulccsal lehetséges bármely közzététel (események aláírása), minden más csak olvasható módban kerül naplózásra.", @@ -440,7 +442,7 @@ "rmdsT4": "{n} napok", "rrfdTe": "Ez a technológia ugyanaz, mint amivel a tökéletes biztonságát a Bitcoin is sikeresen bizonyította.", "rudscU": "Hiba a követők betöltésénél, kérlek próbáld később", - "rx1i0i": "Short link", + "rx1i0i": "Rövid link", "sKDn4e": "Jelvények megjelenítése", "sUNhQE": "felhasználó", "sZQzjQ": "Nem sikerült a zap felosztása: {input}", @@ -484,7 +486,7 @@ "y1Z3or": "Nyelv", "yCLnBC": "LNURL vagy Lightning cím", "yCmnnm": "Globális betöltése innen", - "yNBPJp": "Help fund the development of {site}", + "yNBPJp": "Segítsen finanszírozni a(z) {site} fejlesztését", "zCb8fX": "Súly", "zFegDD": "Kapcsolat", "zINlao": "Tulajdonos", @@ -493,5 +495,6 @@ "zjJZBd": "Készen vagy!", "zonsdq": "Az LNURL szolgáltatás betöltése nem sikerült", "zvCDao": "Automatikusan a legfrissebb bejegyzéseket mutassa", - "zwb6LR": "Pénzverde: {url}" + "zwb6LR": "Pénzverde: {url}", + "zxvhnE": "Daily" } diff --git a/packages/app/src/translations/id_ID.json b/packages/app/src/translations/id_ID.json index 7dba2901..916a7fa6 100644 --- a/packages/app/src/translations/id_ID.json +++ b/packages/app/src/translations/id_ID.json @@ -13,6 +13,7 @@ "/PCavi": "Publik", "/RD0e2": "Nostr menggunakan teknologi tanda tangan digital untuk menyediakan catatan anti pengerusakan yang dapat dengan aman direplikasi ke banyak relai untuk menyediakan penyimpanan konten Anda yang berulang.", "/Xf4UW": "Send anonymous usage metrics", + "/clOBU": "Weekly", "/d6vEc": "Jadikan profil Anda lebih mudah untuk ditemukan dan dibagikan", "/n5KSF": "{n} ms", "00LcfG": "Load more", @@ -231,6 +232,7 @@ "P7FD0F": "Sistem (Bawaan)", "P7nJT9": "Total hari ini (UTC): {amount} sat", "PCSt5T": "Preferensi", + "PJeJFc": "Summary", "PLSbmL": "Your mnemonic phrase", "PaN7t3": "Preview on {site}", "PamNxw": "Unknown file header: {name}", @@ -493,5 +495,6 @@ "zjJZBd": "Anda siap!", "zonsdq": "Gagal memuat layanan LNURL", "zvCDao": "Tampilkan catatan terbaru secara otomatis", - "zwb6LR": "Mint: {url}" + "zwb6LR": "Mint: {url}", + "zxvhnE": "Daily" } diff --git a/packages/app/src/translations/it_IT.json b/packages/app/src/translations/it_IT.json index 8dc3cbf0..28915095 100644 --- a/packages/app/src/translations/it_IT.json +++ b/packages/app/src/translations/it_IT.json @@ -13,6 +13,7 @@ "/PCavi": "Pubblica", "/RD0e2": "Nostr utilizza la tecnologia della firma digitale per fornire note a prova di manomissione che possono essere replicate in modo sicuro su molti relè per fornire l'archiviazione ridondante dei tuoi contenuti.", "/Xf4UW": "Send anonymous usage metrics", + "/clOBU": "Weekly", "/d6vEc": "Rendi il tuo profilo più facile da trovare e condividere", "/n5KSF": "{n} ms", "00LcfG": "Load more", @@ -231,6 +232,7 @@ "P7FD0F": "Sistema (Predefinito)", "P7nJT9": "Totale oggi (UTC): {amount} sat", "PCSt5T": "Preferenze", + "PJeJFc": "Summary", "PLSbmL": "La tua frase mnemonica", "PaN7t3": "Preview on {site}", "PamNxw": "Intestazione del file sconosciuta: {name}", @@ -493,5 +495,6 @@ "zjJZBd": "Tutto fatto!", "zonsdq": "Caricamento del servizio LNURL fallito", "zvCDao": "Visualizza automaticamente le ultime note", - "zwb6LR": "Mint: {url}" + "zwb6LR": "Mint: {url}", + "zxvhnE": "Daily" } diff --git a/packages/app/src/translations/ja_JP.json b/packages/app/src/translations/ja_JP.json index d7f34ac4..56560dd0 100644 --- a/packages/app/src/translations/ja_JP.json +++ b/packages/app/src/translations/ja_JP.json @@ -13,6 +13,7 @@ "/PCavi": "公開", "/RD0e2": "Nostrはデジタル署名技術を使って投稿の改竄防止を図り、多数のリレーに安全に複製してコンテンツの冗長ストレージを提供しています。", "/Xf4UW": "匿名で利用状況を送信します", + "/clOBU": "Weekly", "/d6vEc": "プロフィールを見つけやすく、共有しやすくなる", "/n5KSF": "{n}ミリ秒", "00LcfG": "さらに読み込む", @@ -231,6 +232,7 @@ "P7FD0F": "システム (デフォルト)", "P7nJT9": "本日の合計額 (UTC): {amount} sats", "PCSt5T": "ユーザー設定", + "PJeJFc": "Summary", "PLSbmL": "ニーモニックフレーズ", "PaN7t3": "Preview on {site}", "PamNxw": "不明なファイルヘッダー: {name}", @@ -493,5 +495,6 @@ "zjJZBd": "準備完了!", "zonsdq": "LNURLサービスの読み込みに失敗しました", "zvCDao": "最新の記事を自動で表示する", - "zwb6LR": "Mint: {url}" + "zwb6LR": "Mint: {url}", + "zxvhnE": "Daily" } diff --git a/packages/app/src/translations/nl_NL.json b/packages/app/src/translations/nl_NL.json index 897e353f..bacfc3c3 100644 --- a/packages/app/src/translations/nl_NL.json +++ b/packages/app/src/translations/nl_NL.json @@ -13,6 +13,7 @@ "/PCavi": "Openbaar", "/RD0e2": "Nostr maakt gebruik van digitale handtekeningentechnologie om manipulatiebeveiligde notes te realiseren. Zo kunnen de notes consistent naar veel relays tegelijk worden verzonden en wordt overbodige opslag voorkomen.", "/Xf4UW": "Send anonymous usage metrics", + "/clOBU": "Weekly", "/d6vEc": "Maak je profiel gemakkelijker om te vinden en te delen", "/n5KSF": "{n} ms", "00LcfG": "Meer laden", @@ -231,6 +232,7 @@ "P7FD0F": "Systeem (Standaard)", "P7nJT9": "Totaal vandaag (UTC): {amount} sats", "PCSt5T": "Voorkeuren", + "PJeJFc": "Summary", "PLSbmL": "Uw wachtwoord om te onthouden", "PaN7t3": "Preview on {site}", "PamNxw": "Onbekende bestandsheader: {name}", @@ -493,5 +495,6 @@ "zjJZBd": "Je bent er klaar voor!", "zonsdq": "Laden van LNURL service mislukt", "zvCDao": "Recente notities automatisch weergeven", - "zwb6LR": "Mint: {url}" + "zwb6LR": "Mint: {url}", + "zxvhnE": "Daily" } diff --git a/packages/app/src/translations/pt_BR.json b/packages/app/src/translations/pt_BR.json index c851a14f..3048c0d0 100644 --- a/packages/app/src/translations/pt_BR.json +++ b/packages/app/src/translations/pt_BR.json @@ -13,6 +13,7 @@ "/PCavi": "Público", "/RD0e2": "Nostr usa tecnologia de assinatura digital para prover notas à prova de adulteração que podem ser repostadas em diferentes relays para que haja armazenamento redundante de seu conteúdo.", "/Xf4UW": "Send anonymous usage metrics", + "/clOBU": "Weekly", "/d6vEc": "Faça seu perfil seja mais fácil de achar e compartilhar", "/n5KSF": "{n} ms", "00LcfG": "Carregar mais", @@ -231,6 +232,7 @@ "P7FD0F": "Sistema (Padrão)", "P7nJT9": "Total hoje (UTC): {amount} sats", "PCSt5T": "Preferências", + "PJeJFc": "Summary", "PLSbmL": "A sua senha mnemônica", "PaN7t3": "Preview on {site}", "PamNxw": "Cabeçalho de arquivo desconhecido: {name}", @@ -493,5 +495,6 @@ "zjJZBd": "Você está pronto!", "zonsdq": "Falha ao carregar o serviço LNURL", "zvCDao": "Mostrar automaticamente as últimas notas", - "zwb6LR": "Mint: {url}" + "zwb6LR": "Mint: {url}", + "zxvhnE": "Daily" } diff --git a/packages/app/src/translations/ru_RU.json b/packages/app/src/translations/ru_RU.json index 1f12f7f4..98ca5af6 100644 --- a/packages/app/src/translations/ru_RU.json +++ b/packages/app/src/translations/ru_RU.json @@ -13,6 +13,7 @@ "/PCavi": "Публичный", "/RD0e2": "Nostr использует технологию цифровой подписи для создания защищенных от несанкционированного доступа заметок, которые можно безопасно копировать на множество релеев, обеспечивая резервное хранение Вашего контента.", "/Xf4UW": "Отправлять показатели анонимного использования", + "/clOBU": "Weekly", "/d6vEc": "Упростить поиск и распространение вашего профиля в Nostr", "/n5KSF": "{n} мс", "00LcfG": "Загрузить больше", @@ -231,6 +232,7 @@ "P7FD0F": "Системный (по умолчанию)", "P7nJT9": "Всего сегодня (UTC): {amount} сат", "PCSt5T": "Настройки", + "PJeJFc": "Summary", "PLSbmL": "Ваша мнемоническая фраза", "PaN7t3": "Preview on {site}", "PamNxw": "Неизвестный заголовок файла: {name}", @@ -493,5 +495,6 @@ "zjJZBd": "Готово!", "zonsdq": "Не удалось загрузить службу LNURL", "zvCDao": "Автоматически показывать новые заметки", - "zwb6LR": "Mint: {url}" + "zwb6LR": "Mint: {url}", + "zxvhnE": "Daily" } diff --git a/packages/app/src/translations/sv_SE.json b/packages/app/src/translations/sv_SE.json index deae0b9d..c4366d59 100644 --- a/packages/app/src/translations/sv_SE.json +++ b/packages/app/src/translations/sv_SE.json @@ -13,6 +13,7 @@ "/PCavi": "Publik", "/RD0e2": "Nostr använder digital signatur teknik för att ge manipuleringssäkra anteckningar som säkert kan replikeras till många reläer för att ge redundant lagring av ditt innehåll.", "/Xf4UW": "Skicka anonyma användarvärden", + "/clOBU": "Veckovis", "/d6vEc": "Gör din profil enklare att hitta och dela", "/n5KSF": "{n} ms", "00LcfG": "Ladda fler", @@ -50,7 +51,7 @@ "47FYwb": "Avbryt", "4IPzdn": "Primära Utvecklare", "4L2vUY": "Din nya NIP-05 är:", - "4MBtMa": "Name must be between 1 and 32 characters", + "4MBtMa": "Namnet måste vara mellan 1 och 32 tecken", "4OB335": "Ogilla", "4Vmpt4": "Nostr Plebs är en av de första NIP-05 leverantörerna och erbjuder en bra samling domäner till rimliga priser", "4Z3t5i": "Använd imgproxy för att komprimera bilder", @@ -67,13 +68,13 @@ "6/hB3S": "Titta på repris", "65BmHb": "Det gick inte att proxybilden från {host}, klicka här för att ladda direkt", "6OSOXl": "Anledning: {reason}", - "6TfgXX": "{site} is an open source project built by passionate people in their free time", + "6TfgXX": "{site} är ett projekt med öppen källkod byggt av passionerade personer på fritiden", "6Yfvvp": "Skaffa en identifierare", "6bgpn+": "Inte alla klienter stöder detta, kan du fortfarande få några zaps som om zap delning inte konfigurerades", "6ewQqw": "Gillar ({n})", "6uMqL1": "Obetald", "7+Domh": "Anteckningar", - "7/h1jn": "After submitting the pin there may be a slight delay as we encrypt the key.", + "7/h1jn": "Efter att ha skickat in pin kan det finnas en liten fördröjning när vi krypterar nyckeln.", "7BX/yC": "Konto växlare", "7hp70g": "NIP-05", "8/vBbP": "Delningar ({n})", @@ -108,7 +109,7 @@ "BOUMjw": "Inga nostr användare hittades för {twitterUsername}", "BWpuKl": "Uppdatera", "BcGMo+": "Anteckningar håller textinnehåll, den mest populära användningen av dessa anteckningar är att lagra \"tweet like\" meddelanden.", - "BjNwZW": "Nostr address (nip05)", + "BjNwZW": "Nostr adress (nip05)", "C1LjMx": "Lightning donation", "C5xzTC": "Premium", "C81/uG": "Logga ut", @@ -116,7 +117,7 @@ "CHTbO3": "Det gick inte att ladda fakturan", "CVWeJ6": "Trendande personer", "CmZ9ls": "{n} tystad", - "CoVXRS": "Alternatively, you may choose to store your private key without a PIN by selecting 'Cancel.'", + "CoVXRS": "Alternativt kan du välja att lagra din privata nyckel utan PIN-kod genom att välja \"Avbryt\".", "CsCUYo": "{n} sats", "Cu/K85": "Översatt från {lang}", "D+KzKd": "Zappa automatiskt varje anteckning när den är laddad", @@ -134,7 +135,7 @@ "EWyQH5": "Global", "Ebl/B2": "Översätt till {lang}", "EcZF24": "Anpassade reläer", - "EcfIwB": "Username is available", + "EcfIwB": "Användarnamnet är tillgängligt", "EcglP9": "Nyckel", "EjFyoR": "Donationsadress för On-chain", "EnCOBJ": "Köpa", @@ -205,11 +206,11 @@ "MP54GY": "Plånbokens lösenord", "MRp6Ly": "Twitter-användarnamn", "MWTx65": "Förvald Sida", - "MiMipu": "Set as primary Nostr address (nip05)", + "MiMipu": "Ange som primär Nostr adress (nip05)", "Mrpkot": "Betala för prenumeration", "MuVeKe": "Köp nostr adress", "MzRYWH": "Köper {item}", - "Mzizei": "Iris.to account", + "Mzizei": "Iris.to konto", "N2IrpM": "Bekräfta", "NAidKb": "Notifikationer", "NAuFNH": "Du har redan en prenumeration av den här typen, vänligen förnya eller betala", @@ -222,17 +223,18 @@ "OEW7yJ": "Zaps", "OKhRC6": "Dela", "OLEm6z": "Okänt inloggningsfel", - "OQSOJF": "Get a free nostr address", + "OQSOJF": "Få en gratis nostr adress", "OQXnew": "Din prenumeration är fortfarande aktiv, du kan inte förnya ännu", "ORGv1Q": "Skapad", - "Oq/kVn": "Name-squatting and impersonation is not allowed. {site} and our partners reserve the right to terminate your handle (not your account - nobody can take that away) for violating this rule.", - "P/xrLk": "Secure your private key with a PIN, ensuring enhanced protection on {site}. You'll be prompted to enter this PIN each time you access the site.", + "Oq/kVn": "Namnslåss och personifiering är inte tillåtet. {site} och våra partners förbehåller sig rätten att avsluta ditt handtag (inte ditt konto - ingen kan ta bort det) för att ha brutit mot denna regel.", + "P/xrLk": "Säkra din privata nyckel med en PIN-kod som garanterar ett förbättrat skydd på {site}. Du uppmanas att ange denna PIN-kod varje gång du använder webbplatsen.", "P61BTu": "Kopiera händelse JSON", "P7FD0F": "System (standard)", "P7nJT9": "Totalt idag (UTC): {amount} sats", "PCSt5T": "Inställningar", + "PJeJFc": "Summary", "PLSbmL": "Din mnemoniska lösenfras", - "PaN7t3": "Preview on {site}", + "PaN7t3": "Förhandsgranska på {site}", "PamNxw": "Okänd filrubrik: {name}", "Pe0ogR": "Tema", "PrsIg7": "Reaktioner kommer att visas på varje sida om inga reaktioner inaktiveras", @@ -244,7 +246,7 @@ "R/6nsx": "Prenumeration", "R81upa": "Personer du följer", "RDZVQL": "Kontrollera", - "RSr2uB": "Username must only contain lowercase letters and numbers", + "RSr2uB": "Användarnamnet får bara innehålla gemener och siffror", "RahCRH": "Förfallen", "RfhLwC": "Av: {author}", "RhDAoS": "Är du säker på att du vill radera {id}", @@ -252,7 +254,7 @@ "RoOyAh": "Reläer", "Rs4kCE": "Bokmärke", "RwFaYs": "Sortera", - "SLZGPn": "Enter a pin to encrypt your private key, you must enter this pin every time you open {site}.", + "SLZGPn": "Ange en pin för att kryptera din privata nyckel, du måste ange denna pin varje gång du öppnar {site}.", "SMO+on": "Skicka zap till {name}", "SOqbe9": "Uppdatera Lightning-adress", "SP0+yi": "Köp Prenumeration", @@ -269,12 +271,12 @@ "UT7Nkj": "Ny chatt", "UUPFlt": "Användare måste acceptera innehållsvarningen för att visa innehållet i din anteckning.", "Up5U7K": "Blockera", - "UrKTqQ": "You have an active iris.to account", + "UrKTqQ": "Du har ett aktivt iris.to konto", "VBadwB": "Hmm, kan inte hitta ett Key Manager tillägg.. prova att ladda om sidan.", "VN0+Fz": "Saldo: {amount} sats", "VOjC1i": "Välj vilken uppladdningstjänst du vill ladda upp bilagor till", "VR5eHw": "Publik nyckel (npub/nprofile)", - "VcwrfF": "Yes please", + "VcwrfF": "Ja tack", "VlJkSk": "{n} tystad", "VnXp8Z": "Avatar", "VvaJst": "Visa plånböcker", @@ -299,7 +301,7 @@ "ZKORll": "Aktivera nu", "ZLmyG9": "Bidragsgivare", "ZS+jRE": "Skicka zap-delning till", - "Zff6lu": "Username iris.to/{name} is reserved for you!", + "Zff6lu": "Användarnamnet iris.to/{name} är reserverat för dig!", "Zr5TMx": "Profilinställning", "a5UPxh": "Finansiera utvecklare och plattformar som tillhandahåller NIP-05 verifieringstjänster", "a7TDNm": "Anteckningar kommer att strömmas i realtid in i global och antecknings fliken", @@ -312,7 +314,7 @@ "bfvyfs": "Anon", "brAXSu": "Välj ett användarnamn", "bxv59V": "Just nu", - "c+JYNI": "No thanks", + "c+JYNI": "Nej tack", "c+oiJe": "Installera Tillägg", "c35bj2": "Om du har en förfrågan om din NIP-05 beställning, vänligen DM {link}", "c3g2hL": "Sänd igen", @@ -327,7 +329,7 @@ "d6CyG5": "Historik", "d7d0/x": "LN Adress", "dOQCL8": "Visnings namn", - "deEeEI": "Register", + "deEeEI": "Registrering", "e61Jf3": "Kommer snart", "e7VmYP": "Ange pin för att låsa upp din privata nyckel", "e7qqly": "Markera alla som lästa", @@ -336,7 +338,7 @@ "eSzf2G": "En enda zap med {nIn} sats kommer att fördela {nOut} sats till zappoolen.", "eXT2QQ": "Gruppchatt", "fBI91o": "Zap", - "fBlba3": "Thanks for using {site}, please consider donating if you can.", + "fBlba3": "Tack för att du använder {site}, vänligen överväg att donera om du kan.", "fOksnD": "Kan inte rösta eftersom LNURL-tjänsten inte stöder zaps", "fWZYP5": "Fastnålad", "filwqD": "Läs", @@ -376,9 +378,9 @@ "jzgQ2z": "{n} Reaktioner", "k2veDA": "Skriv", "k7sKNy": "Vår alldeles egna NIP-05 verifieringstjänst, hjälpa till att stödja utvecklingen av denna webbplats och få ett glänsande speciellt märke på vår webbplats!", - "kEZUR8": "Register an Iris username", + "kEZUR8": "Registrera ett användarnamn för Iris", "kJYo0u": "{n,plural,one {}=0{{name} delade} other{{name} & {n} andra delade}}", - "kTLGM2": "{site} is designed to have a similar experience to Twitter.", + "kTLGM2": "{site} är utformat för att ha en liknande upplevelse som Twitter.", "kaaf1E": "nu", "kuPHYE": "{n,plural,one {}=0{{name} gillade} other{{name} & {n} andra gillade}}", "l+ikU1": "Allting i {plan}", @@ -387,7 +389,7 @@ "lD3+8a": "Betala", "lPWASz": "Snort nostr adress", "lTbT3s": "Plånbokens lösenord", - "lVKH7C": "What is {site} and how does it work?", + "lVKH7C": "Vad är {site} och hur fungerar det?", "lgg1KN": "konto sida", "ll3xBp": "Bild proxy tjänst", "lnaT9F": "Följer {n}", @@ -406,7 +408,7 @@ "nN9XTz": "Dela dina tankar med {link}", "nOaArs": "Ställ in Profil", "nWQFic": "Förnya", - "ncbgUU": "{site} is a Nostr UI, nostr is a decentralised protocol for saving and distributing \"notes\".", + "ncbgUU": "{site} är ett Nostr UI, nostr är ett decentraliserat protokoll för att spara och distribuera \"anteckningar\".", "nn1qb3": "Era donationer är mycket uppskattade", "nwZXeh": "{n} blockerad", "o6Uy3d": "Endast den hemliga nyckeln kan användas för att publicera (signeringshändelser), allt annat loggar in dig i bara-läsa läge.", @@ -440,7 +442,7 @@ "rmdsT4": "{n} dagar", "rrfdTe": "Detta är samma teknik som används av Bitcoin och har visat sig vara extremt säker.", "rudscU": "Det gick inte att ladda följande, försök igen senare", - "rx1i0i": "Short link", + "rx1i0i": "Kort länk", "sKDn4e": "Visa emblem", "sUNhQE": "användare", "sZQzjQ": "Misslyckades att tolka zapsplit: {input}", @@ -484,7 +486,7 @@ "y1Z3or": "Språk", "yCLnBC": "LNURL or Lightning Adress", "yCmnnm": "Läs global från", - "yNBPJp": "Help fund the development of {site}", + "yNBPJp": "Hjälp till att finansiera utvecklingen av {site}", "zCb8fX": "Vikt", "zFegDD": "Kontakt", "zINlao": "Ägare", @@ -493,5 +495,6 @@ "zjJZBd": "Du är redo!", "zonsdq": "Det gick inte att ladda LNURL-tjänsten", "zvCDao": "Visa automatiskt de senaste anteckningarna", - "zwb6LR": "Mint: {url}" + "zwb6LR": "Mint: {url}", + "zxvhnE": "Daily" } diff --git a/packages/app/src/translations/sw_KE.json b/packages/app/src/translations/sw_KE.json index e9ca4e59..37954221 100644 --- a/packages/app/src/translations/sw_KE.json +++ b/packages/app/src/translations/sw_KE.json @@ -13,6 +13,7 @@ "/PCavi": "Umma", "/RD0e2": "Nostr hutumia teknolojia ya sahihi ya dijiti kutoa madokezo ya uthibitisho ambayo yanaweza kuigwa kwa usalama kwenye relay nyingi ili kutoa uhifadhi mwingi wa maudhui yako.", "/Xf4UW": "Send anonymous usage metrics", + "/clOBU": "Weekly", "/d6vEc": "Rahisisha wasifu wako kupata na kushiriki", "/n5KSF": "{n} ms", "00LcfG": "Pakia zaidi", @@ -231,6 +232,7 @@ "P7FD0F": "Mfumo (Chaguo-msingi)", "P7nJT9": "Jumla ya leo (UTC): {amount} sats", "PCSt5T": "Preferences", + "PJeJFc": "Summary", "PLSbmL": "Maneno yako ya mnemonic", "PaN7t3": "Preview on {site}", "PamNxw": "Kijajuu cha faili kisichojulikana: {name}", @@ -493,5 +495,6 @@ "zjJZBd": "Uko tayari!", "zonsdq": "Imeshindwa kupakia huduma ya LNURL", "zvCDao": "Onyesha madokezo mapya kiotomatiki", - "zwb6LR": "Mint: {url}" + "zwb6LR": "Mint: {url}", + "zxvhnE": "Daily" } diff --git a/packages/app/src/translations/ta_IN.json b/packages/app/src/translations/ta_IN.json index 62ffb269..4fd84a9b 100644 --- a/packages/app/src/translations/ta_IN.json +++ b/packages/app/src/translations/ta_IN.json @@ -13,6 +13,7 @@ "/PCavi": "பொது", "/RD0e2": "சேதப்படுத்த முடியாத குறிப்புகளை வழங்க, நாஸ்டர் டிஜிட்டல் கையொப்ப தொழில் நுட்பத்தைப் பயன் படுத்துகிறது. இதனால் பல ரிலேகளில் குறிப்புகள் பிரதியெடுக்கப் பட்டு, குறிப்பின் உள்ளடக்கம் கூடுதல் சேமிப்பு அடைகிறது.", "/Xf4UW": "Send anonymous usage metrics", + "/clOBU": "Weekly", "/d6vEc": "உங்கள் சுயவிவரத்தை கண்டறிவதையும் பகிர்வதையும் எளிதாக்குங்கள்", "/n5KSF": "{n} மில்லி வினாடிகள்", "00LcfG": "மேலும் காண்க", @@ -231,6 +232,7 @@ "P7FD0F": "கணினி (இயல்புநிலை)", "P7nJT9": "இன்றைய (UTC) மொத்தம்: {amount} சாட்கள்", "PCSt5T": "விருப்பங்கள்", + "PJeJFc": "Summary", "PLSbmL": "உங்கள் நினைவூட்டும் சொற்றொடர்", "PaN7t3": "Preview on {site}", "PamNxw": "தெரியாத கோப்புத் தலைப்பு: {name}", @@ -493,5 +495,6 @@ "zjJZBd": "நீங்கள் தயார்!", "zonsdq": "LNURL சேவையை ஏற்றுவதில் தோல்வி", "zvCDao": "சமீபத்திய குறிப்புகளைத் தானாகக் காட்டு", - "zwb6LR": "Mint: {url}" + "zwb6LR": "Mint: {url}", + "zxvhnE": "Daily" } diff --git a/packages/app/src/translations/th_TH.json b/packages/app/src/translations/th_TH.json index b07c85f7..d003689a 100644 --- a/packages/app/src/translations/th_TH.json +++ b/packages/app/src/translations/th_TH.json @@ -13,6 +13,7 @@ "/PCavi": "สาธารณะ", "/RD0e2": "Nostr ใช้เทคโนโลยีลายเซ็นดิจิทัลเพื่อแสดงบันทึกหลักฐานการปลอมแปลง ซึ่งสามารถทำซ้ำได้อย่างปลอดภัยไปยังรีเลย์จำนวนมาก เพื่อกระจายการจัดเก็บเนื้อหาที่ซ้ำซ้อนของคุณ", "/Xf4UW": "Send anonymous usage metrics", + "/clOBU": "Weekly", "/d6vEc": "ทำให้ค้นหาและแบ่งปันโปรไฟล์ได้ง่ายขึ้น", "/n5KSF": "{n} ms", "00LcfG": "Load more", @@ -231,6 +232,7 @@ "P7FD0F": "ระบบ (ค่าเริ่มต้น)", "P7nJT9": "ยอดรวมวันนี้ (UTC): {amount} sats", "PCSt5T": "การตั้งค่า", + "PJeJFc": "Summary", "PLSbmL": "Mnemonic phrase ของคุณ", "PaN7t3": "Preview on {site}", "PamNxw": "ส่วนต้นของไฟล์ที่ไม่รู้จัก: {name}", @@ -493,5 +495,6 @@ "zjJZBd": "คุณพร้อมแล้ว!", "zonsdq": "ไม่สามารถโหลดบริการ LNURL", "zvCDao": "โชว์โน้ตแบบย่ออัตโนมัติ", - "zwb6LR": "Mint: {url}" + "zwb6LR": "Mint: {url}", + "zxvhnE": "Daily" } diff --git a/packages/app/src/translations/zh_CN.json b/packages/app/src/translations/zh_CN.json index fc90d316..66a74157 100644 --- a/packages/app/src/translations/zh_CN.json +++ b/packages/app/src/translations/zh_CN.json @@ -13,6 +13,7 @@ "/PCavi": "公开", "/RD0e2": "Nostr 利用数字签名技术实现防篡改的笔记并可令其安全的复制到大量中继节点,给你的内容作为冗余存储。", "/Xf4UW": "发送匿名使用资料", + "/clOBU": "Weekly", "/d6vEc": "使你的帐号可更方便地被找到及分享", "/n5KSF": "{n} 毫秒", "00LcfG": "加载更多", @@ -231,6 +232,7 @@ "P7FD0F": "系统(默认)", "P7nJT9": "今天总计 (UTC):{amount} 聪", "PCSt5T": "选项", + "PJeJFc": "Summary", "PLSbmL": "你的助记词句", "PaN7t3": "Preview on {site}", "PamNxw": "未知文件标头:{name}", @@ -493,5 +495,6 @@ "zjJZBd": "你已准备就绪!", "zonsdq": "加载 LNURL 服务失败", "zvCDao": "自动显示最新笔记", - "zwb6LR": "铸币厂: {url}" + "zwb6LR": "铸币厂: {url}", + "zxvhnE": "Daily" } diff --git a/packages/app/src/translations/zh_TW.json b/packages/app/src/translations/zh_TW.json index 261cf57f..c3e96629 100644 --- a/packages/app/src/translations/zh_TW.json +++ b/packages/app/src/translations/zh_TW.json @@ -13,6 +13,7 @@ "/PCavi": "公開", "/RD0e2": "Nostr 利用數字簽名技術實現防篡改的筆記並可令其安全的複製到大量的中繼節點,給你的內容作為冗余存儲。", "/Xf4UW": "傳送匿名使用資料", + "/clOBU": "Weekly", "/d6vEc": "使你的帳號可更方便地被找到及分享", "/n5KSF": "{n} 毫秒", "00LcfG": "加載更多", @@ -231,6 +232,7 @@ "P7FD0F": "系統(默認)", "P7nJT9": "今天總計(UTC):{amount} 聰", "PCSt5T": "選項", + "PJeJFc": "Summary", "PLSbmL": "你的助記詞句", "PaN7t3": "Preview on {site}", "PamNxw": "未知文件標頭:{name}", @@ -493,5 +495,6 @@ "zjJZBd": "你已經準備就緒!", "zonsdq": "加載 LNURL 服務失敗", "zvCDao": "自動顯示最新筆記", - "zwb6LR": "鑄幣廠: {url}" + "zwb6LR": "鑄幣廠: {url}", + "zxvhnE": "Daily" } diff --git a/packages/app/webpack.config.js b/packages/app/webpack.config.js index aa115b0b..c20183fa 100644 --- a/packages/app/webpack.config.js +++ b/packages/app/webpack.config.js @@ -29,6 +29,7 @@ if (appTitle === "iris") { copyPatterns.push({ from: "public/iris/.well-known", to: ".well-known" }); } else { copyPatterns.push({ from: "public/manifest.json" }); + copyPatterns.push({ from: "public/snort/.well-known", to: ".well-known" }); } const config = { diff --git a/packages/system-web/package.json b/packages/system-web/package.json new file mode 100644 index 00000000..08db3588 --- /dev/null +++ b/packages/system-web/package.json @@ -0,0 +1,25 @@ +{ + "name": "@snort/system-web", + "version": "1.0.0", + "description": "Web based components @snort/system", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "repository": "https://git.v0l.io/Kieran/snort", + "author": "Kieran", + "license": "MIT", + "scripts": { + "build": "rm -rf dist && tsc" + }, + "files": [ + "src", + "dist" + ], + "dependencies": { + "@snort/shared": "^1.0.6", + "@snort/system": "^1.0.21", + "dexie": "^3.2.4" + }, + "devDependencies": { + "typescript": "^5.2.2" + } +} diff --git a/packages/system/src/cache/db.ts b/packages/system-web/src/index.ts similarity index 61% rename from packages/system/src/cache/db.ts rename to packages/system-web/src/index.ts index 108c9cbb..1f3366d2 100644 --- a/packages/system/src/cache/db.ts +++ b/packages/system-web/src/index.ts @@ -1,6 +1,5 @@ -import { DexieLike, DexieTableLike } from "@snort/shared"; -import { MetadataCache, RelayMetrics, UsersRelays } from "."; -import { NostrEvent } from "../nostr"; +import { NostrEvent, MetadataCache, RelayMetrics, UsersRelays } from "@snort/system"; +import Dexie, { Table } from "dexie"; const NAME = "snort-system"; const VERSION = 2; @@ -12,13 +11,12 @@ const STORES = { events: "++id, pubkey, created_at", }; -export class SnortSystemDb extends DexieLike { +export class SnortSystemDb extends Dexie { ready = false; - users!: DexieTableLike; - relayMetrics!: DexieTableLike; - userRelays!: DexieTableLike; - events!: DexieTableLike; - dms!: DexieTableLike; + users!: Table; + relayMetrics!: Table; + userRelays!: Table; + events!: Table; constructor() { super(NAME); diff --git a/packages/system-web/tsconfig.json b/packages/system-web/tsconfig.json new file mode 100644 index 00000000..70340f1f --- /dev/null +++ b/packages/system-web/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "baseUrl": "src", + "target": "ESNext", + "moduleResolution": "Bundler", + "esModuleInterop": true, + "noImplicitOverride": true, + "jsx": "react-jsx", + "strict": true, + "declaration": true, + "declarationMap": true, + "inlineSourceMap": true, + "outDir": "dist", + "skipLibCheck": true + }, + "include": ["src/**/*.ts"], + "files": ["src/index.ts"] +} diff --git a/packages/system/src/cache/events.ts b/packages/system/src/cache/events.ts index 59457cbe..f41ddd5b 100644 --- a/packages/system/src/cache/events.ts +++ b/packages/system/src/cache/events.ts @@ -1,10 +1,9 @@ import { NostrEvent } from "nostr"; -import { db } from "."; -import { FeedCache } from "@snort/shared"; +import { DexieTableLike, FeedCache } from "@snort/shared"; export class EventsCache extends FeedCache { - constructor() { - super("EventsCache", db.events); + constructor(table?: DexieTableLike) { + super("EventsCache", table); } key(of: NostrEvent): string { diff --git a/packages/system/src/cache/index.ts b/packages/system/src/cache/index.ts index 5065a740..f8870e9f 100644 --- a/packages/system/src/cache/index.ts +++ b/packages/system/src/cache/index.ts @@ -1,8 +1,5 @@ import { FullRelaySettings, HexKey, NostrEvent, UserMetadata } from ".."; -import { hexToBech32, unixNowMs } from "@snort/shared"; -import { SnortSystemDb } from "./db"; - -export const db = new SnortSystemDb(); +import { hexToBech32, unixNowMs, DexieTableLike } from "@snort/shared"; export interface MetadataCache extends UserMetadata { /** @@ -71,3 +68,12 @@ export function mapEventToProfile(ev: NostrEvent) { console.error("Failed to parse JSON", ev, e); } } + +export interface SnortSystemDb { + users: DexieTableLike; + relayMetrics: DexieTableLike; + userRelays: DexieTableLike; + events: DexieTableLike; + + isAvailable(): Promise; +} diff --git a/packages/system/src/cache/relay-metric.ts b/packages/system/src/cache/relay-metric.ts index 2eb735bd..dd697c0a 100644 --- a/packages/system/src/cache/relay-metric.ts +++ b/packages/system/src/cache/relay-metric.ts @@ -1,9 +1,9 @@ -import { db, RelayMetrics } from "."; -import { FeedCache } from "@snort/shared"; +import { RelayMetrics } from "."; +import { DexieTableLike, FeedCache } from "@snort/shared"; export class RelayMetricCache extends FeedCache { - constructor() { - super("RelayMetrics", db.relayMetrics); + constructor(table?: DexieTableLike) { + super("RelayMetrics", table); } key(of: RelayMetrics): string { diff --git a/packages/system/src/cache/user-metadata.ts b/packages/system/src/cache/user-metadata.ts index 5693a54b..496ef7f9 100644 --- a/packages/system/src/cache/user-metadata.ts +++ b/packages/system/src/cache/user-metadata.ts @@ -1,12 +1,12 @@ -import { db, MetadataCache } from "."; -import { fetchNip05Pubkey, FeedCache, LNURL } from "@snort/shared"; +import { MetadataCache } from "."; +import { fetchNip05Pubkey, FeedCache, LNURL, DexieTableLike } from "@snort/shared"; export class UserProfileCache extends FeedCache { #zapperQueue: Array<{ pubkey: string; lnurl: string }> = []; #nip5Queue: Array<{ pubkey: string; nip05: string }> = []; - constructor() { - super("UserCache", db.users); + constructor(table?: DexieTableLike) { + super("UserCache", table); this.#processZapperQueue(); this.#processNip5Queue(); } @@ -24,10 +24,10 @@ export class UserProfileCache extends FeedCache { } async search(q: string): Promise> { - if (db.ready) { + if (this.table) { // on-disk cache will always have more data return ( - await db.users + await this.table .where("npub") .startsWithIgnoreCase(q) .or("name") diff --git a/packages/system/src/cache/user-relays.ts b/packages/system/src/cache/user-relays.ts index 7381e341..2e98ab5f 100644 --- a/packages/system/src/cache/user-relays.ts +++ b/packages/system/src/cache/user-relays.ts @@ -1,9 +1,9 @@ -import { db, UsersRelays } from "."; -import { FeedCache } from "@snort/shared"; +import { UsersRelays } from "."; +import { DexieTableLike, FeedCache } from "@snort/shared"; export class UserRelaysCache extends FeedCache { - constructor() { - super("UserRelays", db.userRelays); + constructor(table?: DexieTableLike) { + super("UserRelays", table); } key(of: UsersRelays): string { diff --git a/packages/system/src/const.ts b/packages/system/src/const.ts index af06cced..28159825 100644 --- a/packages/system/src/const.ts +++ b/packages/system/src/const.ts @@ -34,3 +34,8 @@ export const CashuRegex = /(cashuA[A-Za-z0-9_-]{0,10000}={0,3})/i; * Regex to match any npub/nevent/naddr/nprofile/note */ export const MentionNostrEntityRegex = /@n(pub|profile|event|ote|addr|)1[acdefghjklmnpqrstuvwxyz023456789]+/g; + +/** + * Regex to match markdown code content + */ +export const MarkdownCodeRegex = /(```.+?```)/gms; diff --git a/packages/system/src/nostr-system.ts b/packages/system/src/nostr-system.ts index 31e20987..b06ffed7 100644 --- a/packages/system/src/nostr-system.ts +++ b/packages/system/src/nostr-system.ts @@ -16,8 +16,8 @@ import { UserProfileCache, UserRelaysCache, RelayMetricCache, - db, UsersRelays, + SnortSystemDb, } from "."; import { EventsCache } from "./cache/events"; import { RelayCache } from "./gossip-model"; @@ -87,19 +87,21 @@ export class NostrSystem extends ExternalStore implements System relayMetrics?: FeedCache; eventsCache?: FeedCache; queryOptimizer?: QueryOptimizer; + db?: SnortSystemDb; }) { super(); this.#handleAuth = props.authHandler; - this.#relayCache = props.relayCache ?? new UserRelaysCache(); - this.#profileCache = props.profileCache ?? new UserProfileCache(); - this.#relayMetricsCache = props.relayMetrics ?? new RelayMetricCache(); - this.#eventsCache = props.eventsCache ?? new EventsCache(); + this.#relayCache = props.relayCache ?? new UserRelaysCache(props.db?.userRelays); + this.#profileCache = props.profileCache ?? new UserProfileCache(props.db?.users); + this.#relayMetricsCache = props.relayMetrics ?? new RelayMetricCache(props.db?.relayMetrics); + this.#eventsCache = props.eventsCache ?? new EventsCache(props.db?.events); this.#queryOptimizer = props.queryOptimizer ?? DefaultQueryOptimizer; this.#profileLoader = new ProfileLoaderService(this, this.#profileCache); this.#relayMetrics = new RelayMetricHandler(this.#relayMetricsCache); this.#cleanup(); } + HandleAuth?: AuthHandler | undefined; get ProfileLoader() { @@ -122,7 +124,6 @@ export class NostrSystem extends ExternalStore implements System * Setup caches */ async Init() { - db.ready = await db.isAvailable(); const t = [ this.#relayCache.preload(), this.#profileCache.preload(), diff --git a/packages/system/src/text.ts b/packages/system/src/text.ts index 89b9514f..b6aebd7d 100644 --- a/packages/system/src/text.ts +++ b/packages/system/src/text.ts @@ -1,13 +1,31 @@ import { unwrap } from "@snort/shared"; -import { CashuRegex, FileExtensionRegex, HashtagRegex, InvoiceRegex, MentionNostrEntityRegex } from "./const"; +import { + CashuRegex, + FileExtensionRegex, + HashtagRegex, + InvoiceRegex, + MarkdownCodeRegex, + MentionNostrEntityRegex, +} from "./const"; import { validateNostrLink } from "./nostr-link"; import { splitByUrl } from "./utils"; export interface ParsedFragment { - type: "text" | "link" | "mention" | "invoice" | "media" | "cashu" | "hashtag" | "custom_emoji" | "highlighted_text"; + type: + | "text" + | "link" + | "mention" + | "invoice" + | "media" + | "cashu" + | "hashtag" + | "custom_emoji" + | "highlighted_text" + | "code_block"; content: string; mimeType?: string; + language?: string; } export type Fragment = string | ParsedFragment; @@ -179,6 +197,31 @@ function extractCustomEmoji(fragments: Fragment[], tags: Array>) { .flat(); } +function extractMarkdownCode(fragments: Fragment[]): (string | ParsedFragment)[] { + return fragments + .map(f => { + if (typeof f === "string") { + return f.split(MarkdownCodeRegex).map(i => { + if (i.startsWith("```") && i.endsWith("```")) { + const firstLineBreakIndex = i.indexOf("\n"); + const lastLineBreakIndex = i.lastIndexOf("\n"); + + return { + type: "code_block", + content: i.substring(firstLineBreakIndex, lastLineBreakIndex), + language: i.substring(3, firstLineBreakIndex), + } as ParsedFragment; + } else { + return i; + } + }); + } + + return f; + }) + .flat(); +} + export function transformText(body: string, tags: Array>) { let fragments = extractLinks([body]); fragments = extractMentions(fragments); @@ -186,10 +229,11 @@ export function transformText(body: string, tags: Array>) { fragments = extractInvoices(fragments); fragments = extractCashuTokens(fragments); fragments = extractCustomEmoji(fragments, tags); + fragments = extractMarkdownCode(fragments); fragments = fragments .map(a => { if (typeof a === "string") { - if (a.trim().length > 0) { + if (a.length > 0) { return { type: "text", content: a } as ParsedFragment; } } else { diff --git a/yarn.lock b/yarn.lock index 6ecf2593..5f2ef34f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1376,6 +1376,15 @@ __metadata: languageName: node linkType: hard +"@babel/runtime@npm:^7.1.2": + version: 7.23.1 + resolution: "@babel/runtime@npm:7.23.1" + dependencies: + regenerator-runtime: ^0.14.0 + checksum: 0cd0d43e6e7dc7f9152fda8c8312b08321cda2f56ef53d6c22ebdd773abdc6f5d0a69008de90aa41908d00e2c1facb24715ff121274e689305c858355ff02c70 + languageName: node + linkType: hard + "@babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.22.6, @babel/runtime@npm:^7.8.4": version: 7.22.11 resolution: "@babel/runtime@npm:7.22.11" @@ -2692,6 +2701,7 @@ __metadata: "@snort/system": "workspace:*" "@snort/system-react": "workspace:*" "@snort/system-wasm": "workspace:*" + "@snort/system-web": "workspace:*" "@szhsin/react-menu": ^3.3.1 "@types/debug": ^4.1.8 "@types/jest": ^29.5.1 @@ -2704,6 +2714,7 @@ __metadata: "@types/webtorrent": ^0.109.3 "@typescript-eslint/eslint-plugin": ^6.1.0 "@typescript-eslint/parser": ^6.1.0 + "@uidotdev/usehooks": ^2.3.1 "@void-cat/api": ^1.0.4 "@webbtc/webln-types": ^1.0.10 "@webpack-cli/generators": ^3.0.4 @@ -2718,6 +2729,7 @@ __metadata: emojilib: ^3.0.10 eslint: ^8.48.0 eslint-webpack-plugin: ^4.0.1 + highlight.js: ^11.8.0 html-webpack-plugin: ^5.5.1 jest: ^29.5.0 jest-environment-jsdom: ^29.5.0 @@ -2734,6 +2746,7 @@ __metadata: react-router-dom: ^6.5.0 react-textarea-autosize: ^8.4.0 react-twitter-embed: ^4.0.4 + recharts: ^2.8.0 source-map-loader: ^4.0.1 terser-webpack-plugin: ^5.3.9 tinybench: ^2.5.1 @@ -2798,6 +2811,17 @@ __metadata: languageName: unknown linkType: soft +"@snort/system-web@workspace:*, @snort/system-web@workspace:packages/system-web": + version: 0.0.0-use.local + resolution: "@snort/system-web@workspace:packages/system-web" + dependencies: + "@snort/shared": ^1.0.6 + "@snort/system": ^1.0.21 + dexie: ^3.2.4 + typescript: ^5.2.2 + languageName: unknown + linkType: soft + "@snort/system@^1.0.21, @snort/system@workspace:*, @snort/system@workspace:packages/system": version: 0.0.0-use.local resolution: "@snort/system@workspace:packages/system" @@ -3160,6 +3184,75 @@ __metadata: languageName: node linkType: hard +"@types/d3-array@npm:^3.0.3": + version: 3.0.8 + resolution: "@types/d3-array@npm:3.0.8" + checksum: d5a678f1dc3af05bc6beb675d59a11d9b2ad4ea59fb5b6c2b99980fec947d89a9562f3ac3a8d192a4f38152d3a4b9ee9cf4e2a30788eaacaed5de4a6da514e10 + languageName: node + linkType: hard + +"@types/d3-color@npm:*": + version: 3.1.1 + resolution: "@types/d3-color@npm:3.1.1" + checksum: 1fa67a6d11386c2727c942ab0ddffaca2289ba01d2f3cd0723afc78c291e9515dbdc6de082466d9e9c360d7c67ddbf313707456c0daa9aa14acb2d48cb3bcabb + languageName: node + linkType: hard + +"@types/d3-ease@npm:^3.0.0": + version: 3.0.0 + resolution: "@types/d3-ease@npm:3.0.0" + checksum: 1be7c993643b5a08332e0ee146375a3845545d8deb423db5d152e0b061524385d2345ceccf968f75f605247b940dd3f9a144335fee2e7d935cddaf187afb7095 + languageName: node + linkType: hard + +"@types/d3-interpolate@npm:^3.0.1": + version: 3.0.2 + resolution: "@types/d3-interpolate@npm:3.0.2" + dependencies: + "@types/d3-color": "*" + checksum: 86a1c4853c70663cba970d5c57dca995f604a70684b17bc5ff3ba83ce4e2c13f0105af29bb383ee70c4ccb1920c0dd4aeb352ae8721864d4a503a110260b9b13 + languageName: node + linkType: hard + +"@types/d3-path@npm:*": + version: 3.0.0 + resolution: "@types/d3-path@npm:3.0.0" + checksum: af7f45ea912cddd794c03384baba856f11e1f9b57a49d05a66a61968dafaeb86e0e42394883118b9b8ccadce21a5f25b1f9a88ad05235e1dc6d24c3e34a379ff + languageName: node + linkType: hard + +"@types/d3-scale@npm:^4.0.2": + version: 4.0.5 + resolution: "@types/d3-scale@npm:4.0.5" + dependencies: + "@types/d3-time": "*" + checksum: f462a3f2ec8767bb6762953ed65087b4037d9f8c57c84b1ffc62d55b7633975611e053c2f36cef063bf123196fbb5741b257760b2a745ede9544851f7d150d60 + languageName: node + linkType: hard + +"@types/d3-shape@npm:^3.1.0": + version: 3.1.3 + resolution: "@types/d3-shape@npm:3.1.3" + dependencies: + "@types/d3-path": "*" + checksum: ad17781ab4ce4b796954b86de7e14566c731726d39a1db7d73eaf50668a71e996d715450a0ff9f2720755e1b8643c3e88d47d45101a75c9d4ddbef51a636f6a0 + languageName: node + linkType: hard + +"@types/d3-time@npm:*, @types/d3-time@npm:^3.0.0": + version: 3.0.1 + resolution: "@types/d3-time@npm:3.0.1" + checksum: 32b0c4d33574df167717f37d5d69f60fa1aeebb0218823239734a48e6a33024a7f5aadd079e94d833b42bfc0c3e2d9fa7d7ac93f75981f59ef2a46838d008a61 + languageName: node + linkType: hard + +"@types/d3-timer@npm:^3.0.0": + version: 3.0.0 + resolution: "@types/d3-timer@npm:3.0.0" + checksum: 1ec86b3808de6ecfa93cfdf34254761069658af0cc1d9540e8353dbcba161cdf1296a0724187bd17433b2ff16563115fd20b85fc89d5e809ff28f9b1ab134b42 + languageName: node + linkType: hard + "@types/debug@npm:^4.1.8": version: 4.1.8 resolution: "@types/debug@npm:4.1.8" @@ -3760,6 +3853,16 @@ __metadata: languageName: node linkType: hard +"@uidotdev/usehooks@npm:^2.3.1": + version: 2.3.1 + resolution: "@uidotdev/usehooks@npm:2.3.1" + peerDependencies: + react: ">=18.0.0" + react-dom: ">=18.0.0" + checksum: a1339b91bdb4176f59fc2dd8273065fccacb17749b7022879982ff874bda8e4e54a3f8d74f126e6224164fb2ad422f1cc40dac8705467960df525b207fcd3a79 + languageName: node + linkType: hard + "@void-cat/api@npm:^1.0.4": version: 1.0.7 resolution: "@void-cat/api@npm:1.0.7" @@ -5009,6 +5112,13 @@ __metadata: languageName: node linkType: hard +"classnames@npm:^2.2.5": + version: 2.3.2 + resolution: "classnames@npm:2.3.2" + checksum: 2c62199789618d95545c872787137262e741f9db13328e216b093eea91c85ef2bfb152c1f9e63027204e2559a006a92eb74147d46c800a9f96297ae1d9f96f4e + languageName: node + linkType: hard + "clean-css@npm:^5.2.2": version: 5.3.2 resolution: "clean-css@npm:5.3.2" @@ -5552,6 +5662,13 @@ __metadata: languageName: node linkType: hard +"css-unit-converter@npm:^1.1.1": + version: 1.1.2 + resolution: "css-unit-converter@npm:1.1.2" + checksum: 07888033346a5128f34dbe2f72884c966d24e9f29db24416dcde92860242490617ef9a178ac193a92f730834bbeea026cdc7027701d92ba9bbbe59db7a37eb2a + languageName: node + linkType: hard + "css-what@npm:^6.0.1, css-what@npm:^6.1.0": version: 6.1.0 resolution: "css-what@npm:6.1.0" @@ -5674,6 +5791,99 @@ __metadata: languageName: node linkType: hard +"d3-array@npm:2 - 3, d3-array@npm:2.10.0 - 3, d3-array@npm:^3.1.6": + version: 3.2.4 + resolution: "d3-array@npm:3.2.4" + dependencies: + internmap: 1 - 2 + checksum: a5976a6d6205f69208478bb44920dd7ce3e788c9dceb86b304dbe401a4bfb42ecc8b04c20facde486e9adcb488b5d1800d49393a3f81a23902b68158e12cddd0 + languageName: node + linkType: hard + +"d3-color@npm:1 - 3": + version: 3.1.0 + resolution: "d3-color@npm:3.1.0" + checksum: 4931fbfda5d7c4b5cfa283a13c91a954f86e3b69d75ce588d06cde6c3628cebfc3af2069ccf225e982e8987c612aa7948b3932163ce15eb3c11cd7c003f3ee3b + languageName: node + linkType: hard + +"d3-ease@npm:^3.0.1": + version: 3.0.1 + resolution: "d3-ease@npm:3.0.1" + checksum: 06e2ee5326d1e3545eab4e2c0f84046a123dcd3b612e68858219aa034da1160333d9ce3da20a1d3486d98cb5c2a06f7d233eee1bc19ce42d1533458bd85dedcd + languageName: node + linkType: hard + +"d3-format@npm:1 - 3": + version: 3.1.0 + resolution: "d3-format@npm:3.1.0" + checksum: f345ec3b8ad3cab19bff5dead395bd9f5590628eb97a389b1dd89f0b204c7c4fc1d9520f13231c2c7cf14b7c9a8cf10f8ef15bde2befbab41454a569bd706ca2 + languageName: node + linkType: hard + +"d3-interpolate@npm:1.2.0 - 3, d3-interpolate@npm:^3.0.1": + version: 3.0.1 + resolution: "d3-interpolate@npm:3.0.1" + dependencies: + d3-color: 1 - 3 + checksum: a42ba314e295e95e5365eff0f604834e67e4a3b3c7102458781c477bd67e9b24b6bb9d8e41ff5521050a3f2c7c0c4bbbb6e187fd586daa3980943095b267e78b + languageName: node + linkType: hard + +"d3-path@npm:^3.1.0": + version: 3.1.0 + resolution: "d3-path@npm:3.1.0" + checksum: 2306f1bd9191e1eac895ec13e3064f732a85f243d6e627d242a313f9777756838a2215ea11562f0c7630c7c3b16a19ec1fe0948b1c82f3317fac55882f6ee5d8 + languageName: node + linkType: hard + +"d3-scale@npm:^4.0.2": + version: 4.0.2 + resolution: "d3-scale@npm:4.0.2" + dependencies: + d3-array: 2.10.0 - 3 + d3-format: 1 - 3 + d3-interpolate: 1.2.0 - 3 + d3-time: 2.1.1 - 3 + d3-time-format: 2 - 4 + checksum: a9c770d283162c3bd11477c3d9d485d07f8db2071665f1a4ad23eec3e515e2cefbd369059ec677c9ac849877d1a765494e90e92051d4f21111aa56791c98729e + languageName: node + linkType: hard + +"d3-shape@npm:^3.1.0": + version: 3.2.0 + resolution: "d3-shape@npm:3.2.0" + dependencies: + d3-path: ^3.1.0 + checksum: de2af5fc9a93036a7b68581ca0bfc4aca2d5a328aa7ba7064c11aedd44d24f310c20c40157cb654359d4c15c3ef369f95ee53d71221017276e34172c7b719cfa + languageName: node + linkType: hard + +"d3-time-format@npm:2 - 4": + version: 4.1.0 + resolution: "d3-time-format@npm:4.1.0" + dependencies: + d3-time: 1 - 3 + checksum: 7342bce28355378152bbd4db4e275405439cabba082d9cd01946d40581140481c8328456d91740b0fe513c51ec4a467f4471ffa390c7e0e30ea30e9ec98fcdf4 + languageName: node + linkType: hard + +"d3-time@npm:1 - 3, d3-time@npm:2.1.1 - 3, d3-time@npm:^3.0.0": + version: 3.1.0 + resolution: "d3-time@npm:3.1.0" + dependencies: + d3-array: 2 - 3 + checksum: 613b435352a78d9f31b7f68540788186d8c331b63feca60ad21c88e9db1989fe888f97f242322ebd6365e45ec3fb206a4324cd4ca0dfffa1d9b5feb856ba00a7 + languageName: node + linkType: hard + +"d3-timer@npm:^3.0.1": + version: 3.0.1 + resolution: "d3-timer@npm:3.0.1" + checksum: 1cfddf86d7bca22f73f2c427f52dfa35c49f50d64e187eb788dcad6e927625c636aa18ae4edd44d084eb9d1f81d8ca4ec305dae7f733c15846a824575b789d73 + languageName: node + linkType: hard + "dargs@npm:^7.0.0": version: 7.0.0 resolution: "dargs@npm:7.0.0" @@ -5727,6 +5937,13 @@ __metadata: languageName: node linkType: hard +"decimal.js-light@npm:^2.4.1": + version: 2.5.1 + resolution: "decimal.js-light@npm:2.5.1" + checksum: f5a2c7eac1c4541c8ab8a5c8abea64fc1761cefc7794bd5f8afd57a8a78d1b51785e0c4e4f85f4895a043eaa90ddca1edc3981d1263eb6ddce60f32bf5fe66c9 + languageName: node + linkType: hard + "decimal.js@npm:^10.4.2": version: 10.4.3 resolution: "decimal.js@npm:10.4.3" @@ -5946,6 +6163,15 @@ __metadata: languageName: node linkType: hard +"dom-helpers@npm:^3.4.0": + version: 3.4.0 + resolution: "dom-helpers@npm:3.4.0" + dependencies: + "@babel/runtime": ^7.1.2 + checksum: 58d9f1c4a96daf77eddc63ae1236b826e1cddd6db66bbf39b18d7e21896d99365b376593352d52a60969d67fa4a8dbef26adc1439fa2c1b355efa37cacbaf637 + languageName: node + linkType: hard + "dom-serializer@npm:^1.0.1": version: 1.4.1 resolution: "dom-serializer@npm:1.4.1" @@ -6489,7 +6715,7 @@ __metadata: languageName: node linkType: hard -"eventemitter3@npm:^4.0.0, eventemitter3@npm:^4.0.4": +"eventemitter3@npm:^4.0.0, eventemitter3@npm:^4.0.1, eventemitter3@npm:^4.0.4": version: 4.0.7 resolution: "eventemitter3@npm:4.0.7" checksum: 1875311c42fcfe9c707b2712c32664a245629b42bb0a5a84439762dd0fd637fc54d078155ea83c2af9e0323c9ac13687e03cfba79b03af9f40c89b4960099374 @@ -6604,6 +6830,13 @@ __metadata: languageName: node linkType: hard +"fast-equals@npm:^5.0.0": + version: 5.0.1 + resolution: "fast-equals@npm:5.0.1" + checksum: fbb3b6a74f3a0fa930afac151ff7d01639159b4fddd2678b5d50708e0ba38e9ec14602222d10dadb8398187342692c04fbef5a62b1cfcc7942fe03e754e064bc + languageName: node + linkType: hard + "fast-glob@npm:^3.2.11, fast-glob@npm:^3.2.9, fast-glob@npm:^3.3.0": version: 3.3.1 resolution: "fast-glob@npm:3.3.1" @@ -7278,6 +7511,13 @@ __metadata: languageName: node linkType: hard +"highlight.js@npm:^11.8.0": + version: 11.8.0 + resolution: "highlight.js@npm:11.8.0" + checksum: d2578a57aee7315946ff19379053fd0a28b127baabf7617ab1d28d62cdc4eaf3d75053569cb8479a5afdc7a68f1ba9a6c1d612d8ae399b4b9aa43093b4fb6831 + languageName: node + linkType: hard + "hoist-non-react-statics@npm:^3.3.0, hoist-non-react-statics@npm:^3.3.2": version: 3.3.2 resolution: "hoist-non-react-statics@npm:3.3.2" @@ -7681,6 +7921,13 @@ __metadata: languageName: node linkType: hard +"internmap@npm:1 - 2": + version: 2.0.3 + resolution: "internmap@npm:2.0.3" + checksum: 7ca41ec6aba8f0072fc32fa8a023450a9f44503e2d8e403583c55714b25efd6390c38a87161ec456bf42d7bc83aab62eb28f5aef34876b1ac4e60693d5e1d241 + languageName: node + linkType: hard + "interpret@npm:^1.0.0": version: 1.4.0 resolution: "interpret@npm:1.4.0" @@ -9050,7 +9297,7 @@ __metadata: languageName: node linkType: hard -"lodash@npm:^4.17.10, lodash@npm:^4.17.11, lodash@npm:^4.17.20, lodash@npm:^4.17.21": +"lodash@npm:^4.17.10, lodash@npm:^4.17.11, lodash@npm:^4.17.19, lodash@npm:^4.17.20, lodash@npm:^4.17.21": version: 4.17.21 resolution: "lodash@npm:4.17.21" checksum: eb835a2e51d381e561e508ce932ea50a8e5a68f4ebdd771ea240d3048244a8d13658acbd502cd4829768c56f2e16bdd4340b9ea141297d472517b83868e677f7 @@ -10871,6 +11118,13 @@ __metadata: languageName: node linkType: hard +"postcss-value-parser@npm:^3.3.0": + version: 3.3.1 + resolution: "postcss-value-parser@npm:3.3.1" + checksum: 62cd26e1cdbcf2dcc6bcedf3d9b409c9027bc57a367ae20d31dd99da4e206f730689471fd70a2abe866332af83f54dc1fa444c589e2381bf7f8054c46209ce16 + languageName: node + linkType: hard + "postcss-value-parser@npm:^4.1.0, postcss-value-parser@npm:^4.2.0": version: 4.2.0 resolution: "postcss-value-parser@npm:4.2.0" @@ -11032,7 +11286,7 @@ __metadata: languageName: node linkType: hard -"prop-types@npm:^15.7.2, prop-types@npm:^15.8.1": +"prop-types@npm:^15.6.2, prop-types@npm:^15.7.2, prop-types@npm:^15.8.1": version: 15.8.1 resolution: "prop-types@npm:15.8.1" dependencies: @@ -11209,7 +11463,7 @@ __metadata: languageName: node linkType: hard -"react-is@npm:^16.13.1, react-is@npm:^16.7.0": +"react-is@npm:^16.10.2, react-is@npm:^16.13.1, react-is@npm:^16.7.0": version: 16.13.1 resolution: "react-is@npm:16.13.1" checksum: f7a19ac3496de32ca9ae12aa030f00f14a3d45374f1ceca0af707c831b2a6098ef0d6bdae51bd437b0a306d7f01d4677fcc8de7c0d331eb47ad0f46130e53c5f @@ -11223,6 +11477,25 @@ __metadata: languageName: node linkType: hard +"react-lifecycles-compat@npm:^3.0.4": + version: 3.0.4 + resolution: "react-lifecycles-compat@npm:3.0.4" + checksum: a904b0fc0a8eeb15a148c9feb7bc17cec7ef96e71188280061fc340043fd6d8ee3ff233381f0e8f95c1cf926210b2c4a31f38182c8f35ac55057e453d6df204f + languageName: node + linkType: hard + +"react-resize-detector@npm:^8.0.4": + version: 8.1.0 + resolution: "react-resize-detector@npm:8.1.0" + dependencies: + lodash: ^4.17.21 + peerDependencies: + react: ^16.0.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 + checksum: 45e6b87ea7331406bed2a806d0cea98c1467d53a7cfcdf19c2dd55a3460047917d3b175d9cceea6f314b65eb54858cbb981acffd007d67aa16388e517dafb83e + languageName: node + linkType: hard + "react-router-dom@npm:^6.5.0": version: 6.15.0 resolution: "react-router-dom@npm:6.15.0" @@ -11247,6 +11520,20 @@ __metadata: languageName: node linkType: hard +"react-smooth@npm:^2.0.2": + version: 2.0.4 + resolution: "react-smooth@npm:2.0.4" + dependencies: + fast-equals: ^5.0.0 + react-transition-group: 2.9.0 + peerDependencies: + prop-types: ^15.6.0 + react: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 + react-dom: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 + checksum: 21731e2f9ebc9594eae0f0d875526185392a87c00abf013c9769ed642a4077b62c04c1001b2527a196aabafb87af208f6c7107db674538c4bb95c253ed123447 + languageName: node + linkType: hard + "react-textarea-autosize@npm:^8.4.0": version: 8.5.3 resolution: "react-textarea-autosize@npm:8.5.3" @@ -11260,6 +11547,21 @@ __metadata: languageName: node linkType: hard +"react-transition-group@npm:2.9.0": + version: 2.9.0 + resolution: "react-transition-group@npm:2.9.0" + dependencies: + dom-helpers: ^3.4.0 + loose-envify: ^1.4.0 + prop-types: ^15.6.2 + react-lifecycles-compat: ^3.0.4 + peerDependencies: + react: ">=15.0.0" + react-dom: ">=15.0.0" + checksum: d8c9e50aabdc2cfc324e5cdb0ad1c6eecb02e1c0cd007b26d5b30ccf49015e900683dd489348c71fba4055858308d9ba7019e0d37d0e8d37bd46ed098788f670 + languageName: node + linkType: hard + "react-transition-state@npm:^1.1.5": version: 1.1.5 resolution: "react-transition-state@npm:1.1.5" @@ -11413,6 +11715,36 @@ __metadata: languageName: node linkType: hard +"recharts-scale@npm:^0.4.4": + version: 0.4.5 + resolution: "recharts-scale@npm:0.4.5" + dependencies: + decimal.js-light: ^2.4.1 + checksum: e970377190a610e684a32c7461c7684ac3603c2e0ac0020bbba1eea9d099b38138143a8e80bf769bb49c0b7cecf22a2f5c6854885efed2d56f4540d4aa7052bd + languageName: node + linkType: hard + +"recharts@npm:^2.8.0": + version: 2.8.0 + resolution: "recharts@npm:2.8.0" + dependencies: + classnames: ^2.2.5 + eventemitter3: ^4.0.1 + lodash: ^4.17.19 + react-is: ^16.10.2 + react-resize-detector: ^8.0.4 + react-smooth: ^2.0.2 + recharts-scale: ^0.4.4 + reduce-css-calc: ^2.1.8 + victory-vendor: ^36.6.8 + peerDependencies: + prop-types: ^15.6.0 + react: ^16.0.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 + checksum: 4638bd5c6c2af8f5c79de5e13cce0e38f06e0bbb0a3c4df27a9b12632fd72c0a0604c8246f55e830f323dfa84a3da7cb2634c2243bb9c775d899fd71f9d4c87a + languageName: node + linkType: hard + "rechoir@npm:^0.6.2": version: 0.6.2 resolution: "rechoir@npm:0.6.2" @@ -11431,6 +11763,16 @@ __metadata: languageName: node linkType: hard +"reduce-css-calc@npm:^2.1.8": + version: 2.1.8 + resolution: "reduce-css-calc@npm:2.1.8" + dependencies: + css-unit-converter: ^1.1.1 + postcss-value-parser: ^3.3.0 + checksum: 8fd27c06c4b443b84749a69a8b97d10e6ec7d142b625b41923a8807abb22b9e37e44df14e26cc606a802957be07bdce5e8ee2976a6952a7b438a7727007101e9 + languageName: node + linkType: hard + "regenerate-unicode-properties@npm:^10.1.0": version: 10.1.0 resolution: "regenerate-unicode-properties@npm:10.1.0" @@ -13393,6 +13735,28 @@ __metadata: languageName: node linkType: hard +"victory-vendor@npm:^36.6.8": + version: 36.6.11 + resolution: "victory-vendor@npm:36.6.11" + dependencies: + "@types/d3-array": ^3.0.3 + "@types/d3-ease": ^3.0.0 + "@types/d3-interpolate": ^3.0.1 + "@types/d3-scale": ^4.0.2 + "@types/d3-shape": ^3.1.0 + "@types/d3-time": ^3.0.0 + "@types/d3-timer": ^3.0.0 + d3-array: ^3.1.6 + d3-ease: ^3.0.1 + d3-interpolate: ^3.0.1 + d3-scale: ^4.0.2 + d3-shape: ^3.1.0 + d3-time: ^3.0.0 + d3-timer: ^3.0.1 + checksum: 55800076dfa6abedf7758840986a302778a904678d4b66fe47d977c48b6f9484276b780871e6e5105b31c1eb936e9f1331ee39afcc2869bf65ceb7d456143172 + languageName: node + linkType: hard + "vinyl-file@npm:^3.0.0": version: 3.0.0 resolution: "vinyl-file@npm:3.0.0"