mirror of
https://github.com/d0zingcat/NotionNext.git
synced 2026-05-14 07:26:52 +00:00
Merge pull request #2256 from tangly1024/feat/decoration-of-theme-game
Feat/decoration of theme game
This commit is contained in:
167
themes/game/components/GameEmbed.js
Normal file
167
themes/game/components/GameEmbed.js
Normal file
@@ -0,0 +1,167 @@
|
||||
/* eslint-disable @next/next/no-img-element */
|
||||
import { Draggable } from '@/components/Draggable'
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import { deepClone } from '@/lib/utils'
|
||||
import Link from 'next/link'
|
||||
import { useEffect, useState } from 'react'
|
||||
import DownloadButton from './DownloadButton'
|
||||
import FullScreenButton from './FullScreenButton'
|
||||
|
||||
/**
|
||||
* 嵌入游戏
|
||||
* @param {*} param0
|
||||
* @returns
|
||||
*/
|
||||
export default function GameEmbed({ post, siteInfo }) {
|
||||
const game = deepClone(post)
|
||||
const newWindow = game?.ext?.new_window || false
|
||||
const originUrl = game?.ext?.href
|
||||
|
||||
// 提示用户在新窗口打开
|
||||
const [tipNewWindow, setTipNewWindow] = useState(newWindow)
|
||||
const [url, setUrl] = useState(originUrl)
|
||||
const [loading, setLoading] = useState(true)
|
||||
|
||||
/**
|
||||
* 新窗口中打开
|
||||
*/
|
||||
const openInNewWindow = () => {
|
||||
setTipNewWindow(false)
|
||||
setTimeout(function () {
|
||||
setUrl('')
|
||||
setUrl(originUrl)
|
||||
}, 10000) // 10000毫秒 = 10秒
|
||||
}
|
||||
|
||||
// 将当前游戏加入到最近游玩
|
||||
useEffect(() => {
|
||||
setUrl(originUrl)
|
||||
|
||||
const iframe = document.getElementById('game-wrapper')
|
||||
|
||||
// 定义一个函数来处理iframe加载成功事件
|
||||
function iframeLoaded() {
|
||||
if (game) {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
// 绑定加载事件
|
||||
if (iframe?.attachEvent) {
|
||||
iframe?.attachEvent('onload', iframeLoaded)
|
||||
} else if (iframe) {
|
||||
iframe.onload = iframeLoaded
|
||||
}
|
||||
|
||||
// 更改iFrame的title
|
||||
if (
|
||||
document
|
||||
?.getElementById('game-wrapper')
|
||||
?.contentDocument.querySelector('title')?.textContent
|
||||
) {
|
||||
document
|
||||
.getElementById('game-wrapper')
|
||||
.contentDocument.querySelector('title').textContent = `${
|
||||
game?.title || ''
|
||||
} - Play ${game?.title || ''} on ${siteConfig('TITLE')}`
|
||||
}
|
||||
}, [game])
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`${url ? '' : 'hidden'} bg-black w-full xl:h-[calc(100vh-8rem)] h-screen rounded-md relative`}>
|
||||
{/* 移动端返回主页按钮 */}
|
||||
<Draggable stick='left'>
|
||||
<div
|
||||
style={{ left: '0px', top: '1rem' }}
|
||||
className='fixed xl:hidden group space-x-1 flex items-center z-20 pr-3 pl-1 bg-[#202030] rounded-r-2xl shadow-lg '>
|
||||
<Link
|
||||
href='/'
|
||||
className='px-1 py-3 hover:scale-125 duration-200 transition-all'
|
||||
passHref>
|
||||
<i className='fas fa-arrow-left' />
|
||||
</Link>{' '}
|
||||
<span
|
||||
className='text-white font-serif'
|
||||
onClick={() => {
|
||||
document.querySelector('.game-info').scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'end',
|
||||
inline: 'nearest'
|
||||
})
|
||||
}}>
|
||||
{/* Title首字母 */}
|
||||
{siteInfo?.title?.charAt(0)}
|
||||
</span>
|
||||
</div>
|
||||
</Draggable>
|
||||
|
||||
{/* 提示框新窗口打开 */}
|
||||
{tipNewWindow && (
|
||||
<div
|
||||
id='open-tips'
|
||||
className={`animate__animated animate__fadeIn bottom-8 right-4 absolute z-20 flex items-end justify-end`}>
|
||||
<div className='relative w-80 h-auto bg-white rounded-lg p-2'>
|
||||
<div className='absolute right-2'>
|
||||
<button
|
||||
className='text-xl p-2'
|
||||
onClick={() => {
|
||||
setTipNewWindow(false)
|
||||
}}>
|
||||
<i className='fas fa-times'></i>
|
||||
</button>
|
||||
</div>
|
||||
<div className='p-2'>
|
||||
If the game fails to load, please try accessing the{' '}
|
||||
<a
|
||||
className='underline text-blue-500'
|
||||
rel='noReferrer'
|
||||
href={`${url?.replace('/games-external/common/index.htm?n=', '')}`}
|
||||
target='_blank'
|
||||
onClick={openInNewWindow}>
|
||||
source webpage
|
||||
</a>
|
||||
.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Loading遮罩 */}
|
||||
{loading && (
|
||||
<div className='absolute z-20 w-full xl:h-[calc(100vh-8rem)] h-screen rounded-md overflow-hidden '>
|
||||
<div className='z-20 absolute bg-black bg-opacity-75 w-full h-full flex flex-col gap-4 justify-center items-center'>
|
||||
<h2 className='text-3xl text-white flex gap-2 items-center'>
|
||||
<i className='fas fa-spinner animate-spin'></i>
|
||||
{siteInfo?.title || siteConfig('TITLE')}
|
||||
</h2>
|
||||
<h3 className='text-xl text-white'>
|
||||
{siteInfo?.description || siteConfig('DESCRIPTION')}
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
{/* 游戏封面图 */}
|
||||
{game?.pageCoverThumbnail && (
|
||||
<img
|
||||
src={game?.pageCoverThumbnail}
|
||||
className='w-full h-full object-cover blur-md absolute top-0 left-0 z-0'
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<iframe
|
||||
id='game-wrapper'
|
||||
src={url}
|
||||
className={`relative w-full xl:h-[calc(100vh-8rem)] h-screen md:rounded-md overflow-hidden`}
|
||||
/>
|
||||
|
||||
{/* 游戏窗口装饰器 */}
|
||||
{url && !loading && (
|
||||
<div className='game-decorator bg-[#0B0D14] right-0 bottom-0 flex justify-center z-10 md:absolute'>
|
||||
<DownloadButton />
|
||||
<FullScreenButton />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -33,7 +33,7 @@ export const GameListRecent = ({ maxCount = 14 }) => {
|
||||
return (
|
||||
<>
|
||||
<div className='game-list-recent-wrapper w-full max-w-full overflow-x-auto pt-4 px-2'>
|
||||
<div className='game-grid flex gap-2'>
|
||||
<div className='game-grid md:flex grid grid-flow-col gap-2'>
|
||||
{components?.map((ItemComponent, index) => {
|
||||
return ItemComponent
|
||||
})}
|
||||
|
||||
@@ -5,12 +5,12 @@ import Logo from './Logo'
|
||||
* 顶栏
|
||||
* @returns
|
||||
*/
|
||||
export default function Header() {
|
||||
export default function Header({ siteInfo }) {
|
||||
const { setSideBarVisible } = useGameGlobal()
|
||||
return (
|
||||
<header className='z-20'>
|
||||
<div className='w-full h-16 rounded-md bg-white shadow-md hover:shadow-xl transition-shadow duration-200 dark:bg-[#1F2030] flex justify-between items-center px-4'>
|
||||
<Logo />
|
||||
<Logo siteInfo={siteInfo} />
|
||||
|
||||
<button
|
||||
className='flex xl:hidden'
|
||||
|
||||
@@ -2,12 +2,19 @@ import { siteConfig } from '@/lib/config'
|
||||
import Link from 'next/link'
|
||||
|
||||
/* eslint-disable @next/next/no-html-link-for-pages */
|
||||
export default function Logo() {
|
||||
export default function Logo({ siteInfo }) {
|
||||
return (
|
||||
<Link passHref href='/' className='logo rounded cursor-pointer flex flex-col items-center'>
|
||||
<Link
|
||||
passHref
|
||||
href='/'
|
||||
className='logo rounded cursor-pointer flex flex-col items-center'>
|
||||
<div className='w-full'>
|
||||
<h1 className='text-2xl dark:text-white font-bold font-serif'>{siteConfig('TITLE')}</h1>
|
||||
<h2 className='text-xs text-gray-400 whitespace-nowrap'>{siteConfig('BIO')}</h2>
|
||||
<h1 className='text-2xl dark:text-white font-bold font-serif'>
|
||||
{siteInfo?.title}
|
||||
</h1>
|
||||
<h2 className='text-xs text-gray-400 whitespace-nowrap'>
|
||||
{siteConfig('BIO')}
|
||||
</h2>
|
||||
</div>
|
||||
</Link>
|
||||
)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/* eslint-disable @next/next/no-img-element */
|
||||
import Comment from '@/components/Comment'
|
||||
import { Draggable } from '@/components/Draggable'
|
||||
import { AdSlot } from '@/components/GoogleAdsense'
|
||||
import replaceSearchResult from '@/components/Mark'
|
||||
import NotionPage from '@/components/NotionPage'
|
||||
@@ -17,9 +16,8 @@ import BlogArchiveItem from './components/BlogArchiveItem'
|
||||
import { BlogListPage } from './components/BlogListPage'
|
||||
import { BlogListScroll } from './components/BlogListScroll'
|
||||
import BlogPostBar from './components/BlogPostBar'
|
||||
import DownloadButton from './components/DownloadButton'
|
||||
import { Footer } from './components/Footer'
|
||||
import FullScreenButton from './components/FullScreenButton'
|
||||
import GameEmbed from './components/GameEmbed'
|
||||
import { GameListIndexCombine } from './components/GameListIndexCombine'
|
||||
import { GameListRelate } from './components/GameListRealate'
|
||||
import { GameListRecent } from './components/GameListRecent'
|
||||
@@ -46,7 +44,7 @@ export const useGameGlobal = () => useContext(ThemeGlobalGame)
|
||||
* @constructor
|
||||
*/
|
||||
const LayoutBase = props => {
|
||||
const { allNavPages, children } = props
|
||||
const { allNavPages, children, siteInfo } = props
|
||||
const searchModal = useRef(null)
|
||||
// 在列表中进行实时过滤
|
||||
const [filterKey, setFilterKey] = useState('')
|
||||
@@ -99,7 +97,7 @@ const LayoutBase = props => {
|
||||
<div className='py-4 px-2 sticky top-0 h-screen flex flex-col justify-between'>
|
||||
<div className='select-none'>
|
||||
{/* 抬头logo等 */}
|
||||
<Header />
|
||||
<Header siteInfo={siteInfo} />
|
||||
{/* 菜单栏 */}
|
||||
<MenuList {...props} />
|
||||
</div>
|
||||
@@ -277,61 +275,29 @@ const LayoutArchive = props => {
|
||||
const LayoutSlug = props => {
|
||||
const { post, siteInfo, allNavPages, recommendPosts, lock, validPassword } =
|
||||
props
|
||||
const game = deepClone(post)
|
||||
const [loading, setLoading] = useState(true)
|
||||
const url = game?.ext?.href
|
||||
|
||||
const relateGames = recommendPosts
|
||||
const randomGames = shuffleArray(deepClone(allNavPages))
|
||||
|
||||
// 初始化可安装应用
|
||||
initialPWA(game, siteInfo)
|
||||
initialPWA(post, siteInfo)
|
||||
|
||||
// 将当前游戏加入到最近游玩
|
||||
useEffect(() => {
|
||||
// 更新最新游戏
|
||||
const recentGames = localStorage.getItem('recent_games')
|
||||
? JSON.parse(localStorage.getItem('recent_games'))
|
||||
: []
|
||||
|
||||
const existedIndex = recentGames.findIndex(item => item?.id === game?.id)
|
||||
const existedIndex = recentGames.findIndex(item => item?.id === post?.id)
|
||||
if (existedIndex === -1) {
|
||||
recentGames.unshift(game) // 将游戏插入到数组头部
|
||||
recentGames.unshift(post) // 将游戏插入到数组头部
|
||||
} else {
|
||||
// 如果游戏已存在于数组中,将其移至数组头部
|
||||
const existingGame = recentGames.splice(existedIndex, 1)[0]
|
||||
recentGames.unshift(existingGame)
|
||||
}
|
||||
localStorage.setItem('recent_games', JSON.stringify(recentGames))
|
||||
|
||||
const iframe = document.getElementById('game-wrapper')
|
||||
|
||||
// 定义一个函数来处理iframe加载成功事件
|
||||
function iframeLoaded() {
|
||||
if (game) {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
// 绑定加载事件
|
||||
if (iframe?.attachEvent) {
|
||||
iframe?.attachEvent('onload', iframeLoaded)
|
||||
} else {
|
||||
if (iframe) iframe.onload = iframeLoaded
|
||||
}
|
||||
|
||||
// 更改iFrame的title
|
||||
if (
|
||||
document
|
||||
?.getElementById('game-wrapper')
|
||||
?.contentDocument.querySelector('title')?.textContent
|
||||
) {
|
||||
document
|
||||
.getElementById('game-wrapper')
|
||||
.contentDocument.querySelector('title').textContent = `${
|
||||
game?.title || ''
|
||||
} - Play ${game?.title || ''} on ${siteConfig('TITLE')}`
|
||||
}
|
||||
}, [game])
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -339,89 +305,28 @@ const LayoutSlug = props => {
|
||||
|
||||
{!lock && (
|
||||
<div id='article-wrapper' className='md:px-2'>
|
||||
{/* 游戏区域 */}
|
||||
<div className='game-detail-wrapper w-full grow flex md:px-2'>
|
||||
{/* 移动端返回主页按钮 */}
|
||||
<Draggable stick='left'>
|
||||
<div
|
||||
style={{ left: '0px', top: '1rem' }}
|
||||
className='fixed xl:hidden group space-x-1 flex items-center z-20 pr-3 pl-1 bg-[#202030] rounded-r-2xl shadow-lg '>
|
||||
<Link
|
||||
href='/'
|
||||
className='px-1 py-3 hover:scale-125 duration-200 transition-all'
|
||||
passHref>
|
||||
<i className='fas fa-arrow-left' />
|
||||
</Link>{' '}
|
||||
<span
|
||||
className='text-white font-serif'
|
||||
onClick={() => {
|
||||
document.querySelector('.game-info').scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'end',
|
||||
inline: 'nearest'
|
||||
})
|
||||
}}>
|
||||
G
|
||||
</span>
|
||||
</div>
|
||||
</Draggable>
|
||||
|
||||
<div className={`w-full py-1 md:py-4 `}>
|
||||
{/* 游戏区 */}
|
||||
<div
|
||||
className={`${url ? '' : 'hidden'} bg-black w-full xl:h-[calc(100vh-8rem)] h-screen rounded-md relative`}>
|
||||
{/* Loading遮罩 */}
|
||||
{loading && (
|
||||
<div className='absolute z-20 w-full xl:h-[calc(100vh-8rem)] h-screen rounded-md overflow-hidden '>
|
||||
<div className='z-20 absolute bg-black bg-opacity-75 w-full h-full flex flex-col gap-4 justify-center items-center'>
|
||||
<h2 className='text-3xl text-white flex gap-2 items-center'>
|
||||
<i className='fas fa-spinner animate-spin'></i>
|
||||
{siteInfo?.title || siteConfig('TITLE')}
|
||||
</h2>
|
||||
<h3 className='text-xl text-white'>
|
||||
{siteInfo?.description || siteConfig('DESCRIPTION')}
|
||||
</h3>
|
||||
</div>
|
||||
{/* 游戏窗口 */}
|
||||
<GameEmbed post={post} siteInfo={siteInfo} />
|
||||
|
||||
{/* 游戏封面图 */}
|
||||
{game?.pageCoverThumbnail && (
|
||||
<img
|
||||
src={game?.pageCoverThumbnail}
|
||||
className='w-full h-full object-cover blur-md absolute top-0 left-0 z-0'
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<iframe
|
||||
id='game-wrapper'
|
||||
src={url}
|
||||
className={`relative w-full xl:h-[calc(100vh-8rem)] h-screen md:rounded-md overflow-hidden`}
|
||||
/>
|
||||
|
||||
{/* 游戏窗口装饰器 */}
|
||||
{game && !loading && (
|
||||
<div className='game-decorator bg-[#0B0D14] right-0 bottom-0 flex justify-center z-10 md:absolute'>
|
||||
<DownloadButton />
|
||||
<FullScreenButton />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 游戏资讯 */}
|
||||
{/* 资讯 */}
|
||||
<div className='game-info dark:text-white py-4 px-2 md:px-0 mt-14 md:mt-0'>
|
||||
{/* 关联游戏 */}
|
||||
<div className='w-full'>
|
||||
<GameListRelate posts={relateGames} />
|
||||
</div>
|
||||
|
||||
{game && (
|
||||
{/* 详情描述 */}
|
||||
{post && (
|
||||
<div className='bg-white shadow-md my-2 p-2 rounded-md dark:bg-black'>
|
||||
<PostInfo post={post} />
|
||||
<NotionPage post={post} />
|
||||
{/* 广告嵌入 */}
|
||||
<AdSlot />
|
||||
{/* 分享栏目 */}
|
||||
<ShareBar post={post} />
|
||||
{/* 评论区 */}
|
||||
<Comment frontMatter={post} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user