mirror of
https://github.com/coaidev/coai.git
synced 2025-05-25 16:00:15 +09:00
feat: optimize sharing feature, add mobile adapter, add maximized screen and minized screen feature
This commit is contained in:
parent
e05b181047
commit
98cf701ff6
@ -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;
|
||||||
|
@ -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) {
|
||||||
|
@ -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`}
|
||||||
|
@ -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`} />
|
||||||
|
Loading…
Reference in New Issue
Block a user