This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { ArrowLeft, CircleHelp, Loader2, RotateCcw } from 'lucide-react';
|
||||
import { ArrowLeft, CircleHelp, Loader2, RotateCcw, Share2 } from 'lucide-react';
|
||||
import { type PointerEvent, useEffect, useRef, useState } from 'react';
|
||||
|
||||
import type {
|
||||
@@ -7,6 +7,8 @@ import type {
|
||||
BigFishRuntimeSnapshotResponse,
|
||||
SubmitBigFishInputRequest,
|
||||
} from '../../../packages/shared/src/contracts/bigFish';
|
||||
import { buildPublicWorkStagePath } from '../../routing/appPageRoutes';
|
||||
import { copyTextToClipboard } from '../../services/clipboard';
|
||||
import { UnifiedModal } from '../common/UnifiedModal';
|
||||
import { ResolvedAssetImage } from '../ResolvedAssetImage';
|
||||
|
||||
@@ -21,6 +23,8 @@ type TouchSample = TouchOrigin;
|
||||
type BigFishRuntimeShellProps = {
|
||||
run: BigFishRuntimeSnapshotResponse | null;
|
||||
assetSlots?: BigFishAssetSlotResponse[];
|
||||
shareTitle?: string | null;
|
||||
sharePublicWorkCode?: string | null;
|
||||
isBusy?: boolean;
|
||||
error?: string | null;
|
||||
onBack: () => void;
|
||||
@@ -219,6 +223,8 @@ function BigFishEntityDot({
|
||||
export function BigFishRuntimeShell({
|
||||
run,
|
||||
assetSlots = [],
|
||||
shareTitle = null,
|
||||
sharePublicWorkCode = null,
|
||||
isBusy = false,
|
||||
error = null,
|
||||
onBack,
|
||||
@@ -230,6 +236,9 @@ export function BigFishRuntimeShell({
|
||||
const currentTouchRef = useRef<TouchSample | null>(null);
|
||||
const lastTouchSampleRef = useRef<TouchSample | null>(null);
|
||||
const [isRuleModalOpen, setIsRuleModalOpen] = useState(false);
|
||||
const [shareState, setShareState] = useState<'idle' | 'copied' | 'failed'>(
|
||||
'idle',
|
||||
);
|
||||
const [stick, setStick] = useState({ x: 0, y: 0 });
|
||||
const stickRef = useRef(stick);
|
||||
|
||||
@@ -282,6 +291,28 @@ export function BigFishRuntimeShell({
|
||||
setStick(direction);
|
||||
onSubmitInput(direction);
|
||||
};
|
||||
const sharePublicWork = () => {
|
||||
const publicWorkCode = sharePublicWorkCode?.trim();
|
||||
if (!publicWorkCode) {
|
||||
return;
|
||||
}
|
||||
|
||||
const sharePath = buildPublicWorkStagePath(
|
||||
'big-fish-runtime',
|
||||
publicWorkCode,
|
||||
);
|
||||
const shareUrl =
|
||||
typeof window === 'undefined'
|
||||
? sharePath
|
||||
: new URL(sharePath, window.location.origin).href;
|
||||
const title = shareTitle?.trim() || '大鱼吃小鱼';
|
||||
const shareText = `邀请你来玩《${title}》\n作品号:${publicWorkCode}\n${shareUrl}`;
|
||||
|
||||
void copyTextToClipboard(shareText).then((copied) => {
|
||||
setShareState(copied ? 'copied' : 'failed');
|
||||
window.setTimeout(() => setShareState('idle'), 1400);
|
||||
});
|
||||
};
|
||||
|
||||
const beginTouchControl = (event: PointerEvent<HTMLDivElement>) => {
|
||||
if (event.target instanceof HTMLElement && event.target.closest('button')) {
|
||||
@@ -373,6 +404,29 @@ export function BigFishRuntimeShell({
|
||||
<ArrowLeft className="h-4 w-4" />
|
||||
</button>
|
||||
<div className="flex items-center gap-2">
|
||||
{sharePublicWorkCode?.trim() ? (
|
||||
<button
|
||||
type="button"
|
||||
aria-label={
|
||||
shareState === 'copied'
|
||||
? '分享内容已复制'
|
||||
: shareState === 'failed'
|
||||
? '分享内容复制失败'
|
||||
: '分享作品'
|
||||
}
|
||||
title={
|
||||
shareState === 'copied'
|
||||
? '已复制'
|
||||
: shareState === 'failed'
|
||||
? '复制失败'
|
||||
: '分享作品'
|
||||
}
|
||||
onClick={sharePublicWork}
|
||||
className="pointer-events-auto inline-flex h-10 w-10 items-center justify-center rounded-full bg-black/28 text-white backdrop-blur"
|
||||
>
|
||||
<Share2 className="h-4 w-4" />
|
||||
</button>
|
||||
) : null}
|
||||
<button
|
||||
type="button"
|
||||
aria-label="查看规则"
|
||||
|
||||
Reference in New Issue
Block a user