- {formatFileSize(imeta.size)}
+
+ Size
+ {formatFileSize(imeta.size)}
+
+ )}
+ {imeta.dim && (
+
+ Dimensions
+ {imeta.dim}
+
+ )}
+ {imeta.m && (
+
+ Type
+ {imeta.m}
)}
{imeta.duration && (
-
- {formatDuration(imeta.duration)}
+
+ Duration
+ {formatDuration(imeta.duration)}
+
+ )}
+ {imeta.alt && (
+
+ Alt
+ {imeta.alt}
)}
diff --git a/src/components/nostr/RichText.tsx b/src/components/nostr/RichText.tsx
index 58436f5..74ec506 100644
--- a/src/components/nostr/RichText.tsx
+++ b/src/components/nostr/RichText.tsx
@@ -26,14 +26,6 @@ export interface MediaRendererProps {
imeta?: ImetaEntry;
}
-// Context for custom media rendering across RichText subtree
-const MediaRendererContext =
- createContext
| null>(null);
-
-export function useMediaRenderer() {
- return useContext(MediaRendererContext);
-}
-
// Context for passing the source event (for imeta lookup)
const EventContext = createContext(null);
@@ -113,8 +105,6 @@ interface RichTextProps {
options?: RichTextOptions;
/** Parser options for customizing content parsing */
parserOptions?: ParserOptions;
- /** Custom media renderer for images, videos, and audio */
- renderMedia?: React.ComponentType;
children?: React.ReactNode;
}
@@ -143,12 +133,8 @@ export function RichText({
depth = 1,
options = {},
parserOptions = {},
- renderMedia,
children,
}: RichTextProps) {
- // Get parent media renderer to inherit if not explicitly overridden
- const parentMediaRenderer = useMediaRenderer();
-
// Merge provided options with defaults
const mergedOptions: Required = {
...defaultOptions,
@@ -194,19 +180,15 @@ export function RichText({
return (
-
-
-
- {children}
- {renderedContent}
-
-
-
+
+
+ {children}
+ {renderedContent}
+
+
);
diff --git a/src/components/nostr/RichText/Gallery.tsx b/src/components/nostr/RichText/Gallery.tsx
index d4441f0..67addc4 100644
--- a/src/components/nostr/RichText/Gallery.tsx
+++ b/src/components/nostr/RichText/Gallery.tsx
@@ -6,12 +6,10 @@ import {
} from "applesauce-core/helpers/url";
import { MediaDialog } from "../MediaDialog";
import { MediaEmbed } from "../MediaEmbed";
-import {
- useRichTextOptions,
- useMediaRenderer,
- useRichTextEvent,
-} from "../RichText";
+import { CompactMediaRenderer } from "../CompactMediaRenderer";
+import { useRichTextOptions, useRichTextEvent } from "../RichText";
import { findImetaForUrl } from "@/lib/imeta";
+import { useSettings } from "@/hooks/useSettings";
function MediaPlaceholder({
type,
@@ -29,11 +27,14 @@ interface GalleryNodeProps {
export function Gallery({ node }: GalleryNodeProps) {
const options = useRichTextOptions();
- const CustomMediaRenderer = useMediaRenderer();
const event = useRichTextEvent();
+ const { settings } = useSettings();
const [dialogOpen, setDialogOpen] = useState(false);
const [initialIndex, setInitialIndex] = useState(0);
+ // Check global loadMedia setting
+ const loadMedia = settings?.appearance?.loadMedia ?? true;
+
const links = node.links || [];
const handleAudioClick = (index: number) => {
@@ -50,8 +51,8 @@ export function Gallery({ node }: GalleryNodeProps) {
if (isImageURL(url)) {
if (shouldShowMedia && options.showImages) {
- if (CustomMediaRenderer) {
- return ;
+ if (!loadMedia) {
+ return ;
}
return ;
}
@@ -59,8 +60,8 @@ export function Gallery({ node }: GalleryNodeProps) {
}
if (isVideoURL(url)) {
if (shouldShowMedia && options.showVideos) {
- if (CustomMediaRenderer) {
- return ;
+ if (!loadMedia) {
+ return ;
}
return ;
}
@@ -68,8 +69,8 @@ export function Gallery({ node }: GalleryNodeProps) {
}
if (isAudioURL(url)) {
if (shouldShowMedia && options.showAudio) {
- if (CustomMediaRenderer) {
- return ;
+ if (!loadMedia) {
+ return ;
}
return (
[{type}];
@@ -26,11 +24,14 @@ interface LinkNodeProps {
export function Link({ node }: LinkNodeProps) {
const options = useRichTextOptions();
- const CustomMediaRenderer = useMediaRenderer();
const event = useRichTextEvent();
+ const { settings } = useSettings();
const [dialogOpen, setDialogOpen] = useState(false);
const { href } = node;
+ // Check global loadMedia setting
+ const loadMedia = settings?.appearance?.loadMedia ?? true;
+
// Look up imeta for this URL if event is available
const imeta = event ? findImetaForUrl(event, href) : undefined;
@@ -44,8 +45,8 @@ export function Link({ node }: LinkNodeProps) {
// Render appropriate link type
if (isImageURL(href)) {
if (shouldShowMedia && options.showImages) {
- if (CustomMediaRenderer) {
- return ;
+ if (!loadMedia) {
+ return ;
}
return (
;
+ if (!loadMedia) {
+ return ;
}
return (
;
+ if (!loadMedia) {
+ return ;
}
return (
<>
diff --git a/src/services/settings.ts b/src/services/settings.ts
index 4effa8f..bc798c1 100644
--- a/src/services/settings.ts
+++ b/src/services/settings.ts
@@ -22,6 +22,8 @@ export interface PostSettings {
export interface AppearanceSettings {
/** Show client tags in event UI */
showClientTags: boolean;
+ /** Load media inline (images, videos, audio) - when false, show compact links */
+ loadMedia: boolean;
}
/**
@@ -43,6 +45,7 @@ const DEFAULT_POST_SETTINGS: PostSettings = {
const DEFAULT_APPEARANCE_SETTINGS: AppearanceSettings = {
showClientTags: true,
+ loadMedia: true,
};
export const DEFAULT_SETTINGS: AppSettings = {