feat: optimize sharing feature, add mobile adapter, add maximized screen and minized screen feature

This commit is contained in:
Zhang Minghan 2024-02-21 11:09:57 +08:00
parent e05b181047
commit 98cf701ff6
4 changed files with 46 additions and 17 deletions

View File

@ -3,7 +3,6 @@
display: flex; display: flex;
width: 100%; width: 100%;
height: calc(100vh - 56px); height: calc(100vh - 56px);
padding: 0 2rem;
} }
.loading { .loading {
@ -127,6 +126,17 @@
.shot-content { .shot-content {
padding: 2rem; padding: 2rem;
@media (max-width: 768px) {
padding: 1.5rem;
}
@media (max-width: 520px) {
padding: 1rem;
}
.message-toolbar {
display: none;
}
& > * { & > * {
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
@ -151,6 +161,18 @@
width: 80vw; width: 80vw;
height: 70vh; height: 70vh;
background: hsl(var(--background)); background: hsl(var(--background));
transition: 0.25s;
.message-toolbar {
display: none !important;
}
&.maximized {
width: 100vw;
height: 100%;
margin: 0;
border-radius: 0;
}
.header { .header {
display: flex; display: flex;
@ -226,7 +248,8 @@
flex-wrap: wrap; flex-wrap: wrap;
justify-content: flex-end; justify-content: flex-end;
gap: 6px; gap: 6px;
padding: 0.75rem 1.5rem 1rem; padding: 1.25rem 1rem;
border-top: 1px solid hsl(var(--border));
button { button {
white-space: nowrap; white-space: nowrap;

View File

@ -35,6 +35,7 @@ type MessageProps = {
end?: boolean; end?: boolean;
onEvent?: (event: string, index?: number, message?: string) => void; onEvent?: (event: string, index?: number, message?: string) => void;
ref?: Ref<HTMLElement>; ref?: Ref<HTMLElement>;
sharing?: boolean;
}; };
function MessageSegment(props: MessageProps) { function MessageSegment(props: MessageProps) {

View File

@ -50,7 +50,7 @@ function ModelUsageChart({ labels, datasets }: ModelChartProps) {
const categories = useMemo(() => { const categories = useMemo(() => {
return chart.map( return chart.map(
(item) => `${item.name} (${getReadableNumber(item.value, 1)})`, (item) => `${item.name} (${getReadableNumber(item.value, 1)})`,
) );
}, [chart]); }, [chart]);
type CustomTooltipTypeDonut = { type CustomTooltipTypeDonut = {
@ -104,6 +104,7 @@ function ModelUsageChart({ labels, datasets }: ModelChartProps) {
showAnimation={true} showAnimation={true}
valueFormatter={(value) => getReadableNumber(value, 1)} valueFormatter={(value) => getReadableNumber(value, 1)}
customTooltip={customTooltip} customTooltip={customTooltip}
colors={chart.map((item) => getModelColor(item.name))}
/> />
<Legend <Legend
className={`common-chart p-2 w-[50%] z-0`} className={`common-chart p-2 w-[50%] z-0`}

View File

@ -1,16 +1,17 @@
import "@/assets/pages/sharing.less"; import "@/assets/pages/sharing.less";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import { viewConversation, ViewData, ViewForm } from "@/api/sharing.ts"; import { viewConversation, ViewData, ViewForm } from "@/api/sharing.ts";
import { copyClipboard, saveImageAsFile } from "@/utils/dom.ts"; import { saveImageAsFile } from "@/utils/dom.ts";
import { useEffectAsync } from "@/utils/hook.ts"; import { useEffectAsync } from "@/utils/hook.ts";
import { useRef, useState } from "react"; import { useRef, useState } from "react";
import { import {
Clock, Clock,
Copy,
HelpCircle, HelpCircle,
Image, Image,
Loader2, Loader2,
Maximize,
MessagesSquare, MessagesSquare,
Minimize,
Newspaper, Newspaper,
} from "lucide-react"; } from "lucide-react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@ -24,6 +25,8 @@ import Avatar from "@/components/Avatar.tsx";
import { toJpeg } from "html-to-image"; import { toJpeg } from "html-to-image";
import { appLogo } from "@/conf/env.ts"; import { appLogo } from "@/conf/env.ts";
import { extractMessage } from "@/utils/processor.ts"; import { extractMessage } from "@/utils/processor.ts";
import { cn } from "@/components/ui/lib/utils.ts";
import { useMobile } from "@/utils/device.ts";
type SharingFormProps = { type SharingFormProps = {
refer?: string; refer?: string;
@ -35,13 +38,13 @@ function SharingForm({ refer, data }: SharingFormProps) {
const { t } = useTranslation(); const { t } = useTranslation();
const { toast } = useToast(); const { toast } = useToast();
const mobile = useMobile();
const [maximized, setMaximized] = useState(false);
const container = useRef<HTMLDivElement>(null); const container = useRef<HTMLDivElement>(null);
const date = new Date(data.time); const date = new Date(data.time);
const time = `${ const time = `${
date.getMonth() + 1 date.getMonth() + 1
}-${date.getDate()} ${date.getHours()}:${date.getMinutes()}`; }-${date.getDate()} ${date.getHours()}:${date.getMinutes()}`;
const value = JSON.stringify(data, null, 2);
const saveImage = async () => { const saveImage = async () => {
toast({ toast({
title: t("message.saving-image-prompt"), title: t("message.saving-image-prompt"),
@ -68,7 +71,7 @@ function SharingForm({ refer, data }: SharingFormProps) {
}; };
return ( return (
<div className={`sharing-container`}> <div className={cn("sharing-container", maximized && "maximized")}>
<div className={`sharing-screenshot`}> <div className={`sharing-screenshot`}>
<div className={`shot-body`} ref={container}> <div className={`shot-body`} ref={container}>
<div className={`shot-wrapper`}> <div className={`shot-wrapper`}>
@ -78,7 +81,9 @@ function SharingForm({ refer, data }: SharingFormProps) {
<Newspaper className={`shot-icon`} /> <Newspaper className={`shot-icon`} />
<p className={`shot-label`}>{t("message.sharing.title")}</p> <p className={`shot-label`}>{t("message.sharing.title")}</p>
<div className={`grow`} /> <div className={`grow`} />
<p className={`shot-value`}>{data.name}</p> <p className={`shot-value`}>
{mobile ? extractMessage(data.name, 12) : data.name}
</p>
</div> </div>
<div className={`shot-row`}> <div className={`shot-row`}>
<Clock className={`shot-icon`} /> <Clock className={`shot-icon`} />
@ -126,15 +131,14 @@ function SharingForm({ refer, data }: SharingFormProps) {
<div className={`action`}> <div className={`action`}>
<Button <Button
variant={`outline`} variant={`outline`}
onClick={async () => { size={`icon`}
await copyClipboard(value); onClick={() => setMaximized(!maximized)}
toast({
title: t("share.copied"),
});
}}
> >
<Copy className={`h-4 w-4 mr-2`} /> {maximized ? (
{t("message.copy")} <Minimize className={`h-4 w-4`} />
) : (
<Maximize className={`h-4 w-4`} />
)}
</Button> </Button>
<Button variant={`outline`} onClick={saveImage}> <Button variant={`outline`} onClick={saveImage}>
<Image className={`h-4 w-4 mr-2`} /> <Image className={`h-4 w-4 mr-2`} />