Compare commits
10 Commits
313cba38de
...
main
Author | SHA1 | Date | |
---|---|---|---|
2bc8822f60 | |||
51733f3f2e | |||
90126beb35 | |||
1d3c2b0645 | |||
b6614dbaae | |||
2a818cba7f | |||
fdb1812e8e | |||
59edfd8105 | |||
92401ced52 | |||
4a063696cb |
Before Width: | Height: | Size: 134 KiB After Width: | Height: | Size: 134 KiB |
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 74 KiB |
Before Width: | Height: | Size: 464 KiB After Width: | Height: | Size: 464 KiB |
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
公司地址:浙江省杭州市余杭区闲林街道天日山西路 230 号 A 区 3 楼 2954 室
|
公司地址:浙江省杭州市余杭区闲林街道天日山西路 230 号 A 区 3 楼 2954 室
|
||||||
|
|
||||||
公司邮箱: envision@kevisual.cn
|
公司邮箱: kevisual@kevisual.cn
|
||||||
|
|
||||||
公司经营范围:网站部署,笔记,ai 助手,计算机软件开发。
|
公司经营范围:网站部署,笔记,ai 助手,计算机软件开发。
|
||||||
|
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
公司 logo 图片:
|
公司 logo 图片:
|
||||||
|
|
||||||
公司营业执照: 
|
公司营业执照: 
|
||||||
|
|
||||||
举报邮箱: feedback@kevisual.cn
|
举报邮箱: feedback@kevisual.cn
|
||||||
|
|
@@ -3,9 +3,9 @@
|
|||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="https://kevisual.cn/root/center/panda.png" />
|
<link rel="icon" type="image/svg+xml" href="https://kevisual.cn/root/center/panda.jpg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>kevisual 助手</title>
|
<title>逸文设计工作室</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
39
backup/package.json
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
{
|
||||||
|
"name": "@kevisual/official-website",
|
||||||
|
"version": "0.0.2",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"basename": "/root/official",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "vite build",
|
||||||
|
"preview": "vite preview",
|
||||||
|
"pub": "envision deploy ./dist -k official -v 0.0.2 -u -o root"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "abearxiong <xiongxiao@xiongxiao.me>",
|
||||||
|
"license": "MIT",
|
||||||
|
"type": "module",
|
||||||
|
"dependencies": {
|
||||||
|
"@ant-design/v5-patch-for-react-19": "^1.0.3",
|
||||||
|
"@kevisual/query": "^0.0.29",
|
||||||
|
"antd": "^5.26.2",
|
||||||
|
"clsx": "^2.1.1",
|
||||||
|
"lucide-react": "^0.522.0",
|
||||||
|
"react": "^19.1.0",
|
||||||
|
"react-dom": "^19.1.0",
|
||||||
|
"rollup-plugin-visualizer": "^6.0.3"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@kevisual/cache": "^0.0.3",
|
||||||
|
"@kevisual/codemirror": "^0.0.12",
|
||||||
|
"@tailwindcss/vite": "^4.1.10",
|
||||||
|
"@types/react": "^19.1.8",
|
||||||
|
"@types/react-dom": "^19.1.6",
|
||||||
|
"@vitejs/plugin-react": "^4.6.0",
|
||||||
|
"react-feather": "^2.0.10",
|
||||||
|
"react-toastify": "^11.0.5",
|
||||||
|
"tailwindcss": "^4.1.10",
|
||||||
|
"vite": "^7.0.0"
|
||||||
|
}
|
||||||
|
}
|
2939
backup/pnpm-lock.yaml
generated
Normal file
266
backup/src/App.tsx
Normal file
@@ -0,0 +1,266 @@
|
|||||||
|
import { Mail, Phone, MapPin, Book, Globe, Brain, Save } from 'lucide-react';
|
||||||
|
import { chain, TextEditor } from './components/TextEditor';
|
||||||
|
import { toast, ToastContainer } from 'react-toastify';
|
||||||
|
import { Provider } from './Provider';
|
||||||
|
// @ts-ignore
|
||||||
|
import Logo from './assets/logo-1.png';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { CodeDescModal } from './modules/CodeDescModal';
|
||||||
|
import { query } from './modules/query.ts';
|
||||||
|
import { toastSuccess, toastWeChat } from './modules/RedirectSuccess.tsx';
|
||||||
|
import { WeChat } from './components/Icon.tsx';
|
||||||
|
const getOrigin = () => {
|
||||||
|
let origin = window.location.origin;
|
||||||
|
if (origin.includes('www.kevisual.cn')) {
|
||||||
|
origin = origin.replace('www.kevisual.cn', 'kevisual.cn');
|
||||||
|
}
|
||||||
|
return origin;
|
||||||
|
};
|
||||||
|
export const Main = () => {
|
||||||
|
const [showPreview, setShowPreview] = useState(false);
|
||||||
|
const [html, setHtml] = useState<string>('');
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
const [resultUrl, setResultUrl] = useState<string>('');
|
||||||
|
const [url] = useState<string>('https://kevisual.cn');
|
||||||
|
const onSubmit = async (values: { title: string; description: string }) => {
|
||||||
|
setResultUrl('');
|
||||||
|
const uploadData = {
|
||||||
|
title: values?.title,
|
||||||
|
description: values?.description,
|
||||||
|
content: chain.getContent(),
|
||||||
|
};
|
||||||
|
const res = await query.post({
|
||||||
|
path: 'app',
|
||||||
|
key: 'public-upload-html',
|
||||||
|
data: uploadData,
|
||||||
|
});
|
||||||
|
if (res.code === 200) {
|
||||||
|
const url = res.data?.url;
|
||||||
|
if (url) {
|
||||||
|
let origin = getOrigin();
|
||||||
|
const newUrl = new URL(url, origin);
|
||||||
|
// toast.success('创建成功, 访问地址' + newUrl.toString(), { autoClose: 3000 });
|
||||||
|
toastSuccess(newUrl.toString());
|
||||||
|
setResultUrl(newUrl.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div className='min-h-screen bg-gray-50'>
|
||||||
|
{/* Hero Section */}
|
||||||
|
<header className=''>
|
||||||
|
<nav className='px-4 mx-auto h-16 flex justify-between items-center bg-white border-b border-b-gray-200 w-full'>
|
||||||
|
<div
|
||||||
|
className='flex items-center space-x-4 cursor-pointer'
|
||||||
|
onClick={() => {
|
||||||
|
window.open(url, '_blank');
|
||||||
|
}}>
|
||||||
|
<img src={Logo} alt='可视化助手 Logo' className='h-10 w-30 ' />
|
||||||
|
</div>
|
||||||
|
<div className='hidden md:flex space-x-6'>
|
||||||
|
<a
|
||||||
|
className='hover:text-gray-400 cursor-pointer'
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const url = new URL('/root/center/', getOrigin());
|
||||||
|
window.open(url.toString(), '_blank');
|
||||||
|
}}>
|
||||||
|
管理中心
|
||||||
|
</a>
|
||||||
|
<a href='#features' className='hover:text-gray-400 cursor-pointer'>
|
||||||
|
功能
|
||||||
|
</a>
|
||||||
|
<a href='#contact' className='hover:text-gray-400 cursor-pointer'>
|
||||||
|
联系方式
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
<main
|
||||||
|
className='flex flex-col overflow-hidden'
|
||||||
|
style={{
|
||||||
|
height: 'calc(100vh - 64px)',
|
||||||
|
}}>
|
||||||
|
<nav className='h-12 bg-white flex'>
|
||||||
|
<button
|
||||||
|
className='flex items-center px-4 h-full bg-white border-b border-b-gray-200 hover:bg-gray-50 cursor-pointer'
|
||||||
|
onClick={() => {
|
||||||
|
const content = chain.getContent();
|
||||||
|
if (!content) {
|
||||||
|
toast.error('内容不能为空', { position: 'top-center', autoClose: 1000 });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setOpen(true);
|
||||||
|
}}>
|
||||||
|
<span className='text-gray-700'>创建</span>
|
||||||
|
<Save className='ml-2 w-4 h-4 text-gray-500' />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
className='flex items-center px-4 h-full bg-white border-b border-b-gray-200 hover:bg-gray-50 cursor-pointer'
|
||||||
|
style={{
|
||||||
|
backgroundColor: showPreview ? '#f0f0f0' : 'white',
|
||||||
|
}}
|
||||||
|
onClick={() => {
|
||||||
|
setShowPreview(!showPreview);
|
||||||
|
}}>
|
||||||
|
<span className='text-gray-700'>预览</span>
|
||||||
|
<Globe className='ml-2 w-4 h-4 text-gray-500' />
|
||||||
|
</button>
|
||||||
|
</nav>
|
||||||
|
<div className='p-2 rounded shadow flex' style={{ height: 'calc(100% - 48px - 48px)' }}>
|
||||||
|
<div className='h-full overflow-auto flex-1'>
|
||||||
|
<TextEditor content={''} chain={chain} onChange={setHtml} />
|
||||||
|
</div>
|
||||||
|
{showPreview && (
|
||||||
|
<div className='w-1/2 shrink-1 border-l border-gray-200 h-full overflow-auto'>
|
||||||
|
<iframe className='w-full h-full border-0' srcDoc={html} title='预览' sandbox='allow-scripts allow-same-origin allow-popups' />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<footer className='h-12'>
|
||||||
|
{!resultUrl && <div className='flex items-center h-full text-gray-500 px-2 italic'>粘贴您的 HTML 内容到编辑器中,点击“创建”按钮生成链接。</div>}
|
||||||
|
{resultUrl && (
|
||||||
|
<div className='flex items-center gap-2 px-4 h-full bg-white border-t border-t-gray-200'>
|
||||||
|
<span className='text-gray-700'>生成的链接:</span>
|
||||||
|
<a href={resultUrl} target='_blank' rel='noopener noreferrer' className='text-blue-600 hover:underline'>
|
||||||
|
{resultUrl}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</footer>
|
||||||
|
<CodeDescModal open={open} onClose={() => setOpen(false)} onSubmit={onSubmit} />
|
||||||
|
</main>
|
||||||
|
|
||||||
|
{/* Features Section */}
|
||||||
|
<section id='features' className='py-20 bg-white'>
|
||||||
|
<div className='container mx-auto px-6'>
|
||||||
|
<h2 className='text-3xl font-bold text-center mb-16'>核心功能</h2>
|
||||||
|
|
||||||
|
<div className='grid md:grid-cols-3 gap-12'>
|
||||||
|
<div className='p-6 rounded-lg shadow-lg bg-white'>
|
||||||
|
<Globe className='w-12 h-12 text-blue-600 mb-4' />
|
||||||
|
<h3 className='text-xl font-semibold mb-4'>网页部署平台</h3>
|
||||||
|
<p className='text-gray-600'>轻松管理您的博客和自定义网页,支持文件管理、站点创建和域名自定义</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='p-6 rounded-lg shadow-lg bg-white'>
|
||||||
|
<Brain className='w-12 h-12 text-blue-600 mb-4' />
|
||||||
|
<h3 className='text-xl font-semibold mb-4'>应用共享</h3>
|
||||||
|
<p className='text-gray-600'>根据用户需求,某一些应用只能自己访问或者共享</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='p-6 rounded-lg shadow-lg bg-white'>
|
||||||
|
<Book className='w-12 h-12 text-blue-600 mb-4' />
|
||||||
|
<h3 className='text-xl font-semibold mb-4'>临时网页</h3>
|
||||||
|
<p className='text-gray-600'>当个网页助手,帮助您快速生成临时网页</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Contact Section */}
|
||||||
|
<section id='contact' className='py-20 bg-white'>
|
||||||
|
<div className='container mx-auto px-6'>
|
||||||
|
<h2 className='text-3xl font-bold text-center mb-16'>联系我们</h2>
|
||||||
|
<div className='max-w-2xl mx-auto w-[200px]'>
|
||||||
|
<div className='space-y-6'>
|
||||||
|
<div className='flex items-center space-x-4'>
|
||||||
|
<Mail className='w-6 h-6 text-blue-600' />
|
||||||
|
<span>kevisual@kevisual.cn</span>
|
||||||
|
</div>
|
||||||
|
<div className='flex items-center space-x-4'>
|
||||||
|
<Phone className='w-6 h-6 text-blue-600' />
|
||||||
|
<span>18324451015</span>
|
||||||
|
</div>
|
||||||
|
<div className='flex items-center space-x-4'>
|
||||||
|
<MapPin className='w-6 h-6 text-blue-600' />
|
||||||
|
<span>浙江省杭州市</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Footer */}
|
||||||
|
<footer className='bg-gray-900 text-white py-12'>
|
||||||
|
<div className='container mx-auto px-6'>
|
||||||
|
<div className='grid md:grid-cols-4 gap-8'>
|
||||||
|
<div>
|
||||||
|
<h3 className='text-lg font-semibold mb-4'>Kevisual 助手</h3>
|
||||||
|
<p className='text-gray-400'>加速你的工作,生活,学习</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className='text-lg font-semibold mb-4'>快速链接</h3>
|
||||||
|
<ul className='space-y-2 text-gray-400'>
|
||||||
|
<li>
|
||||||
|
<a href='#features' className='hover:text-white'>
|
||||||
|
功能
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href='#contact' className='hover:text-white'>
|
||||||
|
联系方式
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className='text-lg font-semibold mb-4'>法律信息</h3>
|
||||||
|
<ul className='space-y-2 text-gray-400'>
|
||||||
|
<li>
|
||||||
|
<a href='./privacy' className='hover:text-white'>
|
||||||
|
隐私政策
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href='./terms' className='hover:text-white'>
|
||||||
|
用户协议
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className='text-lg font-semibold mb-4'>联系我们</h3>
|
||||||
|
<div className='flex space-x-4'>
|
||||||
|
<a href='mailto:feedback@kevisual.cn' className='text-gray-400 hover:text-white cursor-pointer'>
|
||||||
|
<Mail className='w-6 h-6' />
|
||||||
|
</a>
|
||||||
|
<a href='tel:18324451015' className='text-gray-400 hover:text-white cursor-pointer'>
|
||||||
|
<Phone className='w-6 h-6' />
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
className='text-gray-400 hover:text-white cursor-pointer'
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
toastWeChat();
|
||||||
|
}}>
|
||||||
|
<WeChat className='w-6 h-6' />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className='mt-12 pt-8 border-t border-gray-800 text-center text-gray-400'
|
||||||
|
onClick={() => {
|
||||||
|
window.open('https://beian.miit.gov.cn/', '_blank');
|
||||||
|
}}>
|
||||||
|
<p>浙ICP备2025158778号</p>
|
||||||
|
<p>© 2025 杭州余杭逸文设计工作室. All rights reserved.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const App = () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Provider>
|
||||||
|
<ToastContainer autoClose={2000}></ToastContainer>
|
||||||
|
<Main />
|
||||||
|
</Provider>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
19
backup/src/Provider.tsx
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import ConfigProvider from 'antd/lib/config-provider';
|
||||||
|
import '@ant-design/v5-patch-for-react-19';
|
||||||
|
|
||||||
|
export const Provider = ({ children }: { children: React.ReactNode }) => {
|
||||||
|
return (
|
||||||
|
<ConfigProvider
|
||||||
|
theme={{
|
||||||
|
token: {
|
||||||
|
colorPrimary: '#1677ff',
|
||||||
|
colorTextBase: '#ffffff',
|
||||||
|
colorBgBase: '#1f1f1f',
|
||||||
|
colorBgContainer: '#2c2c2c',
|
||||||
|
colorBorder: '#3a3a3a',
|
||||||
|
},
|
||||||
|
}}>
|
||||||
|
{children}
|
||||||
|
</ConfigProvider>
|
||||||
|
);
|
||||||
|
};
|
BIN
backup/src/assets/logo-1.png
Normal file
After Width: | Height: | Size: 230 KiB |
11
backup/src/components/EvWechat.tsx
Normal file
24
backup/src/components/Icon.tsx
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
export const Github = () => {
|
||||||
|
return (
|
||||||
|
<svg aria-hidden='true' height='24' viewBox='0 0 24 24' version='1.1' width='24' data-view-component='true' className='octicon octicon-mark-github'>
|
||||||
|
<path d='M12 1C5.923 1 1 5.923 1 12c0 4.867 3.149 8.979 7.521 10.436.55.096.756-.233.756-.522 0-.262-.013-1.128-.013-2.049-2.764.509-3.479-.674-3.699-1.292-.124-.317-.66-1.293-1.127-1.554-.385-.207-.936-.715-.014-.729.866-.014 1.485.797 1.691 1.128.99 1.663 2.571 1.196 3.204.907.096-.715.385-1.196.701-1.471-2.448-.275-5.005-1.224-5.005-5.432 0-1.196.426-2.186 1.128-2.956-.111-.275-.496-1.402.11-2.915 0 0 .921-.288 3.024 1.128a10.193 10.193 0 0 1 2.75-.371c.936 0 1.871.123 2.75.371 2.104-1.43 3.025-1.128 3.025-1.128.605 1.513.221 2.64.111 2.915.701.77 1.127 1.747 1.127 2.956 0 4.222-2.571 5.157-5.019 5.432.399.344.743 1.004.743 2.035 0 1.471-.014 2.654-.014 3.025 0 .289.206.632.756.522C19.851 20.979 23 16.854 23 12c0-6.077-4.922-11-11-11Z'></path>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const WeChat = (props: React.SVGProps<SVGSVGElement>) => {
|
||||||
|
return (
|
||||||
|
<div className={'relative ' + props.className}>
|
||||||
|
<svg viewBox='0 0 1024 1024' version='1.1' xmlns='http://www.w3.org/2000/svg' className='w-8 h-8 absolute -top-1 left-0'>
|
||||||
|
<path
|
||||||
|
fill='currentColor'
|
||||||
|
d='M289.8 367.2c0-13.6 7.8-25.4 19.8-31.2 21.3-10.2 49.2 3.5 49.2 32.5 0 18-16 33.5-34.2 33.5-19.4 0-34.8-15.3-34.8-34.8z m174.2 0.7c0-13.7 8.5-26.2 18.9-31.4 12.7-6.3 28.1-4.6 38.6 4.8 11.8 10.5 15 29.4 7.8 42.3-14.3 25.5-49.9 24.2-61.9-1.7-1.5-3.4-3.4-9.6-3.4-14zM149.9 433c0 27.3 2.4 43 10.7 66.7 8.4 24 24 49.6 41.4 68.3 1.6 1.7 2.1 2.7 3.9 4.5l22 20.6c1.6 1.3 3.1 2.4 4.7 3.7 1.7 1.3 2.9 2.3 4.7 3.7 14.3 10.7 10.8 17.2 5.3 36.7l-8.1 30c-2.8 9.5 1.9 14.7 8.2 14.4 4.1-0.2 20.8-10.9 24.6-13.1l40.6-23.3c11.2-5 19-0.9 32.4 2.5 18.6 4.7 28.6 5.3 47.5 7.3l38.1 0.4c-0.8-9.7-8.4-17.1-8.4-58.5 0-16 3.9-33.9 7.8-46.4 5.7-18 16.3-38.3 27.8-53.5l18.8-21.9 14.2-12.9c2.7-2.3 5-4.1 7.8-6.4l39.3-24.6c39.3-18.7 75.6-28.5 124.9-28.5l9.7 0.7c3.1-0.2 3 1.2-0.6-13.1-4.4-17.7-12.1-35.2-21.5-50.8-12.7-21.2-22.5-31.3-39.1-47.9-15.6-15.6-41.7-32.5-60.6-42-15.7-7.8-25.1-11.3-41.7-16.9-14.8-5-30.2-8.1-47.2-10.8-8.6-1.4-17.5-1.9-26.2-2.9-4.5-0.5-10.1 0.2-14.7-0.1-43.9-2.5-103.7 11.4-141.6 31.8-1.9 1-2.5 1.5-4.5 2.6l-23 13.8c-12.4 9.4-20.3 13.9-32.6 26.1l-27.1 30.9c-20.5 30.3-37.5 64.8-37.5 108.9z'
|
||||||
|
p-id='1534'></path>
|
||||||
|
<path
|
||||||
|
fill='currentColor'
|
||||||
|
d='M554.2 543.9c0-16.4 12.2-29 29.7-29 23 0 35.1 27 22.9 44.9-0.7 1-0.7 0.8-1.4 1.8-0.9 1.2-0.8 1.2-1.7 2.2-1.9 2.1-5.3 4.3-8 5.6-11 5.3-23.7 3.6-32.4-4.8-5-5-9.1-11.6-9.1-20.7z m172.2-29h3.9c12.9 0 26.4 13 26.4 25.8 0 9.7-0.7 16-8.5 23.7-21.5 21.1-58.7-3-46.5-31.6 2.8-6.6 7.2-11.6 13.5-14.9 2.9-1.5 7.1-3 11.2-3z m-288.9 81.2c0 22.7 0.9 30.3 6.8 51.2 4.8 16.9 14.2 34 24.1 48.1l10.8 13.7c4.5 4.6 9.7 11.1 14.6 15.1 1.6 1.3 2 1.4 3.5 2.9 5.9 5.9 19.5 15.3 27.3 20.3 2.5 1.6 5.2 3.2 7.7 4.6 32.4 18.5 75.8 31.6 113.5 31.6 32.4 0 45.6-0.6 76.6-8.5 14.5-3.7 16.8-2.2 29.6 5.5l39.5 23c8.3 4.8 13.8-1.8 12.4-7.9l-2.6-9.7c-1.7-6.8-3.5-13.2-5.3-19.9-2.6-10-7.3-19.7 2.6-27 18.5-13.6 30.2-25.7 43.8-43.8 19.1-25.3 31.5-61.5 31.5-93.6 0-7.2-1-16.1-1.9-22.6-3.8-27.5-17.1-56.9-34.4-77.8l-24.5-25.8c-2.3-2.1-4.7-3.6-7.1-5.8-5.6-5-22.9-16.3-29.7-19.9-74.4-39.8-165.2-41.3-239.4-1.3-5.3 2.8-10.4 5.9-15.3 9.2-5.5 3.7-16.7 11.4-21.5 15.9-1.2 1.2-1.5 1.6-3 2.8-1.7 1.3-2 1.5-3.4 3-14.7 14.9-22 21.8-33.4 40.8-12.3 20.7-22.8 50.2-22.8 75.9z'
|
||||||
|
p-id='1535'></path>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
51
backup/src/components/TextEditor.tsx
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
import { createEditor } from '@kevisual/codemirror';
|
||||||
|
import { Chain } from '@kevisual/codemirror/utils';
|
||||||
|
import { useEffect, useRef } from 'react';
|
||||||
|
import { CacheWorkspace } from '@kevisual/cache';
|
||||||
|
|
||||||
|
export const chain = new Chain();
|
||||||
|
type TextEditorProps = {
|
||||||
|
content: string;
|
||||||
|
chain?: Chain;
|
||||||
|
onChange?: (content: string) => void;
|
||||||
|
};
|
||||||
|
export const TextEditor = ({ content, chain, onChange }: TextEditorProps) => {
|
||||||
|
const editorElRef = useRef<HTMLDivElement>(null);
|
||||||
|
const editorRef = useRef<ReturnType<typeof createEditor>>(null);
|
||||||
|
useEffect(() => {
|
||||||
|
initEditor();
|
||||||
|
return () => {
|
||||||
|
if (editorRef.current) {
|
||||||
|
chain?.destroy?.();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
useEffect(() => {
|
||||||
|
if (editorRef.current) {
|
||||||
|
chain?.setContent?.(content);
|
||||||
|
}
|
||||||
|
}, [content]);
|
||||||
|
const initEditor = async () => {
|
||||||
|
if (!editorElRef.current) return;
|
||||||
|
const cache = new CacheWorkspace();
|
||||||
|
const editor = createEditor(editorElRef.current, {
|
||||||
|
type: 'html',
|
||||||
|
onChange: (value) => {
|
||||||
|
cache.set('editor-content-home', value);
|
||||||
|
onChange?.(value);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const value = await cache.get('editor-content-home');
|
||||||
|
const cmScroller = editorElRef.current.querySelector('.cm-scroller');
|
||||||
|
if (cmScroller) {
|
||||||
|
cmScroller.classList.add('scrollbar');
|
||||||
|
}
|
||||||
|
chain?.setEditor?.(editor);
|
||||||
|
editorRef.current = editor;
|
||||||
|
if (value) {
|
||||||
|
chain?.setContent?.(value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return <div className='h-full overflow-hidden' ref={editorElRef}></div>;
|
||||||
|
};
|
@@ -6,3 +6,4 @@ import './index.css';
|
|||||||
const root = createRoot(document.getElementById('root') as HTMLElement);
|
const root = createRoot(document.getElementById('root') as HTMLElement);
|
||||||
|
|
||||||
root.render(<App />);
|
root.render(<App />);
|
||||||
|
|
51
backup/src/modules/CodeDescModal.tsx
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
import Modal from 'antd/es/modal/Modal';
|
||||||
|
import Form, { useForm } from 'antd/es/form/Form';
|
||||||
|
import FormItem from 'antd/es/form/FormItem';
|
||||||
|
import Input from 'antd/es/input';
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
|
type CodeDescModalProps = {
|
||||||
|
open: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
onSubmit?: (values: { title: string; description: string }) => void;
|
||||||
|
initialValues?: { title: string; description: string };
|
||||||
|
};
|
||||||
|
export const CodeDescModal = (props: CodeDescModalProps) => {
|
||||||
|
const [form] = useForm();
|
||||||
|
useEffect(() => {
|
||||||
|
if (!props.open) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (props.initialValues) {
|
||||||
|
form.setFieldsValue(props.initialValues || { title: '', description: '' });
|
||||||
|
}
|
||||||
|
}, [props.open, props.initialValues, form]);
|
||||||
|
return (
|
||||||
|
<Modal title='代码描述' open={props.open} onCancel={props.onClose} footer={null}>
|
||||||
|
<p className='text-gray-500 text-sm mb-4'>登陆用户的数据长存,非登陆的用户,保留30天自动删除。</p>
|
||||||
|
<Form form={form} layout='vertical'>
|
||||||
|
<FormItem label='标题' name='title'>
|
||||||
|
<Input />
|
||||||
|
</FormItem>
|
||||||
|
<FormItem label='描述' name='description'>
|
||||||
|
<Input.TextArea rows={4} />
|
||||||
|
</FormItem>
|
||||||
|
</Form>
|
||||||
|
<div className='flex justify-end mt-4'>
|
||||||
|
<button
|
||||||
|
className='px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 cursor-pointer'
|
||||||
|
onClick={() => {
|
||||||
|
form.validateFields().then((values) => {
|
||||||
|
props.onSubmit?.(values);
|
||||||
|
props.onClose();
|
||||||
|
});
|
||||||
|
}}>
|
||||||
|
提交
|
||||||
|
</button>
|
||||||
|
<button className='ml-2 px-4 py-2 bg-gray-300 text-gray-700 rounded hover:bg-gray-400 cursor-pointer' onClick={props.onClose}>
|
||||||
|
取消
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
35
backup/src/modules/RedirectSuccess.tsx
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import { EvWechat } from '../components/EvWechat';
|
||||||
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
|
export const RedirectSuccess = ({ url }: { url: string }) => {
|
||||||
|
return (
|
||||||
|
<div className='flex flex-col items-center justify-center p-2'>
|
||||||
|
<div className='flex flex-col gap-2 mb-3'>
|
||||||
|
<div className=' font-semibold'>创建成功</div>
|
||||||
|
<a
|
||||||
|
href={url}
|
||||||
|
className='text-blue-600 hover:text-blue-800 transition-colors duration-200 hover:underline block truncate'
|
||||||
|
target='_blank'
|
||||||
|
rel='noopener noreferrer'>
|
||||||
|
跳转到新应用
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const toastSuccess = (url: string) => {
|
||||||
|
toast.success(<RedirectSuccess url={url} />, {
|
||||||
|
autoClose: 5000,
|
||||||
|
className: 'rounded-md shadow-lg',
|
||||||
|
// icon: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const toastWeChat = () => {
|
||||||
|
toast.success(<EvWechat />, {
|
||||||
|
autoClose: 10000,
|
||||||
|
className: 'rounded-md shadow-lg',
|
||||||
|
icon: false,
|
||||||
|
});
|
||||||
|
};
|
3
backup/src/modules/query.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import { QueryClient } from '@kevisual/query';
|
||||||
|
|
||||||
|
export const query = new QueryClient();
|
@@ -1,6 +1,7 @@
|
|||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from 'vite';
|
||||||
import react from '@vitejs/plugin-react';
|
import react from '@vitejs/plugin-react';
|
||||||
import tailwindcss from '@tailwindcss/vite';
|
import tailwindcss from '@tailwindcss/vite';
|
||||||
|
// import { visualizer } from "rollup-plugin-visualizer";
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
const isDev = process.env.NODE_ENV === 'development';
|
const isDev = process.env.NODE_ENV === 'development';
|
||||||
|
|
||||||
@@ -10,4 +11,14 @@ export default defineConfig({
|
|||||||
optimizeDeps: {
|
optimizeDeps: {
|
||||||
exclude: ['lucide-react'],
|
exclude: ['lucide-react'],
|
||||||
},
|
},
|
||||||
|
server: {
|
||||||
|
proxy: {
|
||||||
|
'/api': {
|
||||||
|
target: 'http://localhost:4005',
|
||||||
|
changeOrigin: true,
|
||||||
|
secure: false,
|
||||||
|
rewrite: (path) => path.replace(/^\/api/, '/api'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
24
official/.gitignore
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# build output
|
||||||
|
dist/
|
||||||
|
# generated types
|
||||||
|
.astro/
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# logs
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
|
||||||
|
|
||||||
|
# environment variables
|
||||||
|
.env
|
||||||
|
.env.production
|
||||||
|
|
||||||
|
# macOS-specific files
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# jetbrains setting folder
|
||||||
|
.idea/
|
4
official/.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"recommendations": ["astro-build.astro-vscode"],
|
||||||
|
"unwantedRecommendations": []
|
||||||
|
}
|
11
official/.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"command": "./node_modules/.bin/astro dev",
|
||||||
|
"name": "Development server",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "node-terminal"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
43
official/README.md
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
# Astro Starter Kit: Minimal
|
||||||
|
|
||||||
|
```sh
|
||||||
|
pnpm create astro@latest -- --template minimal
|
||||||
|
```
|
||||||
|
|
||||||
|
> 🧑🚀 **Seasoned astronaut?** Delete this file. Have fun!
|
||||||
|
|
||||||
|
## 🚀 Project Structure
|
||||||
|
|
||||||
|
Inside of your Astro project, you'll see the following folders and files:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/
|
||||||
|
├── public/
|
||||||
|
├── src/
|
||||||
|
│ └── pages/
|
||||||
|
│ └── index.astro
|
||||||
|
└── package.json
|
||||||
|
```
|
||||||
|
|
||||||
|
Astro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page is exposed as a route based on its file name.
|
||||||
|
|
||||||
|
There's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components.
|
||||||
|
|
||||||
|
Any static assets, like images, can be placed in the `public/` directory.
|
||||||
|
|
||||||
|
## 🧞 Commands
|
||||||
|
|
||||||
|
All commands are run from the root of the project, from a terminal:
|
||||||
|
|
||||||
|
| Command | Action |
|
||||||
|
| :------------------------ | :----------------------------------------------- |
|
||||||
|
| `pnpm install` | Installs dependencies |
|
||||||
|
| `pnpm dev` | Starts local dev server at `localhost:4321` |
|
||||||
|
| `pnpm build` | Build your production site to `./dist/` |
|
||||||
|
| `pnpm preview` | Preview your build locally, before deploying |
|
||||||
|
| `pnpm astro ...` | Run CLI commands like `astro add`, `astro check` |
|
||||||
|
| `pnpm astro -- --help` | Get help using the Astro CLI |
|
||||||
|
|
||||||
|
## 👀 Want to learn more?
|
||||||
|
|
||||||
|
Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat).
|
47
official/astro.config.mjs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import { defineConfig } from 'astro/config';
|
||||||
|
import mdx from '@astrojs/mdx';
|
||||||
|
import react from '@astrojs/react';
|
||||||
|
import sitemap from '@astrojs/sitemap';
|
||||||
|
import pkgs from './package.json';
|
||||||
|
import tailwindcss from '@tailwindcss/vite';
|
||||||
|
|
||||||
|
const isDev = process.env.NODE_ENV === 'development';
|
||||||
|
const plugins = [tailwindcss()];
|
||||||
|
|
||||||
|
let target = process.env.VITE_API_URL || 'https://localhost:51015';
|
||||||
|
const apiProxy = { target: target, changeOrigin: true, ws: true, rewriteWsOrigin: true, secure: false, cookieDomainRewrite: 'localhost' };
|
||||||
|
let proxy = {
|
||||||
|
'/root/center/': {
|
||||||
|
target: `${target}/root/center/`,
|
||||||
|
},
|
||||||
|
'/user/login/': {
|
||||||
|
target: `${target}/user/login/`,
|
||||||
|
},
|
||||||
|
'/api': apiProxy,
|
||||||
|
'/client': apiProxy,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
// ...
|
||||||
|
site: 'https://www.kevisual.cn/',
|
||||||
|
// base: isDev ? undefined : pkgs.basename,
|
||||||
|
base: isDev ? undefined : './',
|
||||||
|
integrations: [
|
||||||
|
mdx(),
|
||||||
|
react(), //
|
||||||
|
sitemap(), // sitemap must be site has a domain
|
||||||
|
],
|
||||||
|
|
||||||
|
vite: {
|
||||||
|
plugins,
|
||||||
|
define: {
|
||||||
|
BASE_NAME: JSON.stringify(pkgs.basename),
|
||||||
|
},
|
||||||
|
server: {
|
||||||
|
port: 7008,
|
||||||
|
host: '0.0.0.0',
|
||||||
|
allowedHosts: true,
|
||||||
|
proxy,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
21
official/package.json
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"name": "@kevisual/official-website",
|
||||||
|
"version": "0.0.4",
|
||||||
|
"type": "module",
|
||||||
|
"basename": "/root/official",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "astro dev",
|
||||||
|
"build": "astro build",
|
||||||
|
"preview": "astro preview",
|
||||||
|
"astro": "astro",
|
||||||
|
"pub": "envision deploy ./dist -k official -v 0.0.4 -u -o root"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"astro": "^5.12.3"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@astrojs/mdx": "^4.3.1",
|
||||||
|
"@astrojs/react": "^4.3.0",
|
||||||
|
"@astrojs/sitemap": "^3.4.1"
|
||||||
|
}
|
||||||
|
}
|
4095
official/pnpm-lock.yaml
generated
Normal file
9
official/public/favicon.svg
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 128 128">
|
||||||
|
<path d="M50.4 78.5a75.1 75.1 0 0 0-28.5 6.9l24.2-65.7c.7-2 1.9-3.2 3.4-3.2h29c1.5 0 2.7 1.2 3.4 3.2l24.2 65.7s-11.6-7-28.5-7L67 45.5c-.4-1.7-1.6-2.8-2.9-2.8-1.3 0-2.5 1.1-2.9 2.7L50.4 78.5Zm-1.1 28.2Zm-4.2-20.2c-2 6.6-.6 15.8 4.2 20.2a17.5 17.5 0 0 1 .2-.7 5.5 5.5 0 0 1 5.7-4.5c2.8.1 4.3 1.5 4.7 4.7.2 1.1.2 2.3.2 3.5v.4c0 2.7.7 5.2 2.2 7.4a13 13 0 0 0 5.7 4.9v-.3l-.2-.3c-1.8-5.6-.5-9.5 4.4-12.8l1.5-1a73 73 0 0 0 3.2-2.2 16 16 0 0 0 6.8-11.4c.3-2 .1-4-.6-6l-.8.6-1.6 1a37 37 0 0 1-22.4 2.7c-5-.7-9.7-2-13.2-6.2Z" />
|
||||||
|
<style>
|
||||||
|
path { fill: #000; }
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
path { fill: #FFF; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 749 B |
2
official/public/robots.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
User-agent: *
|
||||||
|
Allow: /
|
216
official/src/apps/index/App.tsx
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
import { Mail, Phone, MapPin, Book, Globe, Brain, Save } from 'lucide-react';
|
||||||
|
import { ToastContainer } from 'react-toastify';
|
||||||
|
import { Provider } from './Provider';
|
||||||
|
import Logo from './assets/logo-1.png';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { toastWeChat } from './modules/RedirectSuccess.tsx';
|
||||||
|
import { WeChat } from './components/Icon.tsx';
|
||||||
|
import { getOrigin } from './modules/get-origin.ts';
|
||||||
|
|
||||||
|
export const openEditor = () => {
|
||||||
|
window.open('./editor');
|
||||||
|
};
|
||||||
|
export const Main = () => {
|
||||||
|
const [url] = useState<string>('https://kevisual.cn');
|
||||||
|
return (
|
||||||
|
<div className='min-h-screen bg-gray-50'>
|
||||||
|
{/* Hero Section */}
|
||||||
|
<div className=''>
|
||||||
|
<nav className='px-4 mx-auto h-16 flex justify-between items-center bg-white border-b border-b-gray-200 w-full'>
|
||||||
|
<div
|
||||||
|
className='flex items-center space-x-4 cursor-pointer'
|
||||||
|
onClick={() => {
|
||||||
|
window.open(url, '_blank');
|
||||||
|
}}>
|
||||||
|
<img src={Logo.src} alt='可视化助手 Logo' className='h-10 w-30 ' />
|
||||||
|
</div>
|
||||||
|
<div className='hidden md:flex space-x-6'>
|
||||||
|
<a
|
||||||
|
className='hover:text-gray-400 cursor-pointer'
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const url = new URL('/root/center/', getOrigin());
|
||||||
|
window.open(url.toString(), '_blank');
|
||||||
|
}}>
|
||||||
|
管理中心
|
||||||
|
</a>
|
||||||
|
<a href='#features' className='hover:text-gray-400 cursor-pointer'>
|
||||||
|
功能
|
||||||
|
</a>
|
||||||
|
<a href='#contact' className='hover:text-gray-400 cursor-pointer'>
|
||||||
|
联系方式
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<article className='container mx-auto px-6 py-10 bg-gray-50'>
|
||||||
|
<div className='mx-auto bg-white p-8 py-10 rounded-lg shadow-lg'>
|
||||||
|
<h2 className='text-3xl font-bold mb-8 text-center'>网页部署平台</h2>
|
||||||
|
<p className='text-gray-700 mb-6'>
|
||||||
|
Kevisual设计助手提供强大的网页部署平台,让您轻松管理自己的博客和自定义网页。无论是个人博客、AI生成的网页,还是专业项目,都能通过我们的平台进行高效管理。
|
||||||
|
</p>
|
||||||
|
<div className='grid md:grid-cols-2 gap-8 mt-10'>
|
||||||
|
<div>
|
||||||
|
<h3 className='text-xl font-semibold mb-4'>功能亮点</h3>
|
||||||
|
<ul className='list-disc pl-5 space-y-2 text-gray-600'>
|
||||||
|
<li>类似图床的文件管理系统,高效整理各类资源</li>
|
||||||
|
<li>一键创建、删除和管理多个站点</li>
|
||||||
|
<li>支持自定义域名,打造专属网络形象</li>
|
||||||
|
<li>权限控制系统,可设置为仅自己可访问或公开共享</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className='text-xl font-semibold mb-4'>使用场景</h3>
|
||||||
|
<ul className='list-disc pl-5 space-y-2 text-gray-600'>
|
||||||
|
<li>个人博客与作品集展示</li>
|
||||||
|
<li className='text-blue-600 hover:underline cursor-pointer' onClick={openEditor}>
|
||||||
|
临时网页快速部署
|
||||||
|
</li>
|
||||||
|
<li>AI生成内容的发布与管理</li>
|
||||||
|
<li>小型项目的在线展示</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='mt-8 text-center'>
|
||||||
|
<a href='./docs/features' className='inline-flex items-center text-blue-600 hover:underline font-medium cursor-not-allowed'>
|
||||||
|
了解更多功能
|
||||||
|
<svg className='w-4 h-4 ml-1' fill='none' stroke='currentColor' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'>
|
||||||
|
<path strokeLinecap='round' strokeLinejoin='round' strokeWidth='2' d='M9 5l7 7-7 7'></path>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
{/* Features Section */}
|
||||||
|
<section id='features' className='container mx-auto px-6 py-10 bg-gray-50'>
|
||||||
|
<div className='mx-auto bg-white p-8 py-10 rounded-lg shadow-lg'>
|
||||||
|
<h2 className='text-3xl font-bold text-center mb-16'>核心功能</h2>
|
||||||
|
|
||||||
|
<div className='grid md:grid-cols-3 gap-12'>
|
||||||
|
<div className='p-6 rounded-lg shadow-lg bg-white'>
|
||||||
|
<Globe className='w-12 h-12 text-blue-600 mb-4' />
|
||||||
|
<h3 className='text-xl font-semibold mb-4'>网页部署平台</h3>
|
||||||
|
<p className='text-gray-600'>轻松管理您的博客和自定义网页,支持文件管理、站点创建和域名自定义</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='p-6 rounded-lg shadow-lg bg-white'>
|
||||||
|
<Brain className='w-12 h-12 text-blue-600 mb-4' />
|
||||||
|
<h3 className='text-xl font-semibold mb-4'>应用共享</h3>
|
||||||
|
<p className='text-gray-600'>根据用户需求,某一些应用只能自己访问或者共享</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='p-6 rounded-lg shadow-lg bg-white'>
|
||||||
|
<Book className='w-12 h-12 text-blue-600 mb-4' />
|
||||||
|
<h3 className='text-xl font-semibold mb-4'>临时网页</h3>
|
||||||
|
<p className='text-gray-600'>当个网页助手,帮助您快速生成临时网页</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Contact Section */}
|
||||||
|
<section id='contact' className='container mx-auto px-6 py-10 bg-gray-50'>
|
||||||
|
<div className='mx-auto bg-white p-8 py-10 rounded-lg shadow-lg'>
|
||||||
|
<h2 className='text-3xl font-bold text-center mb-16'>联系我们</h2>
|
||||||
|
<div className='max-w-2xl mx-auto w-[300px]'>
|
||||||
|
<div className='space-y-6'>
|
||||||
|
<div className='flex items-center space-x-4'>
|
||||||
|
<Mail className='w-6 h-6 text-blue-600' />
|
||||||
|
<span>kevisual@kevisual.cn</span>
|
||||||
|
</div>
|
||||||
|
<div className='flex items-center space-x-4'>
|
||||||
|
<Phone className='w-6 h-6 text-blue-600' />
|
||||||
|
<span>18324451015</span>
|
||||||
|
</div>
|
||||||
|
<div className='flex items-center space-x-4'>
|
||||||
|
<MapPin className='w-6 h-6 text-blue-600' />
|
||||||
|
<span>浙江省杭州市拱墅区杭州北部软件园</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Footer */}
|
||||||
|
<footer className='bg-gray-900 text-white py-12'>
|
||||||
|
<div className='container mx-auto px-6'>
|
||||||
|
<div className='grid md:grid-cols-4 gap-8'>
|
||||||
|
<div>
|
||||||
|
<h3 className='text-lg font-semibold mb-4'>Kevisual 助手</h3>
|
||||||
|
<p className='text-gray-400'>加速你的生活,学习,设计,工作。</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className='text-lg font-semibold mb-4'>快速链接</h3>
|
||||||
|
<ul className='space-y-2 text-gray-400'>
|
||||||
|
<li>
|
||||||
|
<a href='#features' className='hover:text-white'>
|
||||||
|
功能
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href='#contact' className='hover:text-white'>
|
||||||
|
联系方式
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className='text-lg font-semibold mb-4'>法律信息</h3>
|
||||||
|
<ul className='space-y-2 text-gray-400'>
|
||||||
|
<li>
|
||||||
|
<a href='./privacy' className='hover:text-white'>
|
||||||
|
隐私政策
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href='./terms' className='hover:text-white'>
|
||||||
|
用户协议
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className='text-lg font-semibold mb-4'>联系我们</h3>
|
||||||
|
<div className='flex space-x-4'>
|
||||||
|
<a href='mailto:feedback@kevisual.cn' className='text-gray-400 hover:text-white cursor-pointer'>
|
||||||
|
<Mail className='w-6 h-6' />
|
||||||
|
</a>
|
||||||
|
<a href='tel:18324451015' className='text-gray-400 hover:text-white cursor-pointer'>
|
||||||
|
<Phone className='w-6 h-6' />
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
className='text-gray-400 hover:text-white cursor-pointer'
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
toastWeChat();
|
||||||
|
}}>
|
||||||
|
<WeChat className='w-6 h-6' />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className='mt-12 pt-8 border-t border-gray-800 text-center text-gray-400'
|
||||||
|
onClick={() => {
|
||||||
|
window.open('https://beian.miit.gov.cn/', '_blank');
|
||||||
|
}}>
|
||||||
|
<p>浙ICP备2025158778号</p>
|
||||||
|
<p>© 2025 杭州余杭逸文设计工作室. All rights reserved.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const App = () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Provider>
|
||||||
|
<ToastContainer autoClose={2000}></ToastContainer>
|
||||||
|
<Main />
|
||||||
|
</Provider>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
107
official/src/apps/index/Editor.tsx
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
import { Mail, Phone, MapPin, Book, Globe, Brain, Save } from 'lucide-react';
|
||||||
|
import { chain, TextEditor } from './components/TextEditor';
|
||||||
|
import { toast, ToastContainer } from 'react-toastify';
|
||||||
|
import { Provider } from './Provider';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { CodeDescModal } from './modules/CodeDescModal';
|
||||||
|
import { query } from './modules/query.ts';
|
||||||
|
import { toastSuccess, toastWeChat } from './modules/RedirectSuccess.tsx';
|
||||||
|
import { getOrigin } from './modules/get-origin.ts';
|
||||||
|
|
||||||
|
export const Editor = () => {
|
||||||
|
const [showPreview, setShowPreview] = useState(false);
|
||||||
|
const [html, setHtml] = useState<string>('');
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
const [resultUrl, setResultUrl] = useState<string>('');
|
||||||
|
const [url] = useState<string>('https://kevisual.cn');
|
||||||
|
const onSubmit = async (values: { title: string; description: string }) => {
|
||||||
|
setResultUrl('');
|
||||||
|
const uploadData = {
|
||||||
|
title: values?.title,
|
||||||
|
description: values?.description,
|
||||||
|
content: chain.getContent(),
|
||||||
|
};
|
||||||
|
const res = await query.post({
|
||||||
|
path: 'app',
|
||||||
|
key: 'public-upload-html',
|
||||||
|
data: uploadData,
|
||||||
|
});
|
||||||
|
if (res.code === 200) {
|
||||||
|
const url = res.data?.url;
|
||||||
|
if (url) {
|
||||||
|
let origin = getOrigin();
|
||||||
|
const newUrl = new URL(url, origin);
|
||||||
|
// toast.success('创建成功, 访问地址' + newUrl.toString(), { autoClose: 3000 });
|
||||||
|
toastSuccess(newUrl.toString());
|
||||||
|
setResultUrl(newUrl.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<main
|
||||||
|
className='flex flex-col overflow-hidden'
|
||||||
|
style={{
|
||||||
|
height: 'calc(100vh - 64px)',
|
||||||
|
}}>
|
||||||
|
<nav className='h-12 bg-white flex'>
|
||||||
|
<button
|
||||||
|
className='flex items-center px-4 h-full bg-white border-b border-b-gray-200 hover:bg-gray-50 cursor-pointer'
|
||||||
|
onClick={() => {
|
||||||
|
const content = chain.getContent();
|
||||||
|
if (!content) {
|
||||||
|
toast.error('内容不能为空', { position: 'top-center', autoClose: 1000 });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setOpen(true);
|
||||||
|
}}>
|
||||||
|
<span className='text-gray-700'>创建</span>
|
||||||
|
<Save className='ml-2 w-4 h-4 text-gray-500' />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
className='flex items-center px-4 h-full bg-white border-b border-b-gray-200 hover:bg-gray-50 cursor-pointer'
|
||||||
|
style={{
|
||||||
|
backgroundColor: showPreview ? '#f0f0f0' : 'white',
|
||||||
|
}}
|
||||||
|
onClick={() => {
|
||||||
|
setShowPreview(!showPreview);
|
||||||
|
}}>
|
||||||
|
<span className='text-gray-700'>预览</span>
|
||||||
|
<Globe className='ml-2 w-4 h-4 text-gray-500' />
|
||||||
|
</button>
|
||||||
|
</nav>
|
||||||
|
<div className='p-2 rounded shadow flex' style={{ height: 'calc(100% - 48px - 48px)' }}>
|
||||||
|
<div className='h-full overflow-auto flex-1'>
|
||||||
|
<TextEditor content={''} chain={chain} onChange={setHtml} />
|
||||||
|
</div>
|
||||||
|
{showPreview && (
|
||||||
|
<div className='w-1/2 shrink-1 border-l border-gray-200 h-full overflow-auto'>
|
||||||
|
<iframe className='w-full h-full border-0' srcDoc={html} title='预览' sandbox='allow-scripts allow-same-origin allow-popups' />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<footer className='h-12'>
|
||||||
|
{!resultUrl && <div className='flex items-center h-full text-gray-500 px-2 italic'>粘贴您的 HTML 内容到编辑器中,点击“创建”按钮生成链接。</div>}
|
||||||
|
{resultUrl && (
|
||||||
|
<div className='flex items-center gap-2 px-4 h-full bg-white border-t border-t-gray-200'>
|
||||||
|
<span className='text-gray-700'>生成的链接:</span>
|
||||||
|
<a href={resultUrl} target='_blank' rel='noopener noreferrer' className='text-blue-600 hover:underline'>
|
||||||
|
{resultUrl}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</footer>
|
||||||
|
<CodeDescModal open={open} onClose={() => setOpen(false)} onSubmit={onSubmit} />
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export const App = () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Provider>
|
||||||
|
<ToastContainer autoClose={2000}></ToastContainer>
|
||||||
|
<Editor />
|
||||||
|
</Provider>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
19
official/src/apps/index/Provider.tsx
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import ConfigProvider from 'antd/lib/config-provider';
|
||||||
|
import '@ant-design/v5-patch-for-react-19';
|
||||||
|
|
||||||
|
export const Provider = ({ children }: { children: React.ReactNode }) => {
|
||||||
|
return (
|
||||||
|
<ConfigProvider
|
||||||
|
theme={{
|
||||||
|
token: {
|
||||||
|
colorPrimary: '#1677ff',
|
||||||
|
colorTextBase: '#ffffff',
|
||||||
|
colorBgBase: '#1f1f1f',
|
||||||
|
colorBgContainer: '#2c2c2c',
|
||||||
|
colorBorder: '#3a3a3a',
|
||||||
|
},
|
||||||
|
}}>
|
||||||
|
{children}
|
||||||
|
</ConfigProvider>
|
||||||
|
);
|
||||||
|
};
|
BIN
official/src/apps/index/assets/logo-1.png
Normal file
After Width: | Height: | Size: 230 KiB |
11
official/src/apps/index/components/EvWechat.tsx
Normal file
24
official/src/apps/index/components/Icon.tsx
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
export const Github = () => {
|
||||||
|
return (
|
||||||
|
<svg aria-hidden='true' height='24' viewBox='0 0 24 24' version='1.1' width='24' data-view-component='true' className='octicon octicon-mark-github'>
|
||||||
|
<path d='M12 1C5.923 1 1 5.923 1 12c0 4.867 3.149 8.979 7.521 10.436.55.096.756-.233.756-.522 0-.262-.013-1.128-.013-2.049-2.764.509-3.479-.674-3.699-1.292-.124-.317-.66-1.293-1.127-1.554-.385-.207-.936-.715-.014-.729.866-.014 1.485.797 1.691 1.128.99 1.663 2.571 1.196 3.204.907.096-.715.385-1.196.701-1.471-2.448-.275-5.005-1.224-5.005-5.432 0-1.196.426-2.186 1.128-2.956-.111-.275-.496-1.402.11-2.915 0 0 .921-.288 3.024 1.128a10.193 10.193 0 0 1 2.75-.371c.936 0 1.871.123 2.75.371 2.104-1.43 3.025-1.128 3.025-1.128.605 1.513.221 2.64.111 2.915.701.77 1.127 1.747 1.127 2.956 0 4.222-2.571 5.157-5.019 5.432.399.344.743 1.004.743 2.035 0 1.471-.014 2.654-.014 3.025 0 .289.206.632.756.522C19.851 20.979 23 16.854 23 12c0-6.077-4.922-11-11-11Z'></path>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const WeChat = (props: React.SVGProps<SVGSVGElement>) => {
|
||||||
|
return (
|
||||||
|
<div className={'relative ' + props.className}>
|
||||||
|
<svg viewBox='0 0 1024 1024' version='1.1' xmlns='http://www.w3.org/2000/svg' className='w-8 h-8 absolute -top-1 left-0'>
|
||||||
|
<path
|
||||||
|
fill='currentColor'
|
||||||
|
d='M289.8 367.2c0-13.6 7.8-25.4 19.8-31.2 21.3-10.2 49.2 3.5 49.2 32.5 0 18-16 33.5-34.2 33.5-19.4 0-34.8-15.3-34.8-34.8z m174.2 0.7c0-13.7 8.5-26.2 18.9-31.4 12.7-6.3 28.1-4.6 38.6 4.8 11.8 10.5 15 29.4 7.8 42.3-14.3 25.5-49.9 24.2-61.9-1.7-1.5-3.4-3.4-9.6-3.4-14zM149.9 433c0 27.3 2.4 43 10.7 66.7 8.4 24 24 49.6 41.4 68.3 1.6 1.7 2.1 2.7 3.9 4.5l22 20.6c1.6 1.3 3.1 2.4 4.7 3.7 1.7 1.3 2.9 2.3 4.7 3.7 14.3 10.7 10.8 17.2 5.3 36.7l-8.1 30c-2.8 9.5 1.9 14.7 8.2 14.4 4.1-0.2 20.8-10.9 24.6-13.1l40.6-23.3c11.2-5 19-0.9 32.4 2.5 18.6 4.7 28.6 5.3 47.5 7.3l38.1 0.4c-0.8-9.7-8.4-17.1-8.4-58.5 0-16 3.9-33.9 7.8-46.4 5.7-18 16.3-38.3 27.8-53.5l18.8-21.9 14.2-12.9c2.7-2.3 5-4.1 7.8-6.4l39.3-24.6c39.3-18.7 75.6-28.5 124.9-28.5l9.7 0.7c3.1-0.2 3 1.2-0.6-13.1-4.4-17.7-12.1-35.2-21.5-50.8-12.7-21.2-22.5-31.3-39.1-47.9-15.6-15.6-41.7-32.5-60.6-42-15.7-7.8-25.1-11.3-41.7-16.9-14.8-5-30.2-8.1-47.2-10.8-8.6-1.4-17.5-1.9-26.2-2.9-4.5-0.5-10.1 0.2-14.7-0.1-43.9-2.5-103.7 11.4-141.6 31.8-1.9 1-2.5 1.5-4.5 2.6l-23 13.8c-12.4 9.4-20.3 13.9-32.6 26.1l-27.1 30.9c-20.5 30.3-37.5 64.8-37.5 108.9z'
|
||||||
|
p-id='1534'></path>
|
||||||
|
<path
|
||||||
|
fill='currentColor'
|
||||||
|
d='M554.2 543.9c0-16.4 12.2-29 29.7-29 23 0 35.1 27 22.9 44.9-0.7 1-0.7 0.8-1.4 1.8-0.9 1.2-0.8 1.2-1.7 2.2-1.9 2.1-5.3 4.3-8 5.6-11 5.3-23.7 3.6-32.4-4.8-5-5-9.1-11.6-9.1-20.7z m172.2-29h3.9c12.9 0 26.4 13 26.4 25.8 0 9.7-0.7 16-8.5 23.7-21.5 21.1-58.7-3-46.5-31.6 2.8-6.6 7.2-11.6 13.5-14.9 2.9-1.5 7.1-3 11.2-3z m-288.9 81.2c0 22.7 0.9 30.3 6.8 51.2 4.8 16.9 14.2 34 24.1 48.1l10.8 13.7c4.5 4.6 9.7 11.1 14.6 15.1 1.6 1.3 2 1.4 3.5 2.9 5.9 5.9 19.5 15.3 27.3 20.3 2.5 1.6 5.2 3.2 7.7 4.6 32.4 18.5 75.8 31.6 113.5 31.6 32.4 0 45.6-0.6 76.6-8.5 14.5-3.7 16.8-2.2 29.6 5.5l39.5 23c8.3 4.8 13.8-1.8 12.4-7.9l-2.6-9.7c-1.7-6.8-3.5-13.2-5.3-19.9-2.6-10-7.3-19.7 2.6-27 18.5-13.6 30.2-25.7 43.8-43.8 19.1-25.3 31.5-61.5 31.5-93.6 0-7.2-1-16.1-1.9-22.6-3.8-27.5-17.1-56.9-34.4-77.8l-24.5-25.8c-2.3-2.1-4.7-3.6-7.1-5.8-5.6-5-22.9-16.3-29.7-19.9-74.4-39.8-165.2-41.3-239.4-1.3-5.3 2.8-10.4 5.9-15.3 9.2-5.5 3.7-16.7 11.4-21.5 15.9-1.2 1.2-1.5 1.6-3 2.8-1.7 1.3-2 1.5-3.4 3-14.7 14.9-22 21.8-33.4 40.8-12.3 20.7-22.8 50.2-22.8 75.9z'
|
||||||
|
p-id='1535'></path>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
51
official/src/apps/index/components/TextEditor.tsx
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
import { createEditor } from '@kevisual/codemirror';
|
||||||
|
import { Chain } from '@kevisual/codemirror/utils';
|
||||||
|
import { useEffect, useRef } from 'react';
|
||||||
|
import { CacheWorkspace } from '@kevisual/cache';
|
||||||
|
|
||||||
|
export const chain = new Chain();
|
||||||
|
type TextEditorProps = {
|
||||||
|
content: string;
|
||||||
|
chain?: Chain;
|
||||||
|
onChange?: (content: string) => void;
|
||||||
|
};
|
||||||
|
export const TextEditor = ({ content, chain, onChange }: TextEditorProps) => {
|
||||||
|
const editorElRef = useRef<HTMLDivElement>(null);
|
||||||
|
const editorRef = useRef<ReturnType<typeof createEditor>>(null);
|
||||||
|
useEffect(() => {
|
||||||
|
initEditor();
|
||||||
|
return () => {
|
||||||
|
if (editorRef.current) {
|
||||||
|
chain?.destroy?.();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
useEffect(() => {
|
||||||
|
if (editorRef.current) {
|
||||||
|
chain?.setContent?.(content);
|
||||||
|
}
|
||||||
|
}, [content]);
|
||||||
|
const initEditor = async () => {
|
||||||
|
if (!editorElRef.current) return;
|
||||||
|
const cache = new CacheWorkspace();
|
||||||
|
const editor = createEditor(editorElRef.current, {
|
||||||
|
type: 'html',
|
||||||
|
onChange: (value) => {
|
||||||
|
cache.set('editor-content-home', value);
|
||||||
|
onChange?.(value);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const value = await cache.get('editor-content-home');
|
||||||
|
const cmScroller = editorElRef.current.querySelector('.cm-scroller');
|
||||||
|
if (cmScroller) {
|
||||||
|
cmScroller.classList.add('scrollbar');
|
||||||
|
}
|
||||||
|
chain?.setEditor?.(editor);
|
||||||
|
editorRef.current = editor;
|
||||||
|
if (value) {
|
||||||
|
chain?.setContent?.(value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return <div className='h-full overflow-hidden' ref={editorElRef}></div>;
|
||||||
|
};
|
1
official/src/apps/index/index.css
Normal file
@@ -0,0 +1 @@
|
|||||||
|
@import 'tailwindcss';
|
9
official/src/apps/index/main.tsx
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { createRoot } from 'react-dom/client';
|
||||||
|
|
||||||
|
import { App } from './App';
|
||||||
|
import './index.css';
|
||||||
|
|
||||||
|
const root = createRoot(document.getElementById('root') as HTMLElement);
|
||||||
|
|
||||||
|
root.render(<App />);
|
||||||
|
|
51
official/src/apps/index/modules/CodeDescModal.tsx
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
import Modal from 'antd/es/modal/Modal';
|
||||||
|
import Form, { useForm } from 'antd/es/form/Form';
|
||||||
|
import FormItem from 'antd/es/form/FormItem';
|
||||||
|
import Input from 'antd/es/input';
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
|
type CodeDescModalProps = {
|
||||||
|
open: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
onSubmit?: (values: { title: string; description: string }) => void;
|
||||||
|
initialValues?: { title: string; description: string };
|
||||||
|
};
|
||||||
|
export const CodeDescModal = (props: CodeDescModalProps) => {
|
||||||
|
const [form] = useForm();
|
||||||
|
useEffect(() => {
|
||||||
|
if (!props.open) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (props.initialValues) {
|
||||||
|
form.setFieldsValue(props.initialValues || { title: '', description: '' });
|
||||||
|
}
|
||||||
|
}, [props.open, props.initialValues, form]);
|
||||||
|
return (
|
||||||
|
<Modal title='代码描述' open={props.open} onCancel={props.onClose} footer={null}>
|
||||||
|
<p className='text-gray-500 text-sm mb-4'>登陆用户的数据长存,非登陆的用户,保留30天自动删除。</p>
|
||||||
|
<Form form={form} layout='vertical'>
|
||||||
|
<FormItem label='标题' name='title'>
|
||||||
|
<Input />
|
||||||
|
</FormItem>
|
||||||
|
<FormItem label='描述' name='description'>
|
||||||
|
<Input.TextArea rows={4} />
|
||||||
|
</FormItem>
|
||||||
|
</Form>
|
||||||
|
<div className='flex justify-end mt-4'>
|
||||||
|
<button
|
||||||
|
className='px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 cursor-pointer'
|
||||||
|
onClick={() => {
|
||||||
|
form.validateFields().then((values) => {
|
||||||
|
props.onSubmit?.(values);
|
||||||
|
props.onClose();
|
||||||
|
});
|
||||||
|
}}>
|
||||||
|
提交
|
||||||
|
</button>
|
||||||
|
<button className='ml-2 px-4 py-2 bg-gray-300 text-gray-700 rounded hover:bg-gray-400 cursor-pointer' onClick={props.onClose}>
|
||||||
|
取消
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
35
official/src/apps/index/modules/RedirectSuccess.tsx
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import { EvWechat } from '../components/EvWechat';
|
||||||
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
|
export const RedirectSuccess = ({ url }: { url: string }) => {
|
||||||
|
return (
|
||||||
|
<div className='flex flex-col items-center justify-center p-2'>
|
||||||
|
<div className='flex flex-col gap-2 mb-3'>
|
||||||
|
<div className=' font-semibold'>创建成功</div>
|
||||||
|
<a
|
||||||
|
href={url}
|
||||||
|
className='text-blue-600 hover:text-blue-800 transition-colors duration-200 hover:underline block truncate'
|
||||||
|
target='_blank'
|
||||||
|
rel='noopener noreferrer'>
|
||||||
|
跳转到新应用
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const toastSuccess = (url: string) => {
|
||||||
|
toast.success(<RedirectSuccess url={url} />, {
|
||||||
|
autoClose: 5000,
|
||||||
|
className: 'rounded-md shadow-lg',
|
||||||
|
// icon: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const toastWeChat = () => {
|
||||||
|
toast.success(<EvWechat />, {
|
||||||
|
autoClose: 10000,
|
||||||
|
className: 'rounded-md shadow-lg',
|
||||||
|
icon: false,
|
||||||
|
});
|
||||||
|
};
|
7
official/src/apps/index/modules/get-origin.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export const getOrigin = () => {
|
||||||
|
let origin = window.location.origin;
|
||||||
|
if (origin.includes('www.kevisual.cn')) {
|
||||||
|
origin = origin.replace('www.kevisual.cn', 'kevisual.cn');
|
||||||
|
}
|
||||||
|
return origin;
|
||||||
|
};
|
3
official/src/apps/index/modules/query.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import { QueryClient } from '@kevisual/query';
|
||||||
|
|
||||||
|
export const query = new QueryClient();
|
21
official/src/pages/editor.astro
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
import '../apps/index/index.css';
|
||||||
|
import { App } from '../apps/index/Editor.tsx';
|
||||||
|
---
|
||||||
|
|
||||||
|
<!doctype html>
|
||||||
|
<html lang='zh-CN'>
|
||||||
|
<head>
|
||||||
|
<meta charset='UTF-8' />
|
||||||
|
<link rel='icon' type='image/svg+xml' href='https://kevisual.cn/root/center/panda.jpg' />
|
||||||
|
<meta name='viewport' content='width=device-width, initial-scale=1.0' />
|
||||||
|
<meta name='description' content='Kevisual 是一个专注于可视化设计, AI使用助手的工作室' />
|
||||||
|
<meta name='generator' content={Astro.generator} />
|
||||||
|
<meta name="baidu-site-verification" content="codeva-qAEXUzv0tn" />
|
||||||
|
<title>逸文设计工作室</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<App client:only />
|
||||||
|
</body>
|
||||||
|
</html>
|
21
official/src/pages/index.astro
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
import '../apps/index/index.css';
|
||||||
|
import { App } from '../apps/index/App.tsx';
|
||||||
|
---
|
||||||
|
|
||||||
|
<!doctype html>
|
||||||
|
<html lang='zh-CN'>
|
||||||
|
<head>
|
||||||
|
<meta charset='UTF-8' />
|
||||||
|
<link rel='icon' type='image/svg+xml' href='https://kevisual.cn/root/center/panda.jpg' />
|
||||||
|
<meta name='viewport' content='width=device-width, initial-scale=1.0' />
|
||||||
|
<meta name='description' content='Kevisual 是一个专注于可视化设计, AI使用助手的工作室' />
|
||||||
|
<meta name='generator' content={Astro.generator} />
|
||||||
|
<meta name="baidu-site-verification" content="codeva-qAEXUzv0tn" />
|
||||||
|
<title>逸文设计工作室</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<App client:only />
|
||||||
|
</body>
|
||||||
|
</html>
|
5
official/tsconfig.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"extends": "astro/tsconfigs/strict",
|
||||||
|
"include": [".astro/types.d.ts", "**/*"],
|
||||||
|
"exclude": ["dist"]
|
||||||
|
}
|
30
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@kevisual/official-website",
|
"name": "@kevisual/official-website",
|
||||||
"version": "0.0.1",
|
"version": "0.0.2",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"basename": "/root/official",
|
"basename": "/root/official",
|
||||||
@@ -8,24 +8,32 @@
|
|||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"pub": "envision deploy ./dist -k official -v 0.0.1 -u -o root"
|
"pub": "envision deploy ./dist -k official -v 0.0.2 -u -o root"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "abearxiong <xiongxiao@xiongxiao.me>",
|
"author": "abearxiong <xiongxiao@xiongxiao.me>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@ant-design/v5-patch-for-react-19": "^1.0.3",
|
||||||
|
"@kevisual/query": "^0.0.29",
|
||||||
|
"antd": "^5.26.2",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"lucide-react": "^0.483.0",
|
"lucide-react": "^0.522.0",
|
||||||
"react": "^19.0.0",
|
"react": "^19.1.0",
|
||||||
"react-dom": "^19.0.0"
|
"react-dom": "^19.1.0",
|
||||||
|
"rollup-plugin-visualizer": "^6.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tailwindcss/vite": "^4.0.15",
|
"@kevisual/cache": "^0.0.3",
|
||||||
"@types/react": "^19.0.0",
|
"@kevisual/codemirror": "^0.0.12",
|
||||||
"@types/react-dom": "^19.0.0",
|
"@tailwindcss/vite": "^4.1.10",
|
||||||
"@vitejs/plugin-react": "^4.3.4",
|
"@types/react": "^19.1.8",
|
||||||
"tailwindcss": "^4.0.15",
|
"@types/react-dom": "^19.1.6",
|
||||||
"vite": "^6.2.3"
|
"@vitejs/plugin-react": "^4.6.0",
|
||||||
|
"react-feather": "^2.0.10",
|
||||||
|
"react-toastify": "^11.0.5",
|
||||||
|
"tailwindcss": "^4.1.10",
|
||||||
|
"vite": "^7.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
2927
pnpm-lock.yaml
generated
6
pnpm-workspace.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
packages:
|
||||||
|
- backup
|
||||||
|
- official
|
||||||
|
onlyBuiltDependencies:
|
||||||
|
- '@tailwindcss/oxide'
|
||||||
|
- esbuild
|
178
src/App.tsx
@@ -1,178 +0,0 @@
|
|||||||
import { Github, Mail, Phone, MapPin, ChevronDown, ExternalLink, Shield, Book, Globe, Brain } from 'lucide-react';
|
|
||||||
|
|
||||||
export const App = () => {
|
|
||||||
return (
|
|
||||||
<div className='min-h-screen bg-gray-50'>
|
|
||||||
{/* Hero Section */}
|
|
||||||
<header className='bg-gradient-to-r from-blue-600 to-indigo-700 text-white'>
|
|
||||||
<nav className='container mx-auto px-6 py-4 flex justify-between items-center'>
|
|
||||||
<div className='flex items-center space-x-4'>
|
|
||||||
<img src='https://kevisual.cn/root/center/panda.png' alt='Kevisual Logo' className='h-10 w-10 object-contain' />
|
|
||||||
<span className='text-xl font-bold'>Kevisual 助手</span>
|
|
||||||
</div>
|
|
||||||
<div className='hidden md:flex space-x-6'>
|
|
||||||
<a href='#features' className='hover:text-gray-200'>
|
|
||||||
功能
|
|
||||||
</a>
|
|
||||||
<a href='#about' className='hover:text-gray-200'>
|
|
||||||
关于我们
|
|
||||||
</a>
|
|
||||||
<a href='#contact' className='hover:text-gray-200'>
|
|
||||||
联系方式
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div className='container mx-auto px-6 py-24 text-center'>
|
|
||||||
<h1 className='text-4xl md:text-6xl font-bold mb-6'>加速你的工作,生活,学习</h1>
|
|
||||||
<p className='text-xl md:text-2xl mb-8 opacity-90'>专业的网页助手,让您的在线体验更轻松、更高效</p>
|
|
||||||
<ChevronDown className='w-8 h-8 mx-auto animate-bounce' />
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
{/* Features Section */}
|
|
||||||
<section id='features' className='py-20 bg-white'>
|
|
||||||
<div className='container mx-auto px-6'>
|
|
||||||
<h2 className='text-3xl font-bold text-center mb-16'>核心功能</h2>
|
|
||||||
|
|
||||||
<div className='grid md:grid-cols-3 gap-12'>
|
|
||||||
<div className='p-6 rounded-lg shadow-lg bg-white'>
|
|
||||||
<Globe className='w-12 h-12 text-blue-600 mb-4' />
|
|
||||||
<h3 className='text-xl font-semibold mb-4'>网页部署平台</h3>
|
|
||||||
<p className='text-gray-600'>轻松管理您的博客和自定义网页,支持文件管理、站点创建和域名自定义</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className='p-6 rounded-lg shadow-lg bg-white'>
|
|
||||||
<Brain className='w-12 h-12 text-blue-600 mb-4' />
|
|
||||||
<h3 className='text-xl font-semibold mb-4'>AI Mark 推荐</h3>
|
|
||||||
<p className='text-gray-600'>智能工具库助您快速找到解决方案,汇集优质开源项目</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className='p-6 rounded-lg shadow-lg bg-white'>
|
|
||||||
<Book className='w-12 h-12 text-blue-600 mb-4' />
|
|
||||||
<h3 className='text-xl font-semibold mb-4'>笔记助手</h3>
|
|
||||||
<p className='text-gray-600'>AI驱动的笔记工具,帮助您创造性地生成美观的内容并进行可视化</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
{/* About Section */}
|
|
||||||
<section id='about' className='py-20 bg-gray-50'>
|
|
||||||
<div className='container mx-auto px-6'>
|
|
||||||
<h2 className='text-3xl font-bold text-center mb-16'>关于我们</h2>
|
|
||||||
<div className='max-w-3xl mx-auto text-center'>
|
|
||||||
<p className='text-gray-600 mb-8'>我们是一个独立开发团队,致力于提供高质量的软件产品。我们的使命是通过创新技术,让用户的工作和生活更加便捷。</p>
|
|
||||||
<div className='grid md:grid-cols-2 gap-8'>
|
|
||||||
<div>
|
|
||||||
<h3 className='text-xl font-semibold mb-4'>我们的使命</h3>
|
|
||||||
<ul className='text-left text-gray-600 space-y-2'>
|
|
||||||
<li>✓ 提供高质量的软件产品</li>
|
|
||||||
<li>✓ 不断创新,满足用户需求</li>
|
|
||||||
<li>✓ 提供优质的售后服务</li>
|
|
||||||
<li>✓ 保护用户隐私</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<h3 className='text-xl font-semibold mb-4'>我们的愿景</h3>
|
|
||||||
<ul className='text-left text-gray-600 space-y-2'>
|
|
||||||
<li>✓ 创立更简单,方便的网页助手</li>
|
|
||||||
<li>✓ 成为用户信赖的软件品牌</li>
|
|
||||||
<li>✓ 持续创新发展</li>
|
|
||||||
<li>✓ 提供卓越的用户体验</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
{/* Contact Section */}
|
|
||||||
<section id='contact' className='py-20 bg-white'>
|
|
||||||
<div className='container mx-auto px-6'>
|
|
||||||
<h2 className='text-3xl font-bold text-center mb-16'>联系我们</h2>
|
|
||||||
<div className='max-w-2xl mx-auto'>
|
|
||||||
<div className='space-y-6'>
|
|
||||||
<div className='flex items-center space-x-4'>
|
|
||||||
<Mail className='w-6 h-6 text-blue-600' />
|
|
||||||
<span>envision@kevisual.cn</span>
|
|
||||||
</div>
|
|
||||||
<div className='flex items-center space-x-4'>
|
|
||||||
<Phone className='w-6 h-6 text-blue-600' />
|
|
||||||
<span>18324451015</span>
|
|
||||||
</div>
|
|
||||||
<div className='flex items-center space-x-4'>
|
|
||||||
<MapPin className='w-6 h-6 text-blue-600' />
|
|
||||||
<span>浙江省杭州市余杭区闲林街道天日山西路230号A区3楼2954室</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
{/* Footer */}
|
|
||||||
<footer className='bg-gray-900 text-white py-12'>
|
|
||||||
<div className='container mx-auto px-6'>
|
|
||||||
<div className='grid md:grid-cols-4 gap-8'>
|
|
||||||
<div>
|
|
||||||
<h3 className='text-lg font-semibold mb-4'>Kevisual 助手</h3>
|
|
||||||
<p className='text-gray-400'>加速你的工作,生活,学习</p>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<h3 className='text-lg font-semibold mb-4'>快速链接</h3>
|
|
||||||
<ul className='space-y-2 text-gray-400'>
|
|
||||||
<li>
|
|
||||||
<a href='#features' className='hover:text-white'>
|
|
||||||
功能
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href='#about' className='hover:text-white'>
|
|
||||||
关于我们
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href='#contact' className='hover:text-white'>
|
|
||||||
联系方式
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<h3 className='text-lg font-semibold mb-4'>法律信息</h3>
|
|
||||||
<ul className='space-y-2 text-gray-400'>
|
|
||||||
<li>
|
|
||||||
<a href='/privacy' className='hover:text-white'>
|
|
||||||
隐私政策
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href='/terms' className='hover:text-white'>
|
|
||||||
用户协议
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<h3 className='text-lg font-semibold mb-4'>联系我们</h3>
|
|
||||||
<div className='flex space-x-4'>
|
|
||||||
<a href='mailto:feedback@kevisual.cn' className='text-gray-400 hover:text-white'>
|
|
||||||
<Mail className='w-6 h-6' />
|
|
||||||
</a>
|
|
||||||
<a href='https://github.com/' className='text-gray-400 hover:text-white'>
|
|
||||||
<Github className='w-6 h-6' />
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className='mt-12 pt-8 border-t border-gray-800 text-center text-gray-400'>
|
|
||||||
<p>浙ICP备2025158778号</p>
|
|
||||||
<p>© 2024 杭州余杭逸文设计工作室. All rights reserved.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default App;
|
|