Files
SkinbaseNova/resources/js/components/artwork/ArtworkShareButton.jsx
Gregor Klevze dc51d65440 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
2026-03-03 09:48:31 +01:00

79 lines
2.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React, { lazy, Suspense, useCallback, useState } from 'react'
import useWebShare from '../../hooks/useWebShare'
const ArtworkShareModal = lazy(() => import('./ArtworkShareModal'))
/* ── Share icon (lucide-style) ───────────────────────────────────────────── */
function ShareIcon() {
return (
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="h-5 w-5">
<path strokeLinecap="round" strokeLinejoin="round" d="M8.684 13.342C8.886 12.938 9 12.482 9 12c0-.482-.114-.938-.316-1.342m0 2.684a3 3 0 1 1 0-2.684m0 2.684 6.632 3.316m-6.632-6 6.632-3.316m0 0a3 3 0 1 0 5.367-2.684 3 3 0 0 0-5.367 2.684Zm0 9.316a3 3 0 1 0 5.368 2.684 3 3 0 0 0-5.368-2.684Z" />
</svg>
)
}
/**
* ArtworkShareButton renders the Share pill and manages modal / native share.
*
* Props:
* artwork artwork object
* shareUrl canonical URL to share
* size 'default' | 'small' (for mobile bar)
*/
export default function ArtworkShareButton({ artwork, shareUrl, size = 'default', isLoggedIn = false }) {
const [modalOpen, setModalOpen] = useState(false)
const openModal = useCallback(
() => setModalOpen(true),
[],
)
const closeModal = useCallback(
() => setModalOpen(false),
[],
)
const { share } = useWebShare({ onFallback: openModal })
const handleClick = () => {
share({
title: artwork?.title || 'Artwork',
text: artwork?.description?.substring(0, 120) || '',
url: shareUrl || artwork?.canonical_url || window.location.href,
})
}
const isSmall = size === 'small'
return (
<>
<button
type="button"
aria-label="Share artwork"
onClick={handleClick}
className={
isSmall
? 'inline-flex items-center gap-1.5 rounded-full border border-white/[0.08] bg-white/[0.04] px-3.5 py-2 text-xs font-medium text-white/70 transition-all hover:border-white/[0.15] hover:bg-white/[0.07] hover:text-white'
: 'group inline-flex items-center gap-2 rounded-full border border-white/[0.08] bg-white/[0.04] px-5 py-2.5 text-sm font-medium text-white/70 transition-all duration-200 hover:border-white/[0.15] hover:bg-white/[0.07] hover:text-white hover:shadow-lg hover:shadow-white/[0.03]'
}
title="Share"
>
<ShareIcon />
{!isSmall && <span>Share</span>}
</button>
{/* Lazy-loaded modal only rendered when opened */}
{modalOpen && (
<Suspense fallback={null}>
<ArtworkShareModal
open={modalOpen}
onClose={closeModal}
artwork={artwork}
shareUrl={shareUrl}
isLoggedIn={isLoggedIn}
/>
</Suspense>
)}
</>
)
}