shrink tos modal and make it scrollable when vertical space is not enough (#373)

This commit is contained in:
Red J Adaya 2024-09-13 14:10:18 +08:00 committed by GitHub
parent 04924870c1
commit 2715c2ce30
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 143 additions and 89 deletions

View File

@ -18,6 +18,10 @@ body {
transform: translateZ(0);
}
a.plain-link {
color: var(--secondary-text-color);
}
*::-webkit-scrollbar {
width: 4px;
height: 4px;

View File

@ -3,10 +3,65 @@
import { Button } from "@/app/element/button";
import clsx from "clsx";
import { forwardRef } from "react";
import ReactDOM from "react-dom";
import "./modal.less";
interface ModalProps {
children?: React.ReactNode;
description?: string;
okLabel?: string;
cancelLabel?: string;
className?: string;
onClickBackdrop?: () => void;
onOk?: () => void;
onCancel?: () => void;
onClose?: () => void;
}
const Modal = forwardRef<HTMLDivElement, ModalProps>(
(
{
children,
className,
description,
cancelLabel,
okLabel,
onCancel,
onOk,
onClose,
onClickBackdrop,
}: ModalProps,
ref
) => {
const renderBackdrop = (onClick) => <div className="modal-backdrop" onClick={onClick}></div>;
const renderFooter = () => {
return onOk || onCancel;
};
const renderModal = () => (
<div className="modal-wrapper">
{renderBackdrop(onClickBackdrop)}
<div ref={ref} className={clsx(`modal`, className)}>
<Button className="secondary ghost modal-close-btn" onClick={onClose} title="Close (ESC)">
<i className="fa-sharp fa-solid fa-xmark"></i>
</Button>
<div className="content-wrapper">
<ModalContent>{children}</ModalContent>
</div>
{renderFooter() && (
<ModalFooter onCancel={onCancel} onOk={onOk} cancelLabel={cancelLabel} okLabel={okLabel} />
)}
</div>
</div>
);
return ReactDOM.createPortal(renderModal(), document.getElementById("main"));
}
);
interface ModalContentProps {
children: React.ReactNode;
}
@ -39,75 +94,36 @@ const ModalFooter = ({ onCancel, onOk, cancelLabel = "Cancel", okLabel = "Ok" }:
);
};
interface ModalProps {
children?: React.ReactNode;
description?: string;
okLabel?: string;
cancelLabel?: string;
className?: string;
onClickBackdrop?: () => void;
onOk?: () => void;
onCancel?: () => void;
onClose?: () => void;
}
const Modal = ({
children,
className,
description,
cancelLabel,
okLabel,
onCancel,
onOk,
onClose,
onClickBackdrop,
}: ModalProps) => {
const renderBackdrop = (onClick) => <div className="modal-backdrop" onClick={onClick}></div>;
const renderFooter = () => {
return onOk || onCancel;
};
const renderModal = () => (
<div className="modal-wrapper">
{renderBackdrop(onClickBackdrop)}
<div className={clsx(`modal`, className)}>
<Button className="secondary ghost modal-close-btn" onClick={onClose} title="Close (ESC)">
<i className="fa-sharp fa-solid fa-xmark"></i>
</Button>
<div className="content-wrapper">
<ModalContent>{children}</ModalContent>
</div>
{renderFooter() && (
<ModalFooter onCancel={onCancel} onOk={onOk} cancelLabel={cancelLabel} okLabel={okLabel} />
)}
</div>
</div>
);
return ReactDOM.createPortal(renderModal(), document.getElementById("main"));
};
interface FlexiModalProps {
children?: React.ReactNode;
className?: string;
onClickBackdrop?: () => void;
}
const FlexiModal = ({ children, className, onClickBackdrop }: FlexiModalProps) => {
const renderBackdrop = (onClick) => <div className="modal-backdrop" onClick={onClick}></div>;
interface FlexiModalComponent
extends React.ForwardRefExoticComponent<FlexiModalProps & React.RefAttributes<HTMLDivElement>> {
Content: typeof ModalContent;
Footer: typeof ModalFooter;
}
const FlexiModal = forwardRef<HTMLDivElement, FlexiModalProps>(
({ children, className, onClickBackdrop }: FlexiModalProps, ref) => {
const renderBackdrop = (onClick: () => void) => <div className="modal-backdrop" onClick={onClick}></div>;
const renderModal = () => (
<div className="modal-wrapper">
{renderBackdrop(onClickBackdrop)}
<div className={`modal ${className}`}>{children}</div>
<div className={`modal ${className}`} ref={ref}>
{children}
</div>
</div>
);
return ReactDOM.createPortal(renderModal(), document.getElementById("main"));
};
return ReactDOM.createPortal(renderModal(), document.getElementById("main")!);
}
);
FlexiModal.Content = ModalContent;
FlexiModal.Footer = ModalFooter;
(FlexiModal as FlexiModalComponent).Content = ModalContent;
(FlexiModal as FlexiModalComponent).Footer = ModalFooter;
export { FlexiModal, Modal };

View File

@ -2,21 +2,22 @@
// SPDX-License-Identifier: Apache-2.0
.tos-modal {
width: 640px;
width: 560px;
border-radius: 10px;
padding: 0;
.modal-inner {
padding: 40px 76px;
gap: 32px;
display: flex;
flex-direction: column;
overflow-y: auto;
padding: 30px;
header.tos-header {
flex-direction: column;
gap: var(--sizing-sm, 12px);
gap: 8px;
border-bottom: none;
padding: 0;
margin-bottom: 20px;
margin-bottom: 36px;
.logo {
margin-bottom: 10px;
@ -48,12 +49,17 @@
gap: 32px;
width: 100%;
margin-bottom: 0;
margin-bottom: 20px;
.check-toggle-wrapper .toggle-label {
color: var(--secondary-text-color);
}
.content-section {
display: flex;
width: 100%;
align-items: center;
gap: 32px;
gap: 18px;
.icon-wrapper {
.icon {
@ -82,9 +88,13 @@
}
.content-section-text {
color: rgba(255, 255, 255, 0.7);
color: var(--secondary-text-color);
font-style: normal;
line-height: 20px;
b {
color: var(--main-text-color);
}
}
.content-section-field {
@ -102,10 +112,6 @@
}
}
}
.toggle-label {
color: rgba(255, 255, 255, 0.7);
}
}
footer {
@ -123,7 +129,6 @@
button {
font-size: 14px;
margin-bottom: 28px;
}
button.disabled-button {

View File

@ -6,19 +6,43 @@ import { Button } from "@/app/element/button";
import { Toggle } from "@/app/element/toggle";
import { WshServer } from "@/app/store/wshserver";
import * as services from "@/store/services";
import { useEffect, useState } from "react";
import { OverlayScrollbarsComponent } from "overlayscrollbars-react";
import { useEffect, useRef, useState } from "react";
import { FlexiModal } from "./modal";
import "./tos.less";
const TosModal = () => {
const [telemetryEnabled, setTelemetryEnabled] = useState<boolean>(true);
const modalRef = useRef<HTMLDivElement | null>(null);
const updateModalHeight = () => {
const windowHeight = window.innerHeight;
if (modalRef.current) {
const modalHeight = modalRef.current.offsetHeight;
const maxHeight = windowHeight * 0.9;
if (maxHeight < modalHeight) {
modalRef.current.style.height = `${maxHeight}px`;
} else {
modalRef.current.style.height = "auto";
}
}
};
useEffect(() => {
updateModalHeight(); // Run on initial render
window.addEventListener("resize", updateModalHeight); // Run on window resize
return () => {
window.removeEventListener("resize", updateModalHeight);
};
}, []);
const acceptTos = () => {
services.ClientService.AgreeTos();
};
function setTelemetry(value: boolean) {
const setTelemetry = (value: boolean) => {
WshServer.SetConfigCommand({ "telemetry:enabled": value })
.then(() => {
setTelemetryEnabled(value);
@ -26,7 +50,7 @@ const TosModal = () => {
.catch((error) => {
console.error("failed to set telemetry:", error);
});
}
};
useEffect(() => {
services.FileService.GetFullConfig()
@ -42,16 +66,16 @@ const TosModal = () => {
});
}, []);
const label = telemetryEnabled ? "Telemetry enabled" : "Telemetry disabled";
const label = telemetryEnabled ? "Telemetry Enabled" : "Telemetry Disabled";
return (
<FlexiModal className="tos-modal">
<div className="modal-inner">
<FlexiModal className="tos-modal" ref={modalRef}>
<OverlayScrollbarsComponent className="modal-inner" options={{ scrollbars: { autoHide: "leave" } }}>
<header className="modal-header tos-header unselectable">
<div className="logo">
<Logo />
</div>
<div className="modal-title">Welcome to Wave Terminal!</div>
<div className="modal-title">Welcome to Wave Terminal</div>
</header>
<div className="modal-content tos-content unselectable">
<div className="content-section">
@ -73,7 +97,7 @@ const TosModal = () => {
</div>
<div className="content-section">
<div className="icon-wrapper">
<a target="_blank" href="https://github.com/wavetermdev/thenextwave" rel={"noopener"}>
<a target="_blank" href="https://discord.gg/XfvZ334gwU" rel={"noopener"}>
<i className="icon fa-solid fa-people-group"></i>
</a>
</div>
@ -96,15 +120,24 @@ const TosModal = () => {
<div className="content-section-inner">
<div className="content-section-title">Telemetry</div>
<div className="content-section-text">
We collect minimal anonymous
We collect minimal anonymous{" "}
<a
target="_blank"
href="https://docs.waveterm.dev/reference/telemetry"
rel={"noopener"}
>
&nbsp;telemetry data&nbsp;
telemetry data
</a>{" "}
to help us understand how people are using Wave (
<a
className="plain-link"
target="_blank"
href="https://waveterm.dev/privacy"
rel="noopener"
>
Privacy Policy
</a>
to help us understand how people are using Wave.
).
</div>
<Toggle checked={telemetryEnabled} onChange={setTelemetry} label={label} />
</div>
@ -116,12 +149,8 @@ const TosModal = () => {
Get Started
</Button>
</div>
<div className="content-section-text">
By continuing, I accept the&nbsp;
<a href="https://www.waveterm.dev/tos">Terms of Service</a>
</div>
</footer>
</div>
</OverlayScrollbarsComponent>
</FlexiModal>
);
};