feat: forum rich-text editor, emoji picker, mentions, discover nav, feed, uploads, profile
Forum: - TipTap WYSIWYG editor with full toolbar - @emoji-mart/react emoji picker (consistent with tweets) - @mention autocomplete with user search API - Fix PHP 8.4 parse errors in Blade templates - Fix thread data display (paginator items) - Align forum page widths to max-w-5xl Discover: - Extract shared _nav.blade.php partial - Add missing nav links to for-you page - Add Following link for authenticated users Feed/Posts: - Post model, controllers, policies, migrations - Feed page components (PostComposer, FeedCard, etc) - Post reactions, comments, saves, reports, sharing - Scheduled publishing support - Link preview controller Profile: - Profile page components (ProfileHero, ProfileTabs) - Profile API controller Uploads: - Upload wizard enhancements - Scheduled publish picker - Studio status bar and readiness checklist
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import React, { lazy, Suspense, useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { createPortal } from 'react-dom'
|
||||
import ShareToast from '../ui/ShareToast'
|
||||
|
||||
// Lazy-load the Feed share modal so artwork pages don't bundle the feed layer unless needed
|
||||
const FeedShareArtworkModal = lazy(() => import('../Feed/ShareArtworkModal'))
|
||||
|
||||
/* ── Platform share URLs ─────────────────────────────────────────────────── */
|
||||
function facebookUrl(url) {
|
||||
return `https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(url)}`
|
||||
@@ -107,13 +110,14 @@ function trackShare(artworkId, platform) {
|
||||
* artwork – artwork object (id, title, description, thumbs, canonical_url, …)
|
||||
* shareUrl – canonical share URL
|
||||
*/
|
||||
export default function ArtworkShareModal({ open, onClose, artwork, shareUrl }) {
|
||||
export default function ArtworkShareModal({ open, onClose, artwork, shareUrl, isLoggedIn = false }) {
|
||||
const backdropRef = useRef(null)
|
||||
const [linkCopied, setLinkCopied] = useState(false)
|
||||
const [embedCopied, setEmbedCopied] = useState(false)
|
||||
const [showEmbed, setShowEmbed] = useState(false)
|
||||
const [toastVisible, setToastVisible] = useState(false)
|
||||
const [toastMessage, setToastMessage] = useState('')
|
||||
const [profileShareOpen, setProfileShareOpen] = useState(false)
|
||||
|
||||
const url = shareUrl || artwork?.canonical_url || (typeof window !== 'undefined' ? window.location.href : '#')
|
||||
const title = artwork?.title || 'Artwork'
|
||||
@@ -213,6 +217,12 @@ export default function ArtworkShareModal({ open, onClose, artwork, shareUrl })
|
||||
onClick: () => { window.location.href = emailUrl(url, title); trackShare(artwork?.id, 'email') },
|
||||
className: 'border-white/[0.08] bg-white/[0.04] text-white/70 hover:border-white/[0.15] hover:bg-white/[0.07] hover:text-white',
|
||||
},
|
||||
...(isLoggedIn ? [{
|
||||
label: 'My Profile',
|
||||
icon: <i className="fa-solid fa-share-nodes h-5 w-5 text-[1.1rem]" />,
|
||||
onClick: () => setProfileShareOpen(true),
|
||||
className: 'border-sky-500/30 bg-sky-500/10 text-sky-400 hover:border-sky-400/50 hover:bg-sky-500/20',
|
||||
}] : []),
|
||||
]
|
||||
|
||||
return createPortal(
|
||||
@@ -330,6 +340,26 @@ export default function ArtworkShareModal({ open, onClose, artwork, shareUrl })
|
||||
visible={toastVisible}
|
||||
onHide={() => setToastVisible(false)}
|
||||
/>
|
||||
|
||||
{/* Share to Profile (Feed) modal — lazy loaded */}
|
||||
{profileShareOpen && (
|
||||
<Suspense fallback={null}>
|
||||
<FeedShareArtworkModal
|
||||
isOpen={profileShareOpen}
|
||||
onClose={() => setProfileShareOpen(false)}
|
||||
preselectedArtwork={artwork?.id ? {
|
||||
id: artwork.id,
|
||||
title: artwork.title,
|
||||
thumb_url: artwork.thumbs?.md?.url ?? artwork.thumbs?.lg?.url ?? null,
|
||||
user: artwork.user ?? null,
|
||||
} : null}
|
||||
onShared={() => {
|
||||
setProfileShareOpen(false)
|
||||
showToast('Shared to your profile!')
|
||||
}}
|
||||
/>
|
||||
</Suspense>
|
||||
)}
|
||||
</>,
|
||||
document.body,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user