update for astro
This commit is contained in:
BIN
backup/docs/assets/feature/user-apps.png
Normal file
BIN
backup/docs/assets/feature/user-apps.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 134 KiB |
BIN
backup/docs/assets/feature/user-files.png
Normal file
BIN
backup/docs/assets/feature/user-files.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 74 KiB |
BIN
backup/docs/assets/营业执照.jpg
Normal file
BIN
backup/docs/assets/营业执照.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 464 KiB |
19
backup/docs/公司介绍.md
Normal file
19
backup/docs/公司介绍.md
Normal file
@@ -0,0 +1,19 @@
|
||||
## 公司介绍
|
||||
|
||||
公司名称:杭州余杭逸文设计工作室(个体工商户)
|
||||
|
||||
公司地址:浙江省杭州市余杭区闲林街道天日山西路 230 号 A 区 3 楼 2954 室
|
||||
|
||||
公司邮箱: kevisual@kevisual.cn
|
||||
|
||||
公司经营范围:网站部署,笔记,ai 助手,计算机软件开发。
|
||||
|
||||
公司网页: https://www.kevisual.cn
|
||||
|
||||
公司 logo 图片:
|
||||
|
||||
公司营业执照: 
|
||||
|
||||
举报邮箱: feedback@kevisual.cn
|
||||
|
||||
备案号:浙 ICP 备 2025158778 号
|
||||
25
backup/docs/关于.md
Normal file
25
backup/docs/关于.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# 关于我们
|
||||
|
||||
我们是一个独立开发团队,致力于提供高质量的软件产品。我们的团队成员都是经验丰富的开发者,他们有着对技术的深刻理解和创新能力。
|
||||
|
||||
我们的使命是:
|
||||
|
||||
1. 提供高质量的软件产品
|
||||
2. 不断创新,满足用户需求
|
||||
3. 提供优质的售后服务
|
||||
4. 保护用户隐私
|
||||
|
||||
我们的愿景是:
|
||||
|
||||
1. 创立更简单,方便的网页助手,让生活更美好。
|
||||
2. 成为用户信赖的软件品牌
|
||||
3. 不断创新,满足用户需求
|
||||
4. 提供优质的售后服务
|
||||
|
||||
联系信息:
|
||||
|
||||
邮箱:feedback@kevisual.cn
|
||||
|
||||
电话:18324451015
|
||||
|
||||
地址:浙江省杭州市余杭区闲林街道天日山西路 230 号 A 区 3 楼 2954 室
|
||||
48
backup/docs/功能介绍.md
Normal file
48
backup/docs/功能介绍.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# kevisual 助手
|
||||
|
||||
加速你的工作,生活,学习。
|
||||
|
||||
## 功能介绍
|
||||
|
||||
### 1. 网页部署平台
|
||||
|
||||
任何人的自己的博客,自定义的 ai 创建的网页,都可以通过这个平台,来管理自己的网页。
|
||||
|
||||
实现了:
|
||||
|
||||
- 类似图床的文件管理
|
||||
- 站点的创建,删除
|
||||
- 域名自定义
|
||||
|
||||
#### 1.1. 用户的用户管理 web 网站
|
||||
|
||||

|
||||
|
||||
可以配置只自己可以访问。
|
||||
|
||||
#### 1.2. 文件管理
|
||||
|
||||

|
||||
|
||||
配置自己的文件的目录
|
||||
|
||||
### 2. AI Mark 推荐
|
||||
|
||||
大模型汇总了大量信息,但在具体应用时,用户需要一个精炼的知识库来找到解决方案。因此,我们计划创建一个网站助手工具库。当用户提出问题时,工具库可以提供快捷方式或直接实现解决方案。我们来提炼这个资料库。
|
||||
|
||||
例如,我们将收录一些可自行部署的软件和开源项目,如 GitHub 上的优秀项目:vaultwarden(密码管理)、memos(笔记)等。
|
||||
|
||||
由于应用种类繁多,我们需要一个便捷的入口来快速访问这些工具。
|
||||
|
||||
TODO:
|
||||
|
||||
### 2. 笔记助手
|
||||
|
||||
快速将内容粘贴到视觉程序库中,通过 AI 创造性地生成美观的内容并进行可视化。便捷地创建个人笔记,加速思考,快速生成笔记和网页。
|
||||
|
||||
TODO:
|
||||
|
||||
### 3. 资料库 AI
|
||||
|
||||
搭建自己的资料库。
|
||||
TODO:
|
||||
20
backup/docs/用户协议.md
Normal file
20
backup/docs/用户协议.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# 用户协议
|
||||
|
||||
欢迎使用本网站。在使用本网站之前,请仔细阅读以下用户协议条款。访问或使用本网站即表示您同意遵守本协议。
|
||||
|
||||
## 1. 使用条款
|
||||
用户在使用本网站时,必须遵守所有适用的法律法规。用户不得利用本网站从事任何非法活动。
|
||||
|
||||
## 2. 知识产权
|
||||
本网站的所有内容,包括但不限于文本、图像、标识和软件,均受版权法和其他知识产权法的保护。未经授权,用户不得复制、分发或以其他方式使用本网站的内容。
|
||||
|
||||
## 3. 责任限制
|
||||
本网站不对因使用或无法使用本网站而导致的任何直接、间接、偶然、特殊或后果性损害承担责任。
|
||||
|
||||
## 4. 隐私政策
|
||||
用户的隐私对我们非常重要。请参阅我们的隐私政策以了解更多信息。
|
||||
|
||||
## 5. 修改和终止
|
||||
本网站保留随时修改或终止本协议的权利。修改后的协议将在本网站上发布,并立即生效。
|
||||
|
||||
感谢您使用本网站。如有任何问题,请联系我们。
|
||||
31
backup/docs/隐私政策.md
Normal file
31
backup/docs/隐私政策.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# 隐私政策
|
||||
|
||||
杭州余杭逸文设计工作室(个体工商户)(以下简称"我们")非常重视用户的隐私。请仔细阅读以下隐私政策,以了解我们如何收集、使用和保护您的信息。
|
||||
|
||||
## 1. 信息收集
|
||||
我们可能会收集以下类型的信息:
|
||||
- 联系信息:如您的姓名、电子邮件地址。
|
||||
- 使用信息:如您访问我们网站的频率、使用的功能等。
|
||||
|
||||
## 2. 信息使用
|
||||
我们收集的信息将用于以下目的:
|
||||
- 提供和改进我们的服务。
|
||||
- 处理您的请求和反馈。
|
||||
- 发送重要通知和更新。
|
||||
|
||||
## 3. 信息共享
|
||||
我们不会与第三方共享您的个人信息,除非:
|
||||
- 获得您的明确同意。
|
||||
- 法律要求或允许。
|
||||
|
||||
## 4. 信息安全
|
||||
我们采取合理的措施保护您的信息免受未经授权的访问、使用或披露。
|
||||
|
||||
## 5. 隐私政策的变更
|
||||
我们可能会不时更新本隐私政策。任何更改将在我们的网站上发布,并立即生效。
|
||||
|
||||
如有任何问题或建议,请通过以下方式联系我们:
|
||||
- 公司邮箱:envision@kevisual.cn
|
||||
- 举报邮箱:feedback@kevisual.cn
|
||||
|
||||
感谢您信任我们。
|
||||
16
backup/index.html
Normal file
16
backup/index.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<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" />
|
||||
<title>逸文设计工作室</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="./src/main.tsx"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
39
backup/package.json
Normal file
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
2939
backup/pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
266
backup/src/App.tsx
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
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
BIN
backup/src/assets/logo-1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 230 KiB |
11
backup/src/components/EvWechat.tsx
Normal file
11
backup/src/components/EvWechat.tsx
Normal file
File diff suppressed because one or more lines are too long
24
backup/src/components/Icon.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
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>;
|
||||
};
|
||||
1
backup/src/index.css
Normal file
1
backup/src/index.css
Normal file
@@ -0,0 +1 @@
|
||||
@import 'tailwindcss';
|
||||
9
backup/src/main.tsx
Normal file
9
backup/src/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
backup/src/modules/CodeDescModal.tsx
Normal file
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
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
3
backup/src/modules/query.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { QueryClient } from '@kevisual/query';
|
||||
|
||||
export const query = new QueryClient();
|
||||
43
backup/tsconfig.app.json
Normal file
43
backup/tsconfig.app.json
Normal file
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": [
|
||||
"ES2020",
|
||||
"DOM",
|
||||
"DOM.Iterable"
|
||||
],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"isolatedModules": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
// "jsx": "react",
|
||||
// "jsxFragmentFactory": "Fragment",
|
||||
// "jsxFactory": "h",
|
||||
"jsx": "react-jsx",
|
||||
"baseUrl": "./",
|
||||
"typeRoots": [
|
||||
"node_modules/@types",
|
||||
"node_modules/@kevisual/types",
|
||||
],
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"src/*"
|
||||
]
|
||||
},
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noImplicitAny": false,
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"include": [
|
||||
"src",
|
||||
"typings.d.ts"
|
||||
]
|
||||
}
|
||||
7
backup/tsconfig.json
Normal file
7
backup/tsconfig.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{ "path": "./tsconfig.app.json" },
|
||||
{ "path": "./tsconfig.node.json" }
|
||||
]
|
||||
}
|
||||
22
backup/tsconfig.node.json
Normal file
22
backup/tsconfig.node.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"lib": ["ES2023"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"isolatedModules": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
||||
24
backup/vite.config.mjs
Normal file
24
backup/vite.config.mjs
Normal file
@@ -0,0 +1,24 @@
|
||||
import { defineConfig } from 'vite';
|
||||
import react from '@vitejs/plugin-react';
|
||||
import tailwindcss from '@tailwindcss/vite';
|
||||
// import { visualizer } from "rollup-plugin-visualizer";
|
||||
// https://vitejs.dev/config/
|
||||
const isDev = process.env.NODE_ENV === 'development';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [react(), tailwindcss()],
|
||||
base: isDev ? '/' : './', //'/root/official/',
|
||||
optimizeDeps: {
|
||||
exclude: ['lucide-react'],
|
||||
},
|
||||
server: {
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'http://localhost:4005',
|
||||
changeOrigin: true,
|
||||
secure: false,
|
||||
rewrite: (path) => path.replace(/^\/api/, '/api'),
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user