Compare commits

..

4 Commits

10 changed files with 436 additions and 232 deletions

View File

@ -1,4 +1,4 @@
import React, { useContext, useState } from "react";
import React, { useContext, useState, useRef } from "react";
// import { exportComponentAsPNG } from "react-component-export-image";
import "./CoverImage.css";
import { ImgContext } from "../utils/ImgContext";
@ -10,70 +10,167 @@ const ComponentToImg = (props) => {
const [loading, setLoading] = useState(false)
const { unsplashImage } = useContext(ImgContext);
const componentRef = React.createRef();
const componentRef = useRef(null);
async function saveImage(data) {
var a = document.createElement("A");
a.href = data;
a.download = `cover.png`;
document.body.appendChild(a);
setLoading(false)
a.click();
document.body.removeChild(a);
}
const downloadImage = async () => {
// exportComponentAsPNG(componentRef, 'cover')
setLoading(true)
const element = componentRef.current;
// console.log(element)
// console.log(element.offsetHeight)
let data = await domtoimage.toPng(componentRef.current, {
height: element.offsetHeight * 2,
width: element.offsetWidth * 2,
style: {
transform: "scale(" + 2 + ")",
transformOrigin: "top left",
width: element.offsetWidth + "px",
height: element.offsetHeight + "px",
}
})
// console.log(data)
await saveImage(data);
if (unsplashImage) {
unsplash.photos.trackDownload({ downloadLocation: unsplashImage.downloadLink, });
try {
var a = document.createElement("A");
a.href = data;
a.download = `cover.png`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
} catch (error) {
console.error('保存图片失败:', error);
alert('下载失败,请重试');
} finally {
setLoading(false);
}
}
const downloadImage = async () => {
try {
setLoading(true);
// 等待一小段时间确保组件完全渲染
await new Promise(resolve => setTimeout(resolve, 100));
const element = componentRef.current;
if (!element) {
throw new Error('无法找到要下载的元素,请稍后重试');
}
// 检查元素是否在DOM中且可见
if (!document.body.contains(element)) {
throw new Error('元素不在DOM中');
}
if (element.offsetWidth === 0 || element.offsetHeight === 0) {
throw new Error('元素尺寸为0请等待页面完全加载');
}
// 等待所有图片加载完成
const images = element.querySelectorAll('img');
console.log(`等待 ${images.length} 张图片加载完成...`);
await Promise.all(Array.from(images).map((img, index) => {
if (img.complete && img.naturalWidth > 0) {
console.log(`图片 ${index + 1} 已加载`);
return Promise.resolve();
}
return new Promise((resolve) => {
const timeout = setTimeout(() => {
console.warn(`图片 ${index + 1} 加载超时:`, img.src);
resolve();
}, 8000);
img.onload = () => {
console.log(`图片 ${index + 1} 加载完成`);
clearTimeout(timeout);
resolve();
};
img.onerror = () => {
console.warn(`图片 ${index + 1} 加载失败:`, img.src);
clearTimeout(timeout);
resolve();
};
// 如果图片已经加载但事件没触发
if (img.complete) {
clearTimeout(timeout);
resolve();
}
});
}));
console.log('所有图片处理完成开始生成PNG...');
// 再次确认元素状态
if (!componentRef.current) {
throw new Error('DOM元素在处理过程中丢失');
}
// 使用更保守的配置
const options = {
height: element.offsetHeight * 2,
width: element.offsetWidth * 2,
style: {
transform: "scale(2)",
transformOrigin: "top left",
width: element.offsetWidth + "px",
height: element.offsetHeight + "px",
},
// 添加过滤器,跳过可能有问题的节点
filter: (node) => {
// 跳过脚本标签和样式标签
if (node.tagName === 'SCRIPT' || node.tagName === 'STYLE') {
return false;
}
// 跳过隐藏元素
if (node.style && node.style.display === 'none') {
return false;
}
return true;
}
};
const data = await domtoimage.toPng(componentRef.current, options);
console.log('PNG生成成功');
await saveImage(data);
// 跟踪 Unsplash 下载
if (unsplashImage && unsplashImage.downloadLink) {
try {
await unsplash.photos.trackDownload({
downloadLocation: unsplashImage.downloadLink
});
} catch (trackError) {
console.warn('跟踪下载失败:', trackError);
}
}
} catch (error) {
console.error('下载图片时出错:', error);
setLoading(false);
// 提供更具体的错误信息
let errorMessage = '图片下载失败,请重试。';
if (error.message.includes('cloneNode')) {
errorMessage = '页面还未完全加载,请等待几秒后重试。';
} else if (error.message.includes('CORS') || error.message.includes('cross-origin')) {
errorMessage = '图片下载失败:跨域访问被阻止。请尝试刷新页面后重新选择图片。';
} else if (error.message.includes('网络')) {
errorMessage = '图片下载失败:网络连接问题。请检查网络连接后重试。';
} else if (error.message.includes('无法找到要下载的元素')) {
errorMessage = '页面还未准备好,请稍等片刻后重试。';
}
alert(errorMessage);
}
}
return (
<React.Fragment>
<div ref={componentRef}>{props.children}</div>
<button
className="border p-2 bg-gray-700 hover:bg-gray-800 flex items-center text-white text-xl rounded-lg m-4 px-4"
onClick={() => downloadImage()}>
onClick={() => downloadImage()}
disabled={loading}>
<span>
{
loading ?
<svg xmlns="http://www.w3.org/2000/svg" className="w-6 h-6 text-white animate animate-spin" fill="currentColor" width="24" height="24" viewBox="0 0 24 24" ><path d="M12 22c5.421 0 10-4.579 10-10h-2c0 4.337-3.663 8-8 8s-8-3.663-8-8c0-4.336 3.663-8 8-8V2C6.579 2 2 6.58 2 12c0 5.421 4.579 10 10 10z"></path></svg>
<svg xmlns="http://www.w3.org/2000/svg" className="w-6 h-6 text-white animate-spin" fill="currentColor" width="24" height="24" viewBox="0 0 24 24" ><path d="M12 22c5.421 0 10-4.579 10-10h-2c0 4.337-3.663 8-8 8s-8-3.663-8-8c0-4.336 3.663-8 8-8V2C6.579 2 2 6.58 2 12c0 5.421 4.579 10 10 10z"></path></svg>
:
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"></path></svg>
}
</span>
<span className="mx-2">下载</span>
<span className="mx-2">{loading ? '下载中...' : '下载'}</span>
</button>
</React.Fragment>
);

View File

@ -39,9 +39,8 @@ const CoverImage = (props) => {
}
}
return (
<div className={`border-2 border-gray-50 md:scale-100 scale-50 ${props.platform}`}>
<div className={`md:scale-100 scale-50 ${props.platform}`}>
{selectTheme(theme)}
</div>
);

View File

@ -25,7 +25,7 @@ const defaultSettings = {
platform: 'hashnode'
};
const devIconsUrl = "https://mirror.20200511.xyz/https://raw.githubusercontent.com/devicons/devicon/master/devicon.json"
const devIconsUrl = "https://raw.githubusercontent.com/devicons/devicon/master/devicon.json"
class Editor extends React.Component {

View File

@ -23,7 +23,7 @@ const BackgroundTheme = ({ config }) => {
<div className='relative flex group'>
<div className="h-max w-full ">
<img src={unsplashImage.url && unsplashImage.url} className=" object-cover h-full w-full " alt="preview" />
<img src={unsplashImage.url && unsplashImage.url} className=" object-cover h-full w-full " alt="preview" crossOrigin="anonymous" />
</div>

View File

@ -1,43 +1,71 @@
import React from 'react';
import React, { useContext } from 'react';
import { ImgContext } from '../../utils/ImgContext';
import UnsplashSearch from '../UnsplashSearch';
const BasicTheme = ({ config }) => {
const { title, bgColor, pattern, author, icon, font, customIcon } = config;
const { unsplashImage, setUnsplashImage } = useContext(ImgContext);
return (
<div className=" bg-white w-full h-full ">
<div className={`overflow-y-hidden flex text-gray-800 items-center h-full ${pattern} `}
<div className="bg-white w-full h-full">
<div className={`overflow-y-hidden flex flex-col h-full`}
style={{ backgroundColor: bgColor }}
>
<div className={`${font} bg-white md:w-10/12 m-auto flex flex-col pt-12 rounded-xl`}>
<div className="px-12">
<div>
<h1 className="text-3xl md:text-5xl text-gray-800 font-bold text-center">{title}</h1>
</div>
</div>
<div className=" flex mx-4 p-4 rounded-xl items-center bg-white">
{
customIcon ?
<div className="w-12 h-12 ">
<img src={customIcon} alt="img" className="rounded-full bg-white p-1 border-white" />
<div className="flex flex-row items-center bg-white justify-center h-full">
<div className="w-full h-full">
{unsplashImage ?
<div className='relative flex group h-full'>
<div className="h-full w-full">
<img src={unsplashImage.url && unsplashImage.url} className="object-cover h-full w-full" alt="preview" crossOrigin="anonymous" />
</div>
:
<div className="mr-auto ml-2 items-center justify-center flex">
<i className={`devicon-${icon.value}-plain p-4 dev-icon text-5xl`}></i>
<div className="h-full bg-gray-800/60 absolute top-0 right-0 left-0 flex items-center justify-center">
<button
onClick={() => setUnsplashImage('')}
className="absolute top-2 right-2 cursor-pointer">
<svg className="group-hover:inline-block hidden w-8 h-8 text-gray-800 bg-white p-2 rounded-full z-10" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12"></path></svg>
</button>
<div className={`${font} bg-white/90 md:w-10/12 mx-auto flex flex-col py-12 px-12 rounded-xl ${pattern}`}>
<div>
<h1 className="text-3xl md:text-5xl text-gray-800 font-bold text-center">{title}</h1>
</div>
<div className="flex mx-4 mt-8 p-4 rounded-xl items-center bg-white/80">
{
customIcon ?
<div className="w-12 h-12">
<img src={customIcon} alt="img" className="rounded-full bg-white p-1 border-white" />
</div>
:
<div className="mr-auto ml-2 items-center justify-center flex">
<i className={`devicon-${icon.value}-plain p-4 dev-icon text-5xl`}></i>
</div>
}
<h2 className="text-xl ml-auto mr-2 font-semibold">{author}</h2>
</div>
</div>
</div>
<div className="absolute bottom-4 right-4 opacity-80">
<div className="group-hover:flex hidden items-center">
<span className="text-sm text-white mx-2">Photo by</span>
<a href={unsplashImage.profile} target="_blank" rel="noreferrer" className="cursor-pointer flex items-center bg-gray-300 rounded-full text-sm">
<img src={unsplashImage.avatar && unsplashImage.avatar} alt={unsplashImage.name} className="h-6 w-6 rounded-full mr-2" />
<span className="pr-2">{unsplashImage.name}</span>
</a>
<a href="https://unsplash.com/?utm_source=https://coverview.czl.net&utm_medium=referral" className="text-sm text-white mx-2">Unsplash</a>
</div>
</div>
</div>
:
<div className="flex flex-col p-2 bg-white items-center justify-center h-full">
<UnsplashSearch largeImgPreview />
</div>
}
<h2 className="text-xl ml-auto mr-2 font-semibold">{author}</h2>
</div>
</div>
</div>
</div>
);
}

View File

@ -1,65 +1,80 @@
import React, { useState } from 'react';
import React, { useState, useContext } from 'react';
import { ImgContext } from '../../utils/ImgContext';
import UnsplashSearch from '../UnsplashSearch';
const MobileMockupTheme = ({ config }) => {
const { bgColor, title, font } = config;
const [image, setImage] = useState()
const { unsplashImage, setUnsplashImage } = useContext(ImgContext);
const [image, setImage] = useState();
return (
<div className={`bg-white w-full h-full`}>
<div className={`overflow-y-hidden flex flex-row px-10 items-center w-full h-full justify-center pt-4`}
<div className={`overflow-y-hidden flex flex-row w-full h-full justify-center`}
style={{ backgroundColor: bgColor }}
>
<div className="w-full h-full">
{unsplashImage ?
<div className='relative flex group h-full'>
<div className="h-full w-full">
<img src={unsplashImage.url && unsplashImage.url} className="object-cover h-full w-full" alt="preview" crossOrigin="anonymous" />
</div>
<div className="h-full bg-gray-800/60 absolute top-0 right-0 left-0 flex items-center px-10">
<button
onClick={() => setUnsplashImage('')}
className="absolute top-2 right-2 cursor-pointer">
<svg className="group-hover:inline-block hidden w-8 h-8 text-gray-800 bg-white p-2 rounded-full z-10" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12"></path></svg>
</button>
<h1 className={`${font} text-2xl w-1/2 md:text-4xl px-4 text-white font-bold text-left`}>{title}</h1>
<h1 className={`${font} text-2xl w-1/2 md:text-4xl px-4 text-white font-bold text-left`}>{title}</h1>
<div className="w-5/12 mx-auto m-4 mt-10 group h-full shadow-lg flex flex-col bg-white border-t-8 border-x-8 border-gray-800 rounded-t-3xl border-white">
<div className="bg-gray-800 h-8 w-full p-2 pb-3 flex items-center rounded-t">
<div className="w-5/12 mx-auto m-4 group h-4/5 shadow-lg flex flex-col bg-white border-t-8 border-x-8 border-gray-800 rounded-t-3xl border-white">
<div className="bg-gray-800 h-8 w-full p-2 pb-3 flex items-center rounded-t">
<div className="flex mx-auto items-center">
<div className="bg-white h-3 w-3 rounded-full mx-1"></div>
<div className="bg-white h-2 w-20 rounded-full mx-1"></div>
</div>
</div>
<div className="flex mx-auto items-center">
{image ?
<div className="group relative h-full">
<img src={image && image} className="object-cover rounded -translate-y-1 h-full w-full" alt="preview" />
<button
onClick={() => setImage('')}
className="absolute top-4 right-2 cursor-pointer">
<svg className="group-hover:inline-block hidden w-6 h-6 bg-gray-500 p-1 text-white rounded-full z-10" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12"></path></svg>
</button>
</div>
:
<div className="flex flex-col px-4 rounded-xl py-20 bg-white items-center justify-center h-full">
<input type="file"
className="text-sm flex flex-col cursor-pointer mb-2 bg-white rounded border"
onChange={(e) => setImage(URL.createObjectURL(e.target.files[0]))}
/>
<span className="text-center italic">点击上传截图</span>
</div>
}
</div>
</div>
<div className="bg-white h-3 w-3 rounded-full mx-1"></div>
<div className="bg-white h-2 w-20 rounded-full mx-1"></div>
</div>
</div>
{image ?
<div className="group relative">
<img src={image && image} className="object-cover rounded -translate-y-1 h-full" alt="preview" />
<button
onClick={() => setImage('')}
className="ml-auto mr-4 cursor-pointer">
<svg className="group-hover:inline-block absolute top-4 right-2 bg-gray-500 hidden w-8 h-8 p-2 text-white rounded-full z-10" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12"></path></svg>
</button>
<div className="absolute bottom-4 right-4 opacity-80">
<div className="group-hover:flex hidden items-center">
<span className="text-sm text-white mx-2">Photo by</span>
<a href={unsplashImage.profile} target="_blank" rel="noreferrer" className="cursor-pointer flex items-center bg-gray-300 rounded-full text-sm">
<img src={unsplashImage.avatar && unsplashImage.avatar} alt={unsplashImage.name} className="h-6 w-6 rounded-full mr-2" />
<span className="pr-2">{unsplashImage.name}</span>
</a>
<a href="https://unsplash.com/?utm_source=https://coverview.czl.net&utm_medium=referral" className="text-sm text-white mx-2">Unsplash</a>
</div>
</div>
</div>
:
<div className="flex flex-col px-4 rounded-xl py-20 bg-white items-center justify-center">
<input type="file"
className="text-sm flex flex-col cursor-pointer mb-2 bg-white rounded border"
onChange={(e) => setImage(URL.createObjectURL(e.target.files[0]))}
/>
<span className=" text-center italic">点击上传截图</span>
<div className="flex flex-col p-2 bg-white items-center justify-center h-full">
<UnsplashSearch largeImgPreview />
</div>
}
</div>
</div>
</div>
);
}

View File

@ -1,39 +1,71 @@
import React from 'react';
import React, { useContext } from 'react';
import { ImgContext } from '../../utils/ImgContext';
import UnsplashSearch from '../UnsplashSearch';
const ModernTheme = ({ config }) => {
const { title, bgColor, pattern, author, icon, font, customIcon } = config;
const { unsplashImage, setUnsplashImage } = useContext(ImgContext);
return (
<div className="w-full h-full bg-white ">
<div className=" overflow-y-hidden w-full h-full flex items-center">
<div className={` h-full w-full p-4 text-gray-800 flex items-center ${pattern} `}
<div className="w-full h-full bg-white">
<div className="overflow-y-hidden w-full h-full flex items-center">
<div className="h-full w-full flex items-center"
style={{ backgroundColor: bgColor }}
>
<div className="w-full h-full">
{unsplashImage ?
<div className='relative flex group h-full'>
<div className="h-full w-full">
<img src={unsplashImage.url && unsplashImage.url} className="object-cover h-full w-full" alt="preview" crossOrigin="anonymous" />
</div>
{
customIcon ?
<div className=" mx-auto items-center justify-center flex">
<img src={customIcon} alt="img" className="w-28 h-28 rounded-full bg-white border-4 border-white" />
<div className="h-full bg-gray-800/60 absolute top-0 right-0 left-0 flex items-center">
<button
onClick={() => setUnsplashImage('')}
className="absolute top-2 right-2 cursor-pointer">
<svg className="group-hover:inline-block hidden w-8 h-8 text-gray-800 bg-white p-2 rounded-full z-10" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12"></path></svg>
</button>
<div className="w-full flex items-center px-8">
{
customIcon ?
<div className="mx-auto items-center justify-center flex">
<img src={customIcon} alt="img" className="w-28 h-28 rounded-full bg-white border-4 border-white" />
</div>
:
<div className="rounded-full p-6 w-32 h-32 bg-white mx-auto items-center justify-center flex">
<i className={`devicon-${icon.value}-plain p-4 dev-icon text-7xl`}></i>
</div>
}
<div className="w-2/3">
<div className={`${font} bg-white/90 px-12 justify-center text-left rounded-xl py-8 flex flex-col ${pattern}`}>
<h1 className="text-3xl md:text-5xl font-bold text-gray-800">{title}</h1>
<h2 className="text-xl mt-10 font-semibold text-left">{author}</h2>
</div>
</div>
</div>
</div>
<div className="absolute bottom-4 right-4 opacity-80">
<div className="group-hover:flex hidden items-center">
<span className="text-sm text-white mx-2">Photo by</span>
<a href={unsplashImage.profile} target="_blank" rel="noreferrer" className="cursor-pointer flex items-center bg-gray-300 rounded-full text-sm">
<img src={unsplashImage.avatar && unsplashImage.avatar} alt={unsplashImage.name} className="h-6 w-6 rounded-full mr-2" />
<span className="pr-2">{unsplashImage.name}</span>
</a>
<a href="https://unsplash.com/?utm_source=https://coverview.czl.net&utm_medium=referral" className="text-sm text-white mx-2">Unsplash</a>
</div>
</div>
</div>
:
<div className=" rounded-full p-6 w-32 h-32 bg-white mx-auto items-center justify-center flex">
<i className={`devicon-${icon.value}-plain p-4 dev-icon text-7xl`}></i>
<div className="flex flex-col p-2 bg-white items-center justify-center h-full">
<UnsplashSearch largeImgPreview />
</div>
}
<div className="h-full w-2/3">
<div className={`${font} bg-white px-12 justify-center text-left rounded-xl h-full p-4 flex flex-col`}>
<h1 className="text-3xl md:text-5xl font-bold text-gray-800">{title}</h1>
<h2 className="text-xl mt-10 font-semibold text-left ">{author}</h2>
</div>
}
</div>
</div>
</div>
</div>
);
}

View File

@ -1,41 +1,69 @@
import React from 'react';
import React, { useContext } from 'react';
import { ImgContext } from '../../utils/ImgContext';
import UnsplashSearch from '../UnsplashSearch';
const OutlineTheme = ({ config }) => {
const { title, bgColor, author, icon, font, customIcon } = config;
const { unsplashImage, setUnsplashImage } = useContext(ImgContext);
return (
<div className="w-full h-full bg-white ">
<div className={`overflow-y-hidden flex flex-col text-gray-800 px-10 h-full`}
<div className="w-full h-full bg-white">
<div className={`overflow-y-hidden flex flex-col text-gray-800 h-full`}
style={{ backgroundColor: bgColor }}
>
<div className="flex flex-row items-center bg-white justify-center h-full">
<div className="w-full h-full">
{unsplashImage ?
<div className='relative flex group h-full'>
<div className="h-full w-full">
<img src={unsplashImage.url && unsplashImage.url} className="object-cover h-full w-full" alt="preview" crossOrigin="anonymous" />
</div>
<div className="h-full bg-gray-800/60 absolute top-0 right-0 left-0 flex items-center justify-center">
<button
onClick={() => setUnsplashImage('')}
className="absolute top-2 right-2 cursor-pointer">
<svg className="group-hover:inline-block hidden w-8 h-8 text-gray-800 bg-white p-2 rounded-full z-10" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12"></path></svg>
</button>
<div className={`${font} rounded-2xl py-6 flex flex-col `}>
{
customIcon ?
<div className=" m-6">
<img src={customIcon} alt="img" className="rounded-full object-cover w-24 h-24 bg-white p-1 border-white" />
<div className={`${font} rounded-2xl py-6 px-10 flex flex-col mx-10`}>
{
customIcon ?
<div className="m-6">
<img src={customIcon} alt="img" className="rounded-full object-cover w-24 h-24 bg-white p-1 border-white" />
</div>
:
<div className="mr-auto ml-2 items-center justify-center flex">
<i className={`devicon-${icon.value}-plain text-white p-4 dev-icon text-8xl`}></i>
</div>
}
<h1 className="text-3xl p-4 text-white md:text-5xl font-bold">{title}</h1>
<div className={`${font} w-full h-16 flex mt-auto mb-0 p-2 px-6 items-center`}>
<h2 className="text-2xl text-white font-semibold">{author}</h2>
</div>
</div>
</div>
<div className="absolute bottom-4 right-4 opacity-80">
<div className="group-hover:flex hidden items-center">
<span className="text-sm text-white mx-2">Photo by</span>
<a href={unsplashImage.profile} target="_blank" rel="noreferrer" className="cursor-pointer flex items-center bg-gray-300 rounded-full text-sm">
<img src={unsplashImage.avatar && unsplashImage.avatar} alt={unsplashImage.name} className="h-6 w-6 rounded-full mr-2" />
<span className="pr-2">{unsplashImage.name}</span>
</a>
<a href="https://unsplash.com/?utm_source=https://coverview.czl.net&utm_medium=referral" className="text-sm text-white mx-2">Unsplash</a>
</div>
</div>
</div>
:
<div className=" mr-auto ml-2 items-center justify-center flex">
<i className={`devicon-${icon.value}-plain text-white p-4 dev-icon text-8xl`}></i>
<div className="flex flex-col p-2 bg-white items-center justify-center h-full">
<UnsplashSearch largeImgPreview />
</div>
}
<h1 className="text-3xl p-4 text-white md:text-5xl font-bold ">{title}</h1>
<div className={`${font} w-full h-16 flex mt-auto mb-0 p-2 px-6 items-center `}>
<h2 className="text-2xl text-white font-semibold">{author}</h2>
}
</div>
</div>
</div>
</div>
);
}

View File

@ -1,53 +1,79 @@
import React, { useState } from 'react';
import React, { useState, useContext } from 'react';
import { ImgContext } from '../../utils/ImgContext';
import UnsplashSearch from '../UnsplashSearch';
const PreviewTheme = ({ config }) => {
const { bgColor, title, font } = config;
const [image, setImage] = useState()
const { unsplashImage, setUnsplashImage } = useContext(ImgContext);
const [image, setImage] = useState();
return (
<div className="w-full h-full bg-white">
<div className={`overflow-y-hidden flex flex-col px-4 pt-4 w-full h-full`}
<div className={`overflow-y-hidden flex flex-col w-full h-full`}
style={{ backgroundColor: bgColor }}
>
<div className="w-full h-full">
{unsplashImage ?
<div className='relative flex group h-full'>
<div className="h-full w-full">
<img src={unsplashImage.url && unsplashImage.url} className="object-cover h-full w-full" alt="preview" crossOrigin="anonymous" />
</div>
<h1 className={`${font} text-2xl md:text-3xl p-10 text-white font-bold text-center`}>{title}</h1>
<div className="h-full bg-gray-800/60 absolute top-0 right-0 left-0 flex flex-col items-center justify-center px-4">
<button
onClick={() => setUnsplashImage('')}
className="absolute top-2 right-2 cursor-pointer">
<svg className="group-hover:inline-block hidden w-8 h-8 text-gray-800 bg-white p-2 rounded-full z-10" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12"></path></svg>
</button>
<div className="w-10/12 group mx-auto mt-auto mb-0 shadow-lg flex flex-col bg-white rounded-t-xl border-white">
<div className="bg-gray-800 h-8 w-full p-2 flex items-center rounded-t-xl">
<div className="bg-red-400 h-3 w-3 rounded-full mx-1"></div>
<div className="bg-yellow-400 h-3 w-3 rounded-full mx-1"></div>
<div className="bg-green-400 h-3 w-3 rounded-full mx-1"></div>
<button
onClick={() => setImage('')}
className="ml-auto mr-4 cursor-pointer">
<svg className="group-hover:inline-block hidden w-4 h-4 text-white rounded-full z-10" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12"></path></svg>
<h1 className={`${font} text-2xl md:text-3xl p-10 text-white font-bold text-center`}>{title}</h1>
</button>
</div>
<div className="w-10/12 group shadow-lg flex flex-col bg-white rounded-xl border-white">
<div className="bg-gray-800 h-8 w-full p-2 flex items-center rounded-t-xl">
<div className="bg-red-400 h-3 w-3 rounded-full mx-1"></div>
<div className="bg-yellow-400 h-3 w-3 rounded-full mx-1"></div>
<div className="bg-green-400 h-3 w-3 rounded-full mx-1"></div>
<button
onClick={() => setImage('')}
className="ml-auto mr-4 cursor-pointer">
<svg className="group-hover:inline-block hidden w-4 h-4 text-white rounded-full z-10" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12"></path></svg>
</button>
</div>
{image ?
<div className="h-full">
<img src={image && image} className="object-cover rounded-b-xl h-full w-full" alt="preview" />
</div>
:
<div className="flex flex-col p-20 py-28 bg-white rounded-b-xl items-center justify-center">
<input type="file"
className="text-xl cursor-pointer mb-2 bg-white rounded border"
onChange={(e) => setImage(URL.createObjectURL(e.target.files[0]))}
/>
<span className="text-center italic">点击上传截图</span>
</div>
}
</div>
</div>
{image ?
<div className="">
<img src={image && image} className="object-cover " alt="preview" />
<div className="absolute bottom-4 right-4 opacity-80">
<div className="group-hover:flex hidden items-center">
<span className="text-sm text-white mx-2">Photo by</span>
<a href={unsplashImage.profile} target="_blank" rel="noreferrer" className="cursor-pointer flex items-center bg-gray-300 rounded-full text-sm">
<img src={unsplashImage.avatar && unsplashImage.avatar} alt={unsplashImage.name} className="h-6 w-6 rounded-full mr-2" />
<span className="pr-2">{unsplashImage.name}</span>
</a>
<a href="https://unsplash.com/?utm_source=https://coverview.czl.net&utm_medium=referral" className="text-sm text-white mx-2">Unsplash</a>
</div>
</div>
</div>
:
<div className="flex flex-col p-20 py-28 bg-white items-center justify-center">
<input type="file"
className="text-xl cursor-pointer mb-2 bg-white rounded border"
onChange={(e) => setImage(URL.createObjectURL(e.target.files[0]))}
/>
<span className=" text-center italic">点击上传截图</span>
<div className="flex flex-col p-2 bg-white items-center justify-center h-full">
<UnsplashSearch largeImgPreview />
</div>
}
</div>
</div>
</div>
);
}

View File

@ -6,81 +6,60 @@ const StylishTheme = ({ config }) => {
const { title, author, font, icon, customIcon, bgColor } = config;
const { unsplashImage, setUnsplashImage } = useContext(ImgContext);
return (
<div className=" bg-white w-full h-full">
<div className={` overflow-y-hidden flex flex-col`}
<div className="bg-white w-full h-full">
<div className={`overflow-y-hidden flex flex-col h-full`}
style={{ backgroundColor: bgColor }}
>
<div className="flex flex-row items-center bg-white justify-center">
<div className="h-full w-1/2 bg-white rounded-l-xl">
<div className={`${font} px-12 justify-center text-left rounded-xl h-full p-4 flex flex-col`}>
<h1 className=" text-4xl font-bold text-gray-800">{title}</h1>
<div className="flex flex-row items-center bg-white justify-center h-full">
<div className="h-full w-1/2 bg-white rounded-l-xl flex items-center">
<div className={`${font} px-12 justify-center text-left rounded-xl w-full p-4 flex flex-col`}>
<h1 className="text-4xl font-bold text-gray-800">{title}</h1>
<div className="flex items-center mt-10 text-left">
{
customIcon ?
<div className=" ">
<div className="">
<img src={customIcon} alt="img" className="w-12 h-12 mr-2 rounded-full bg-white border border-white" />
</div>
:
<div className="mr-2 items-center justify-center flex">
<i className={`devicon-${icon.value}-plain dev-icon text-3xl`}></i>
<i className={`devicon-${icon.value}-plain dev-icon text-3xl`}></i>
</div>
}
<h2 className="text-xl font-semibold text-left ">{author}</h2>
<h2 className="text-xl font-semibold text-left">{author}</h2>
</div>
</div>
</div>
<div className="w-1/2 h-full">
{unsplashImage ?
<div className='relative w-full h-max flex group'>
<img src={unsplashImage.url && unsplashImage.url} className=" object-cover w-full h-full " alt="preview" />
<div className='relative w-full h-full flex group'>
<img src={unsplashImage.url && unsplashImage.url} className="object-cover w-full h-full rounded-r-xl" alt="preview" crossOrigin="anonymous" />
<button
onClick={() => setUnsplashImage('')}
className="absolute top-4 right-2 cursor-pointer">
className="absolute top-4 right-2 cursor-pointer">
<svg className="group-hover:inline-block hidden w-6 h-6 text-gray-800 bg-white p-1 rounded-full z-10" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12"></path></svg>
</button>
<div className="absolute bottom-4 right-4 opacity-80">
<div className=" group-hover:flex hidden items-center">
<div className="absolute bottom-4 right-4 opacity-80">
<div className="group-hover:flex hidden items-center">
<span className="text-sm text-white mx-2">Photo by</span>
<a href={unsplashImage.profile} target="_blank" rel="noreferrer" className="cursor-pointer flex items-center bg-gray-300 rounded-full text-sm">
<img src={unsplashImage.avatar && unsplashImage.avatar} alt={unsplashImage.name} className="h-6 w-6 rounded-full mr-2" />
<span className="pr-2">{unsplashImage.name}</span>
</a>
<a href="https://unsplash.com/?utm_source=https://coverview.czl.net&utm_medium=referral" className="text-sm text-white mx-2">Unsplash</a>
</div>
</div>
</div>
:
<div className="flex h-max w-full flex-col bg-white items-center justify-center">
<div className="flex h-full w-full flex-col bg-white items-center justify-center rounded-r-xl">
<UnsplashSearch />
</div>
}
</div>
</div>
</div>
</div>
);
}