This commit is contained in:
Ren Amamiya 2023-10-04 14:11:45 +07:00
parent 480580890e
commit f80dd78a8e
14 changed files with 165 additions and 176 deletions

View File

@ -40,7 +40,7 @@
"@tiptap/react": "^2.1.11",
"@tiptap/starter-kit": "^2.1.11",
"@tiptap/suggestion": "^2.1.11",
"@vidstack/react": "^1.1.5",
"@vidstack/react": "^1.1.7",
"dayjs": "^1.11.10",
"destr": "^2.0.1",
"html-to-text": "^9.0.5",
@ -57,7 +57,6 @@
"react-hook-form": "^7.47.0",
"react-markdown": "^8.0.7",
"react-router-dom": "^6.16.0",
"react-textarea-autosize": "^8.5.3",
"reactflow": "^11.9.2",
"remark-gfm": "^3.0.1",
"tauri-plugin-sql-api": "github:tauri-apps/tauri-plugin-sql#v1",

View File

@ -72,8 +72,8 @@ dependencies:
specifier: ^2.1.11
version: 2.1.11(@tiptap/core@2.1.11)(@tiptap/pm@2.1.11)
'@vidstack/react':
specifier: ^1.1.5
version: 1.1.5(@types/react@18.2.24)(react@18.2.0)
specifier: ^1.1.7
version: 1.1.7(@types/react@18.2.24)(react@18.2.0)
dayjs:
specifier: ^1.11.10
version: 1.11.10
@ -122,9 +122,6 @@ dependencies:
react-router-dom:
specifier: ^6.16.0
version: 6.16.0(react-dom@18.2.0)(react@18.2.0)
react-textarea-autosize:
specifier: ^8.5.3
version: 8.5.3(@types/react@18.2.24)(react@18.2.0)
reactflow:
specifier: ^11.9.2
version: 11.9.2(@types/react@18.2.24)(react-dom@18.2.0)(react@18.2.0)
@ -2703,8 +2700,8 @@ packages:
eslint-visitor-keys: 3.4.3
dev: true
/@vidstack/react@1.1.5(@types/react@18.2.24)(react@18.2.0):
resolution: {integrity: sha512-EutVuOU2b6XTryEmPU23T2Ftu3j4BuJGdGbyHoDtc15m6iL/DtpkBJCLqRVI7PaiuQtqneKcvKUNcBNogVz5KQ==}
/@vidstack/react@1.1.7(@types/react@18.2.24)(react@18.2.0):
resolution: {integrity: sha512-qNd3+hLBdtWqFuPe1OZetVi/F/qOKXb1ByTPc4JdCmiGaheNhpMMLf8HM/r26YnP5v86WXvKgCFDuiiMyWXGbg==}
engines: {node: '>=18'}
peerDependencies:
'@types/react': ^18.0.0
@ -5732,20 +5729,6 @@ packages:
tslib: 2.6.2
dev: false
/react-textarea-autosize@8.5.3(@types/react@18.2.24)(react@18.2.0):
resolution: {integrity: sha512-XT1024o2pqCuZSuBt9FwHlaDeNtVrtCXu0Rnz88t1jUGheCLa3PhjE1GH8Ctm2axEtvdCl5SUHYschyQ0L5QHQ==}
engines: {node: '>=10'}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0
dependencies:
'@babel/runtime': 7.23.1
react: 18.2.0
use-composed-ref: 1.3.0(react@18.2.0)
use-latest: 1.2.1(@types/react@18.2.24)(react@18.2.0)
transitivePeerDependencies:
- '@types/react'
dev: false
/react@18.2.0:
resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==}
engines: {node: '>=0.10.0'}
@ -6428,41 +6411,6 @@ packages:
tslib: 2.6.2
dev: false
/use-composed-ref@1.3.0(react@18.2.0):
resolution: {integrity: sha512-GLMG0Jc/jiKov/3Ulid1wbv3r54K9HlMW29IWcDFPEqFkSO2nS0MuefWgMJpeHQ9YJeXDL3ZUF+P3jdXlZX/cQ==}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0
dependencies:
react: 18.2.0
dev: false
/use-isomorphic-layout-effect@1.1.2(@types/react@18.2.24)(react@18.2.0):
resolution: {integrity: sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==}
peerDependencies:
'@types/react': '*'
react: ^16.8.0 || ^17.0.0 || ^18.0.0
peerDependenciesMeta:
'@types/react':
optional: true
dependencies:
'@types/react': 18.2.24
react: 18.2.0
dev: false
/use-latest@1.2.1(@types/react@18.2.24)(react@18.2.0):
resolution: {integrity: sha512-xA+AVm/Wlg3e2P/JiItTziwS7FK92LWrDB0p+hgXloIMuVCeJJ8v6f0eeHyPZaJrM+usM1FkFfbNCrJGs8A/zw==}
peerDependencies:
'@types/react': '*'
react: ^16.8.0 || ^17.0.0 || ^18.0.0
peerDependenciesMeta:
'@types/react':
optional: true
dependencies:
'@types/react': 18.2.24
react: 18.2.0
use-isomorphic-layout-effect: 1.1.2(@types/react@18.2.24)(react@18.2.0)
dev: false
/use-sidecar@1.1.2(@types/react@18.2.24)(react@18.2.0):
resolution: {integrity: sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==}
engines: {node: '>=10'}

View File

@ -4,8 +4,8 @@ import { useCallback, useEffect, useRef } from 'react';
import { useParams } from 'react-router-dom';
import { VList, VListHandle } from 'virtua';
import { ChatMessageForm } from '@app/chats/components/messages/form';
import { ChatMessageItem } from '@app/chats/components/messages/item';
import { ChatForm } from '@app/chats/components/chatForm';
import { ChatMessage } from '@app/chats/components/message';
import { useNDK } from '@libs/ndk/provider';
import { useStorage } from '@libs/storage/provider';
@ -31,7 +31,7 @@ export function ChatScreen() {
const renderItem = useCallback(
(message: NDKEvent) => {
return (
<ChatMessageItem
<ChatMessage
message={message}
userPubkey={db.account.pubkey}
userPrivkey={userPrivkey}
@ -42,7 +42,7 @@ export function ChatScreen() {
);
useEffect(() => {
if (data.length > 0) listRef.current?.scrollToIndex(data.length);
if (data && data.length > 0) listRef.current?.scrollToIndex(data.length);
}, [data]);
useEffect(() => {
@ -68,10 +68,9 @@ export function ChatScreen() {
}, [pubkey]);
return (
<div className="grid h-full w-full grid-cols-3 bg-white/10 backdrop-blur-xl">
<div className="col-span-2 border-r border-white/5">
<div className="h-full w-full flex-1 p-3">
<div className="flex h-full flex-col justify-between overflow-hidden rounded-xl bg-white/10 backdrop-blur-xl">
<div className="h-full w-full p-3">
<div className="rounded-lg border-t border-white/5 bg-white/10 backdrop-blur-xl">
<div className="flex h-full flex-col justify-between overflow-hidden">
<div className="h-full w-full flex-1">
{status === 'loading' ? (
<div className="flex h-full w-full items-center justify-center">
@ -93,8 +92,8 @@ export function ChatScreen() {
</VList>
)}
</div>
<div className="z-50 shrink-0 rounded-b-xl border-t border-white/5 bg-white/10 p-3 px-5 backdrop-blur-xl">
<ChatMessageForm
<div className="z-50 shrink-0 rounded-b-xl border-t border-white/5 bg-white/10 p-3 backdrop-blur-xl">
<ChatForm
receiverPubkey={pubkey}
userPubkey={db.account.pubkey}
userPrivkey={userPrivkey}
@ -103,6 +102,5 @@ export function ChatScreen() {
</div>
</div>
</div>
</div>
);
}

View File

@ -41,7 +41,7 @@ export const ChatListItem = memo(function ChatListItem({ event }: { event: NDKEv
preventScrollReset={true}
className={({ isActive }) =>
twMerge(
'flex items-center gap-2.5 px-3 py-2 hover:bg-white/10',
'flex items-center gap-2.5 px-3 py-1.5 hover:bg-white/10',
isActive
? 'border-fuchsia-500 bg-white/5 text-white'
: 'border-transparent text-white/70'
@ -55,14 +55,10 @@ export const ChatListItem = memo(function ChatListItem({ event }: { event: NDKEv
loading="lazy"
decoding="async"
style={{ contentVisibility: 'auto' }}
className="h-10 w-10 rounded-lg"
className="h-9 w-9 rounded-lg"
/>
<Avatar.Fallback delayMs={300}>
<img
src={svgURI}
alt={event.pubkey}
className="h-10 w-10 rounded-lg border border-white/5 bg-black"
/>
<img src={svgURI} alt={event.pubkey} className="h-9 w-9 rounded-lg bg-white" />
</Avatar.Fallback>
</Avatar.Root>
<div className="flex w-full flex-col">

View File

@ -1,14 +1,13 @@
import { nip04 } from 'nostr-tools';
import { useCallback, useState } from 'react';
import TextareaAutosize from 'react-textarea-autosize';
import { MediaUploader } from '@app/chats/components/messages/mediaUploader';
import { MediaUploader } from '@app/chats/components/mediaUploader';
import { EnterIcon } from '@shared/icons';
import { useNostr } from '@utils/hooks/useNostr';
export function ChatMessageForm({
export function ChatForm({
receiverPubkey,
userPrivkey,
}: {
@ -46,8 +45,10 @@ export function ChatMessageForm({
};
return (
<div className="flex w-full items-center justify-between rounded-md bg-white/20 px-3">
<TextareaAutosize
<div className="flex items-center gap-2">
<MediaUploader setState={setValue} />
<div className="flex w-full items-center justify-between rounded-full bg-white/20 px-3">
<input
value={value}
onChange={(e) => setValue(e.target.value)}
onKeyDown={handleEnterPress}
@ -56,14 +57,12 @@ export function ChatMessageForm({
autoCorrect="off"
autoCapitalize="off"
placeholder="Message"
className="min-h-[44px] flex-1 resize-none bg-transparent py-3 text-white !outline-none placeholder:text-white"
className="h-10 flex-1 resize-none bg-transparent px-3 text-white placeholder:text-white/80 focus:outline-none"
/>
<div className="inline-flex items-center gap-2">
<MediaUploader setState={setValue} />
<button
type="button"
onClick={submit}
className="inline-flex items-center gap-1.5 text-sm font-medium leading-none text-white/50"
className="inline-flex shrink-0 items-center gap-1.5 text-sm font-medium text-white/80"
>
<EnterIcon className="h-5 w-5" />
Send

View File

@ -29,12 +29,12 @@ export function MediaUploader({
<button
type="button"
onClick={() => uploadMedia()}
className="group inline-flex h-8 w-8 items-center justify-center rounded backdrop-blur-xl hover:bg-white/10"
className="group inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-white/10 text-white backdrop-blur-xl hover:bg-white/20"
>
{loading ? (
<LoaderIcon className="h-5 w-5 animate-spin text-white" />
<LoaderIcon className="h-4 w-4 animate-spin" />
) : (
<MediaIcon className="h-5 w-5 text-white" />
<MediaIcon className="h-4 w-4" />
)}
</button>
</Tooltip.Trigger>

View File

@ -0,0 +1,54 @@
import { NDKEvent } from '@nostr-dev-kit/ndk';
import { useDecryptMessage } from '@app/chats/hooks/useDecryptMessage';
import { ImagePreview, LinkPreview, MentionNote, VideoPreview } from '@shared/notes';
import { User } from '@shared/user';
import { parser } from '@utils/parser';
export function ChatMessage({
message,
userPubkey,
userPrivkey,
}: {
message: NDKEvent;
userPubkey: string;
userPrivkey: string;
}) {
const decryptedContent = useDecryptMessage(message, userPubkey, userPrivkey);
const richContent = parser(decryptedContent) ?? null;
return (
<div className="flex h-min min-h-min w-full select-text flex-col px-5 py-3 hover:bg-white/10">
<div className="flex flex-col">
<User pubkey={message.pubkey} time={message.created_at} variant="chat" />
<div className="-mt-6 flex items-start gap-3">
<div className="w-10 shrink-0" />
{!richContent ? (
<p>Decrypting...</p>
) : (
<div>
<p className="select-text whitespace-pre-line text-white">
{richContent.parsed}
</p>
<div>
{richContent.images.length > 0 && (
<ImagePreview urls={richContent.images} />
)}
{richContent.videos.length > 0 && (
<VideoPreview urls={richContent.videos} />
)}
{richContent.links.length > 0 && <LinkPreview urls={richContent.links} />}
{richContent.notes.length > 0 &&
richContent.notes.map((note: string) => (
<MentionNote key={note} id={note} />
))}
</div>
</div>
)}
</div>
</div>
</div>
);
}

View File

@ -1,34 +0,0 @@
import { NDKEvent } from '@nostr-dev-kit/ndk';
import { useDecryptMessage } from '@app/chats/hooks/useDecryptMessage';
import { TextNote } from '@shared/notes';
import { User } from '@shared/user';
export function ChatMessageItem({
message,
userPubkey,
userPrivkey,
}: {
message: NDKEvent;
userPubkey: string;
userPrivkey: string;
}) {
const decryptedContent = useDecryptMessage(message, userPubkey, userPrivkey);
// if we have decrypted content, use it instead of the encrypted content
if (decryptedContent) {
message['content'] = decryptedContent;
}
return (
<div className="flex h-min min-h-min w-full select-text flex-col px-5 py-3 hover:bg-white/10">
<div className="flex flex-col">
<User pubkey={message.pubkey} time={message.created_at} variant="chat" />
<div className="-mt-5 flex items-start gap-3">
<div className="w-10 shrink-0" />
<TextNote content={message.content} />
</div>
</div>
</div>
);
}

View File

@ -3,16 +3,13 @@ import { useQuery } from '@tanstack/react-query';
import { useCallback } from 'react';
import { Outlet } from 'react-router-dom';
import { ChatListItem } from '@app/chats/components/item';
import { useStorage } from '@libs/storage/provider';
import { ChatListItem } from '@app/chats/components/chaListItem';
import { LoaderIcon } from '@shared/icons';
import { useNostr } from '@utils/hooks/useNostr';
export function ChatsScreen() {
const { db } = useStorage();
const { getAllNIP04Chats } = useNostr();
const { status, data } = useQuery(
['nip04-chats'],
@ -24,9 +21,7 @@ export function ChatsScreen() {
const renderItem = useCallback(
(event: NDKEvent) => {
if (db.account.pubkey !== event.pubkey) {
return <ChatListItem key={event.id} event={event} />;
}
},
[data]
);
@ -34,7 +29,10 @@ export function ChatsScreen() {
return (
<div className="grid h-full w-full grid-cols-3">
<div className="scrollbar-hide col-span-1 h-full overflow-y-auto border-r border-white/5">
<div className="h-16 w-full shrink-0 border-b border-white/5" />
<div
data-tauri-drag-region
className="h-16 w-full shrink-0 border-b border-white/5"
/>
<div className="flex h-full flex-col gap-1 py-2">
{status === 'loading' ? (
<div className="flex h-full w-full items-center justify-center pb-16">

View File

@ -50,15 +50,15 @@ input::-ms-clear {
}
.markdown {
@apply prose prose-white max-w-none select-text whitespace-pre-line text-white prose-headings:mb-1 prose-headings:mt-3 prose-p:mb-0 prose-p:mt-0 prose-p:last:mb-0 prose-a:font-normal hover:prose-a:text-fuchsia-500 prose-blockquote:mb-1 prose-blockquote:mt-1 prose-blockquote:border-l-[2px] prose-blockquote:border-fuchsia-500 prose-blockquote:pl-2 prose-pre:whitespace-pre-wrap prose-pre:break-words prose-pre:break-all prose-pre:bg-white/10 prose-ol:m-0 prose-ol:mb-1 prose-ul:mb-1 prose-ul:mt-1 prose-img:mb-2 prose-img:mt-3 prose-hr:mx-0 prose-hr:my-2;
@apply prose prose-white max-w-none select-text text-white prose-headings:mb-1 prose-headings:mt-3 prose-p:mb-0 prose-p:mt-0 prose-p:last:mb-0 prose-a:font-normal hover:prose-a:text-fuchsia-500 prose-blockquote:mb-1 prose-blockquote:mt-1 prose-blockquote:border-l-[2px] prose-blockquote:border-fuchsia-500 prose-blockquote:pl-2 prose-pre:whitespace-pre-wrap prose-pre:break-words prose-pre:break-all prose-pre:bg-white/10 prose-ol:m-0 prose-ol:mb-1 prose-ul:mb-1 prose-ul:mt-1 prose-img:mb-2 prose-img:mt-3 prose-hr:mx-0 prose-hr:my-2;
}
.markdown-article {
@apply prose prose-white max-w-none select-text whitespace-pre-line text-white/80 prose-headings:mb-1 prose-headings:mt-3 prose-headings:text-white prose-p:mb-2 prose-p:mt-0 prose-p:break-words prose-p:[word-break:break-word] prose-a:break-words prose-a:break-all prose-a:font-normal hover:prose-a:text-fuchsia-500 prose-blockquote:mb-1 prose-blockquote:mt-1 prose-blockquote:border-l-[2px] prose-blockquote:border-fuchsia-500 prose-blockquote:pl-2 prose-pre:whitespace-pre-wrap prose-pre:break-words prose-pre:break-all prose-pre:bg-white/10 prose-ol:m-0 prose-ol:mb-1 prose-ul:mb-1 prose-ul:mt-1 prose-img:mb-2 prose-img:mt-3 prose-hr:mx-0 prose-hr:my-2;
@apply prose prose-white max-w-none select-text text-white/80 prose-headings:mb-1 prose-headings:mt-3 prose-headings:text-white prose-p:mb-2 prose-p:mt-0 prose-p:break-words prose-p:[word-break:break-word] prose-a:break-words prose-a:break-all prose-a:font-normal hover:prose-a:text-fuchsia-500 prose-blockquote:mb-1 prose-blockquote:mt-1 prose-blockquote:border-l-[2px] prose-blockquote:border-fuchsia-500 prose-blockquote:pl-2 prose-pre:whitespace-pre-wrap prose-pre:break-words prose-pre:break-all prose-pre:bg-white/10 prose-ol:m-0 prose-ol:mb-1 prose-ul:mb-1 prose-ul:mt-1 prose-img:mb-2 prose-img:mt-3 prose-hr:mx-0 prose-hr:my-2;
}
.markdown-simple {
@apply prose prose-white max-w-none select-text hyphens-auto whitespace-pre-line text-white/70 prose-headings:mb-1 prose-headings:mt-3 prose-p:mb-0 prose-p:mt-0 prose-p:break-words prose-p:[word-break:break-word] prose-p:last:mb-0 prose-a:break-words prose-a:break-all prose-a:font-normal hover:prose-a:text-fuchsia-500 prose-blockquote:mb-1 prose-blockquote:mt-1 prose-blockquote:border-l-[2px] prose-blockquote:border-fuchsia-500 prose-blockquote:pl-2 prose-pre:whitespace-pre-wrap prose-pre:break-words prose-pre:break-all prose-pre:bg-white/10 prose-ol:m-0 prose-ol:mb-1 prose-ul:mb-1 prose-ul:mt-1 prose-img:mb-2 prose-img:mt-3 prose-hr:mx-0 prose-hr:my-2;
@apply prose prose-white max-w-none select-text hyphens-auto text-white/70 prose-headings:mb-1 prose-headings:mt-3 prose-p:mb-0 prose-p:mt-0 prose-p:break-words prose-p:[word-break:break-word] prose-p:last:mb-0 prose-a:break-words prose-a:break-all prose-a:font-normal hover:prose-a:text-fuchsia-500 prose-blockquote:mb-1 prose-blockquote:mt-1 prose-blockquote:border-l-[2px] prose-blockquote:border-fuchsia-500 prose-blockquote:pl-2 prose-pre:whitespace-pre-wrap prose-pre:break-words prose-pre:break-all prose-pre:bg-white/10 prose-ol:m-0 prose-ol:mb-1 prose-ul:mb-1 prose-ul:mt-1 prose-img:mb-2 prose-img:mt-3 prose-hr:mx-0 prose-hr:my-2;
}
.ProseMirror p.is-empty::before {

View File

@ -5,7 +5,6 @@ import { message } from '@tauri-apps/api/dialog';
import { QRCodeSVG } from 'qrcode.react';
import { useEffect, useRef, useState } from 'react';
import CurrencyInput from 'react-currency-input-field';
import TextareaAutosize from 'react-textarea-autosize';
import { CancelIcon, ZapIcon } from '@shared/icons';
@ -99,7 +98,7 @@ export function NoteZap({ id, pubkey }: { id: string; pubkey: string }) {
<ZapIcon className="h-5 w-5 text-white/80 group-hover:text-orange-400" />
</button>
</Dialog.Trigger>
<Dialog.Portal className="relative z-10">
<Dialog.Portal>
<Dialog.Overlay className="fixed inset-0 z-50 bg-black/80 backdrop-blur-2xl" />
<Dialog.Content className="fixed inset-0 z-50 flex min-h-full items-center justify-center">
<div className="relative h-min w-full max-w-xl rounded-xl bg-white/10 backdrop-blur-xl">
@ -171,7 +170,7 @@ export function NoteZap({ id, pubkey }: { id: string; pubkey: string }) {
</div>
</div>
<div className="mt-4 flex w-full flex-col gap-2">
<TextareaAutosize
<input
name="zapMessage"
value={zapMessage}
onChange={(e) => setZapMessage(e.target.value)}

View File

@ -1,5 +1,10 @@
import { NDKEvent } from '@nostr-dev-kit/ndk';
import { MediaPlayer, MediaProvider } from '@vidstack/react';
import { MediaPlayer, MediaProvider, Poster } from '@vidstack/react';
import {
DefaultAudioLayout,
DefaultVideoLayout,
defaultLayoutIcons,
} from '@vidstack/react/player/layouts/default';
import { Link } from 'react-router-dom';
import { Image } from '@shared/image';
@ -31,9 +36,27 @@ export function FileNote(props: { event?: NDKEvent }) {
poster={`https://thumbnail.video/api/get?url=${url}&seconds=1`}
load="visible"
aspectRatio="16/9"
muted={true}
crossorigin=""
className="player"
>
<MediaProvider />
<MediaProvider>
<Poster
className="vds-poster"
src="https://thumbnail.video/api/get?url=${url}&seconds=1"
alt={url}
/>
</MediaProvider>
<DefaultAudioLayout
icons={defaultLayoutIcons}
smallLayoutWhen="(width < 500) or (height < 380)"
noModal={true}
/>
<DefaultVideoLayout
icons={defaultLayoutIcons}
smallLayoutWhen="(width < 500) or (height < 380)"
noModal={true}
/>
</MediaPlayer>
</div>
);

View File

@ -7,7 +7,7 @@ export function Hashtag({ tag }: { tag: string }) {
const setWidget = useWidgets((state) => state.setWidget);
return (
<span
<div
role="button"
tabIndex={0}
onClick={() =>
@ -24,9 +24,9 @@ export function Hashtag({ tag }: { tag: string }) {
content: tag.replace('#', ''),
})
}
className="break-words text-fuchsia-400 hover:text-fuchsia-500"
className="break-all text-fuchsia-400 hover:text-fuchsia-500"
>
{tag}
</span>
</div>
);
}

View File

@ -15,6 +15,7 @@ export function VideoPreview({ urls }: { urls: string[] }) {
load="visible"
aspectRatio="16/9"
crossorigin=""
muted={true}
className="player"
>
<MediaProvider>
@ -24,8 +25,16 @@ export function VideoPreview({ urls }: { urls: string[] }) {
alt={url}
/>
</MediaProvider>
<DefaultAudioLayout icons={defaultLayoutIcons} />
<DefaultVideoLayout icons={defaultLayoutIcons} />
<DefaultAudioLayout
icons={defaultLayoutIcons}
smallLayoutWhen="(width < 500) or (height < 380)"
noModal={true}
/>
<DefaultVideoLayout
icons={defaultLayoutIcons}
smallLayoutWhen="(width < 500) or (height < 380)"
noModal={true}
/>
</MediaPlayer>
))}
</div>