mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-19 14:41:24 +08:00
feat(privacy): add English and Chinese privacy policy pages and popup component
- Introduced new HTML files for the privacy policy in English and Chinese. - Implemented a PrivacyPopup component to display the privacy policy within the application. - The popup dynamically loads the appropriate language based on user settings and includes options to accept or decline the policy.
This commit is contained in:
parent
183b46be9e
commit
cc650b58d3
252
resources/cherry-studio/privacy-en.html
Normal file
252
resources/cherry-studio/privacy-en.html
Normal file
@ -0,0 +1,252 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Privacy Policy</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica Neue', Arial, sans-serif;
|
||||
line-height: 1.6;
|
||||
color: #333;
|
||||
background: transparent;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
body.dark {
|
||||
background: transparent;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 20px;
|
||||
color: #1a1a1a;
|
||||
}
|
||||
|
||||
body.dark h1 {
|
||||
color: rgba(255, 255, 255, 0.95);
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
margin-top: 24px;
|
||||
margin-bottom: 12px;
|
||||
color: #2c2c2c;
|
||||
}
|
||||
|
||||
body.dark h2 {
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 12px 0;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
body.dark p {
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
|
||||
ul {
|
||||
margin: 12px 0;
|
||||
padding-left: 24px;
|
||||
}
|
||||
|
||||
li {
|
||||
margin: 6px 0;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
body.dark li {
|
||||
color: rgba(255, 255, 255, 0.75);
|
||||
}
|
||||
|
||||
a {
|
||||
color: #0066cc;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
body.dark a {
|
||||
color: #4da6ff;
|
||||
}
|
||||
|
||||
.footer {
|
||||
margin-top: 40px;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid #e0e0e0;
|
||||
font-size: 13px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
body.dark .footer {
|
||||
border-top-color: rgba(255, 255, 255, 0.1);
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.content-wrapper {
|
||||
max-height: calc(100vh - 40px);
|
||||
overflow-y: auto;
|
||||
padding-right: 10px;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* Scrollbar styles - Light mode */
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
/* Scrollbar styles - Dark mode */
|
||||
body.dark ::-webkit-scrollbar-track {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
body.dark ::-webkit-scrollbar-thumb {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
body.dark ::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
// Detect theme
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const theme = urlParams.get('theme');
|
||||
if (theme === 'dark') {
|
||||
document.documentElement.classList.add('dark');
|
||||
document.body.classList.add('dark');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="content-wrapper">
|
||||
<h1>Privacy Policy</h1>
|
||||
|
||||
<p>
|
||||
Welcome to Cherry Studio (hereinafter referred to as "the Software" or "we"). We highly value your privacy
|
||||
protection. This Privacy Policy explains how we process and protect your personal information and data.
|
||||
Please read and understand this policy carefully before using the Software:
|
||||
</p>
|
||||
|
||||
<h2>1. Information We Collect</h2>
|
||||
<p>To optimize user experience and improve software quality, we may only collect the following anonymous,
|
||||
non-personal information:</p>
|
||||
<ul>
|
||||
<li>Software version information</li>
|
||||
<li>Activity and usage frequency of software features</li>
|
||||
<li>Anonymous crash and error log information</li>
|
||||
</ul>
|
||||
<p>The above information is completely anonymous, does not involve any personal identity data, and cannot be
|
||||
linked to your personal information.</p>
|
||||
|
||||
<h2>2. Information We Do Not Collect</h2>
|
||||
<p>To maximize the protection of your privacy and security, we explicitly commit that we:</p>
|
||||
<ul>
|
||||
<li>Will not collect, save, transmit, or process model service API Key information you enter into the
|
||||
Software</li>
|
||||
<li>Will not collect, save, transmit, or process any conversation data generated during your use of the
|
||||
Software, including but not limited to chat content, instruction information, knowledge base
|
||||
information, vector data, and other custom content</li>
|
||||
<li>Will not collect, save, transmit, or process any sensitive information that can identify personal
|
||||
identity</li>
|
||||
</ul>
|
||||
|
||||
<h2>3. Data Interaction Description</h2>
|
||||
<p>
|
||||
The Software uses API Keys from third-party model service providers that you apply for and configure
|
||||
yourself to complete model calls and conversation functions. The model services you use (such as large
|
||||
models, API interfaces, etc.) are directly provided by third-party providers of your choice. We do not
|
||||
intervene, monitor, or interfere with the data transmission process.
|
||||
</p>
|
||||
<p>
|
||||
Data interactions between you and third-party model services are governed by the privacy policies and user
|
||||
agreements of third-party service providers. We recommend that you fully understand the privacy terms of
|
||||
relevant service providers before use.
|
||||
</p>
|
||||
|
||||
<h2>4. Local Data Security Protection</h2>
|
||||
<p>The Software is a localized application, and all data is stored on your local device by default. We have
|
||||
taken the following measures to ensure data security:</p>
|
||||
<ul>
|
||||
<li>Conversation records, configuration information, and other data are only saved on your local device</li>
|
||||
<li>Data import/export functions are provided to facilitate your independent management and backup of data
|
||||
</li>
|
||||
<li>Your local data will not be uploaded to any server or cloud storage</li>
|
||||
</ul>
|
||||
|
||||
<h2>5. Third-Party Services</h2>
|
||||
<p>
|
||||
When using the Software, you may access third-party services (such as AI model APIs, translation services,
|
||||
etc.). The use of these third-party services is governed by their respective terms of service and privacy
|
||||
policies. We strongly recommend that you carefully read and understand the relevant terms before use.
|
||||
</p>
|
||||
|
||||
<h2>6. User Rights</h2>
|
||||
<p>You have complete control over your data:</p>
|
||||
<ul>
|
||||
<li>You can view, modify, and delete all locally stored data at any time</li>
|
||||
<li>You can choose whether to enable specific features or services</li>
|
||||
<li>You can stop using the Software and delete all related data at any time</li>
|
||||
</ul>
|
||||
|
||||
<h2>7. Children's Privacy Protection</h2>
|
||||
<p>The Software is not intended for minors under 18 years of age. If you are a minor, please use the Software
|
||||
under the guidance of a guardian.</p>
|
||||
|
||||
<h2>8. Privacy Policy Updates</h2>
|
||||
<p>
|
||||
We may update this Privacy Policy based on legal requirements or changes in product features. The updated
|
||||
policy will be published in the Software and you will be notified before it takes effect. If you do not
|
||||
agree with the updated terms, you can choose to stop using the Software.
|
||||
</p>
|
||||
|
||||
<h2>9. Contact Us</h2>
|
||||
<p>If you have any questions, suggestions, or complaints about this Privacy Policy, please contact us through
|
||||
the following methods:</p>
|
||||
<ul>
|
||||
<li>
|
||||
GitHub: <a href="https://github.com/CherryHQ/cherry-studio" target="_blank"
|
||||
rel="noopener noreferrer">https://github.com/CherryHQ/cherry-studio</a>
|
||||
</li>
|
||||
<li>Email: support@cherry-ai.com</li>
|
||||
</ul>
|
||||
|
||||
<div class="footer">
|
||||
Last Updated: December 2024
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
230
resources/cherry-studio/privacy-zh.html
Normal file
230
resources/cherry-studio/privacy-zh.html
Normal file
@ -0,0 +1,230 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>隐私协议</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica Neue', Arial, sans-serif;
|
||||
line-height: 1.6;
|
||||
color: #333;
|
||||
background: transparent;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
body.dark {
|
||||
background: transparent;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 20px;
|
||||
color: #1a1a1a;
|
||||
}
|
||||
|
||||
body.dark h1 {
|
||||
color: rgba(255, 255, 255, 0.95);
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
margin-top: 24px;
|
||||
margin-bottom: 12px;
|
||||
color: #2c2c2c;
|
||||
}
|
||||
|
||||
body.dark h2 {
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 12px 0;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
body.dark p {
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
|
||||
ul {
|
||||
margin: 12px 0;
|
||||
padding-left: 24px;
|
||||
}
|
||||
|
||||
li {
|
||||
margin: 6px 0;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
body.dark li {
|
||||
color: rgba(255, 255, 255, 0.75);
|
||||
}
|
||||
|
||||
a {
|
||||
color: #0066cc;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
body.dark a {
|
||||
color: #4da6ff;
|
||||
}
|
||||
|
||||
.footer {
|
||||
margin-top: 40px;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid #e0e0e0;
|
||||
font-size: 13px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
body.dark .footer {
|
||||
border-top-color: rgba(255, 255, 255, 0.1);
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.content-wrapper {
|
||||
overflow-y: auto;
|
||||
padding-right: 10px;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* 滚动条样式 - 亮色模式 */
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
/* 滚动条样式 - 暗色模式 */
|
||||
body.dark ::-webkit-scrollbar-track {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
body.dark ::-webkit-scrollbar-thumb {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
body.dark ::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
// 检测主题
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const theme = urlParams.get('theme');
|
||||
if (theme === 'dark') {
|
||||
document.documentElement.classList.add('dark');
|
||||
document.body.classList.add('dark');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="content-wrapper">
|
||||
<h1>隐私协议</h1>
|
||||
|
||||
<p>
|
||||
欢迎使用 Cherry Studio(以下简称"本软件"或"我们")。我们高度重视您的隐私保护,本隐私协议将说明我们如何处理与保护您的个人信息和数据。请在使用本软件前仔细阅读并理解本协议:
|
||||
</p>
|
||||
|
||||
<h2>一、我们收集的信息范围</h2>
|
||||
<p>为了优化用户体验和提升软件质量,我们仅可能会匿名收集以下非个人化信息:</p>
|
||||
<ul>
|
||||
<li>软件版本信息;</li>
|
||||
<li>软件功能的活跃度、使用频次;</li>
|
||||
<li>匿名的崩溃、错误日志信息;</li>
|
||||
</ul>
|
||||
<p>上述信息完全匿名,不会涉及任何个人身份数据,也无法关联到您的个人信息。</p>
|
||||
|
||||
<h2>二、我们不会收集的任何信息</h2>
|
||||
<p>为了最大限度保护您的隐私安全,我们明确承诺:</p>
|
||||
<ul>
|
||||
<li>不会收集、保存、传输或处理您输入到本软件中的模型服务 API Key 信息;</li>
|
||||
<li>不会收集、保存、传输或处理您在使用本软件过程中产生的任何对话数据,包括但不限于聊天内容、指令信息、知识库信息、向量数据及其他自定义内容;</li>
|
||||
<li>不会收集、保存、传输或处理任何可识别个人身份的敏感信息。</li>
|
||||
</ul>
|
||||
|
||||
<h2>三、数据交互说明</h2>
|
||||
<p>
|
||||
本软件采用您自行申请并配置的第三方模型服务提供商的 API Key,以完成相关模型的调用与对话功能。您使用的模型服务(例如大模型、API 接口等)由您选择的第三方提供商直接提供,我们不会介入、监控或干扰数据传输过程。
|
||||
</p>
|
||||
<p>
|
||||
您与第三方模型服务之间的数据交互受第三方服务提供商的隐私政策和用户协议约束,我们建议您在使用前充分了解相关服务商的隐私条款。
|
||||
</p>
|
||||
|
||||
<h2>四、本地数据的安全保护</h2>
|
||||
<p>本软件为本地化应用程序,所有数据默认存储在您的本地设备上。我们采取了以下措施保障数据安全:</p>
|
||||
<ul>
|
||||
<li>对话记录、配置信息等数据仅保存在您的本地设备中;</li>
|
||||
<li>提供数据导入/导出功能,方便您自主管理和备份数据;</li>
|
||||
<li>不会将您的本地数据上传至任何服务器或云端存储。</li>
|
||||
</ul>
|
||||
|
||||
<h2>五、第三方服务</h2>
|
||||
<p>
|
||||
在使用本软件过程中,您可能会接入第三方服务(如 AI 模型 API、翻译服务等)。这些第三方服务的使用受其各自的服务条款和隐私政策约束。我们强烈建议您在使用前仔细阅读并理解相关条款。
|
||||
</p>
|
||||
|
||||
<h2>六、用户权利</h2>
|
||||
<p>您对自己的数据拥有完全的控制权:</p>
|
||||
<ul>
|
||||
<li>您可以随时查看、修改、删除本地存储的所有数据;</li>
|
||||
<li>您可以选择是否启用特定功能或服务;</li>
|
||||
<li>您可以随时停止使用本软件并删除所有相关数据。</li>
|
||||
</ul>
|
||||
|
||||
<h2>七、儿童隐私保护</h2>
|
||||
<p>本软件不面向 18 岁以下的未成年人提供服务。如果您是未成年人,请在监护人的指导下使用本软件。</p>
|
||||
|
||||
<h2>八、隐私政策的更新</h2>
|
||||
<p>
|
||||
我们可能会根据法律法规要求或产品功能的变化更新本隐私协议。更新后的协议将在软件中发布,并在生效前通知您。如果您不同意更新后的条款,您可以选择停止使用本软件。
|
||||
</p>
|
||||
|
||||
<h2>九、联系我们</h2>
|
||||
<p>如果您对本隐私协议有任何疑问、建议或投诉,请通过以下方式联系我们:</p>
|
||||
<ul>
|
||||
<li>
|
||||
GitHub: <a href="https://github.com/CherryHQ/cherry-studio" target="_blank"
|
||||
rel="noopener noreferrer">https://github.com/CherryHQ/cherry-studio</a>
|
||||
</li>
|
||||
<li>Email: support@cherry-ai.com</li>
|
||||
</ul>
|
||||
|
||||
<div class="footer">
|
||||
最后更新日期:2024年12月
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
137
src/renderer/src/components/Popups/PrivacyPopup.tsx
Normal file
137
src/renderer/src/components/Popups/PrivacyPopup.tsx
Normal file
@ -0,0 +1,137 @@
|
||||
import { TopView } from '@renderer/components/TopView'
|
||||
import { useTheme } from '@renderer/context/ThemeProvider'
|
||||
import { ThemeMode } from '@renderer/types'
|
||||
import { runAsyncFunction } from '@renderer/utils'
|
||||
import { Button, Modal } from 'antd'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import styled from 'styled-components'
|
||||
|
||||
const WebViewContainer = styled.div`
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
overflow: hidden;
|
||||
|
||||
webview {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
background: transparent;
|
||||
}
|
||||
`
|
||||
|
||||
interface ShowParams {
|
||||
title?: string
|
||||
showDeclineButton?: boolean
|
||||
}
|
||||
|
||||
interface Props extends ShowParams {
|
||||
resolve: (data: any) => void
|
||||
}
|
||||
|
||||
const PopupContainer: React.FC<Props> = ({ title, showDeclineButton = true, resolve }) => {
|
||||
const [open, setOpen] = useState(true)
|
||||
const [privacyUrl, setPrivacyUrl] = useState<string>('')
|
||||
const { theme } = useTheme()
|
||||
const { i18n } = useTranslation()
|
||||
|
||||
const getTitle = () => {
|
||||
if (title) return title
|
||||
const isChinese = i18n.language.startsWith('zh')
|
||||
return isChinese ? '隐私协议' : 'Privacy Policy'
|
||||
}
|
||||
|
||||
const handleAccept = () => {
|
||||
setOpen(false)
|
||||
localStorage.setItem('privacy-popup-accepted', 'true')
|
||||
resolve({ accepted: true })
|
||||
}
|
||||
|
||||
const handleDecline = () => {
|
||||
setOpen(false)
|
||||
window.api.quit()
|
||||
resolve({ accepted: false })
|
||||
}
|
||||
|
||||
const onClose = () => {
|
||||
if (!showDeclineButton) {
|
||||
handleAccept()
|
||||
} else {
|
||||
handleDecline()
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
runAsyncFunction(async () => {
|
||||
const { appPath } = await window.api.getAppInfo()
|
||||
const isChinese = i18n.language.startsWith('zh')
|
||||
const htmlFile = isChinese ? 'privacy-zh.html' : 'privacy-en.html'
|
||||
const url = `file://${appPath}/resources/cherry-studio/${htmlFile}?theme=${theme === ThemeMode.dark ? 'dark' : 'light'}`
|
||||
setPrivacyUrl(url)
|
||||
})
|
||||
}, [theme, i18n.language])
|
||||
|
||||
PrivacyPopup.hide = () => setOpen(false)
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title={getTitle()}
|
||||
open={open}
|
||||
onCancel={showDeclineButton ? handleDecline : undefined}
|
||||
afterClose={onClose}
|
||||
transitionName=""
|
||||
maskTransitionName=""
|
||||
centered
|
||||
closable={false}
|
||||
maskClosable={false}
|
||||
styles={{
|
||||
mask: { backgroundColor: 'var(--color-background)' },
|
||||
header: { paddingLeft: 20 },
|
||||
body: { paddingLeft: 20 }
|
||||
}}
|
||||
width={900}
|
||||
footer={[
|
||||
showDeclineButton && (
|
||||
<Button key="decline" onClick={handleDecline}>
|
||||
{i18n.language.startsWith('zh') ? '拒绝' : 'Decline'}
|
||||
</Button>
|
||||
),
|
||||
<Button key="accept" type="primary" onClick={handleAccept}>
|
||||
{i18n.language.startsWith('zh') ? '同意并继续' : 'Accept and Continue'}
|
||||
</Button>
|
||||
].filter(Boolean)}>
|
||||
<WebViewContainer>
|
||||
{privacyUrl && <webview src={privacyUrl} style={{ width: '100%', height: '100%' }} />}
|
||||
</WebViewContainer>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
const TopViewKey = 'PrivacyPopup'
|
||||
|
||||
export default class PrivacyPopup {
|
||||
static topviewId = 0
|
||||
static hide() {
|
||||
TopView.hide(TopViewKey)
|
||||
}
|
||||
static async show(props?: ShowParams) {
|
||||
const accepted = localStorage.getItem('privacy-popup-accepted')
|
||||
|
||||
if (accepted) {
|
||||
return
|
||||
}
|
||||
|
||||
return new Promise<{ accepted: boolean }>((resolve) => {
|
||||
TopView.show(
|
||||
<PopupContainer
|
||||
{...(props || {})}
|
||||
resolve={(v) => {
|
||||
resolve(v)
|
||||
TopView.hide(TopViewKey)
|
||||
}}
|
||||
/>,
|
||||
TopViewKey
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user