feat: support to adjust writing style (#290)

* feat: implment backend for adjust report style

* feat: add web part

* fix test cases

* fix: fix typing

---------

Co-authored-by: Henry Li <henry1943@163.com>
This commit is contained in:
DanielWalnut
2025-06-07 20:48:39 +08:00
committed by GitHub
parent cda3870add
commit 0e22c373af
14 changed files with 411 additions and 7 deletions

View File

@@ -0,0 +1,45 @@
export function ReportStyle({ className }: { className?: string }) {
return (
<svg
className={className}
version="1.1"
width="800px"
height="800px"
viewBox="0 0 24 24"
fill="none"
>
<g fill="currentcolor">
<path
d="M4 4C4 3.44772 4.44772 3 5 3H19C19.5523 3 20 3.44772 20 4V20C20 20.5523 19.5523 21 19 21H5C4.44772 21 4 20.5523 4 20V4Z"
stroke="currentColor"
strokeWidth="2"
fill="none"
/>
<path
d="M8 7H16"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
/>
<path
d="M8 11H16"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
/>
<path
d="M8 15H12"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
/>
<circle
cx="16"
cy="15"
r="2"
fill="currentColor"
/>
</g>
</svg>
);
}

View File

@@ -0,0 +1,128 @@
// Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
// SPDX-License-Identifier: MIT
import { useState } from "react";
import { Check, FileText, Newspaper, Users, GraduationCap } from "lucide-react";
import { Button } from "~/components/ui/button";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "~/components/ui/dialog";
import { setReportStyle, useSettingsStore } from "~/core/store";
import { cn } from "~/lib/utils";
import { Tooltip } from "./tooltip";
const REPORT_STYLES = [
{
value: "academic" as const,
label: "Academic",
description: "Formal, objective, and analytical with precise terminology",
icon: GraduationCap,
},
{
value: "popular_science" as const,
label: "Popular Science",
description: "Engaging and accessible for general audience",
icon: FileText,
},
{
value: "news" as const,
label: "News",
description: "Factual, concise, and impartial journalistic style",
icon: Newspaper,
},
{
value: "social_media" as const,
label: "Social Media",
description: "Concise, attention-grabbing, and shareable",
icon: Users,
},
];
export function ReportStyleDialog() {
const [open, setOpen] = useState(false);
const currentStyle = useSettingsStore((state) => state.general.reportStyle);
const handleStyleChange = (
style: "academic" | "popular_science" | "news" | "social_media",
) => {
setReportStyle(style);
setOpen(false);
};
const currentStyleConfig =
REPORT_STYLES.find((style) => style.value === currentStyle) ||
REPORT_STYLES[0]!;
const CurrentIcon = currentStyleConfig.icon;
return (
<Dialog open={open} onOpenChange={setOpen}>
<Tooltip
className="max-w-60"
title={
<div>
<h3 className="mb-2 font-bold">
Writing Style: {currentStyleConfig.label}
</h3>
<p>
Choose the writing style for your research reports. Different
styles are optimized for different audiences and purposes.
</p>
</div>
}
>
<DialogTrigger asChild>
<Button
className="!border-brand !text-brand rounded-2xl"
variant="outline"
>
<CurrentIcon className="h-4 w-4" /> {currentStyleConfig.label}
</Button>
</DialogTrigger>
</Tooltip>
<DialogContent className="sm:max-w-[500px]">
<DialogHeader>
<DialogTitle>Choose Writing Style</DialogTitle>
<DialogDescription>
Select the writing style for your research reports. Each style is
optimized for different audiences and purposes.
</DialogDescription>
</DialogHeader>
<div className="grid gap-3 py-4">
{REPORT_STYLES.map((style) => {
const Icon = style.icon;
const isSelected = currentStyle === style.value;
return (
<button
key={style.value}
className={cn(
"hover:bg-accent flex items-start gap-3 rounded-lg border p-4 text-left transition-colors",
isSelected && "border-primary bg-accent",
)}
onClick={() => handleStyleChange(style.value)}
>
<Icon className="mt-0.5 h-5 w-5 shrink-0" />
<div className="flex-1 space-y-1">
<div className="flex items-center gap-2">
<h4 className="font-medium">{style.label}</h4>
{isSelected && <Check className="text-primary h-4 w-4" />}
</div>
<p className="text-muted-foreground text-sm">
{style.description}
</p>
</div>
</button>
);
})}
</div>
</DialogContent>
</Dialog>
);
}