Merge branch 'main' of http://113.45.157.195:3003/insiinc/leader-mail
This commit is contained in:
commit
700b3eb2c7
|
@ -24,15 +24,14 @@ interface LetterCardProps {
|
||||||
export function LetterCard({ letter }: LetterCardProps) {
|
export function LetterCard({ letter }: LetterCardProps) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full border-2 p-4 bg-white rounded-xl transition-all duration-300 ease-in-out group">
|
<div className="w-full p-4 bg-white transition-all duration-300 ease-in-out group">
|
||||||
<div className="flex flex-col gap-3">
|
<div className="flex flex-col gap-3">
|
||||||
{/* Title & Priority */}
|
{/* Title & Priority */}
|
||||||
<div className="flex justify-between items-start">
|
<div className="flex justify-between items-start">
|
||||||
<Title level={4} className="!mb-0 flex-1">
|
<Title level={4} className="!mb-0 flex-1">
|
||||||
<a
|
<a
|
||||||
href={`/letters/${letter.id}`}
|
href={`/${letter.id}/detail`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
className="text-primary transition-all duration-300 relative
|
className="text-primary transition-all duration-300 relative
|
||||||
before:absolute before:bottom-0 before:left-0 before:w-0 before:h-[2px] before:bg-primary-600
|
before:absolute before:bottom-0 before:left-0 before:w-0 before:h-[2px] before:bg-primary-600
|
||||||
|
|
|
@ -47,7 +47,7 @@ export default function PostCommentCard({
|
||||||
{isReceiverComment && (
|
{isReceiverComment && (
|
||||||
<div className=" ">
|
<div className=" ">
|
||||||
<span className=" px-2 text-sm rounded-full bg-blue-100 text-blue-800">
|
<span className=" px-2 text-sm rounded-full bg-blue-100 text-blue-800">
|
||||||
官方回答
|
官方回复
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -150,12 +150,6 @@ export default function PostCommentList() {
|
||||||
animate={{ opacity: 1, y: 0 }}
|
animate={{ opacity: 1, y: 0 }}
|
||||||
className="text-center py-12 text-slate-500">
|
className="text-center py-12 text-slate-500">
|
||||||
暂无回复,来发表第一条回复吧
|
暂无回复,来发表第一条回复吧
|
||||||
<Button
|
|
||||||
onClick={() => {
|
|
||||||
console.log(receiverIds);
|
|
||||||
}}>
|
|
||||||
123
|
|
||||||
</Button>
|
|
||||||
</motion.div>
|
</motion.div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { useContext } from "react";
|
import { useContext } from "react";
|
||||||
|
import { useState, useRef, useEffect } from "react";
|
||||||
import { PostDetailContext } from "../context/PostDetailContext";
|
import { PostDetailContext } from "../context/PostDetailContext";
|
||||||
import { motion } from "framer-motion";
|
import { motion } from "framer-motion";
|
||||||
|
|
||||||
|
@ -7,29 +8,45 @@ import { StatsSection } from "./StatsSection";
|
||||||
import PostResources from "../PostResources";
|
import PostResources from "../PostResources";
|
||||||
export default function Content() {
|
export default function Content() {
|
||||||
const { post, user } = useContext(PostDetailContext);
|
const { post, user } = useContext(PostDetailContext);
|
||||||
|
const [isExpanded, setIsExpanded] = useState(false);
|
||||||
|
const contentRef = useRef(null);
|
||||||
|
const [shouldCollapse, setShouldCollapse] = useState(false);
|
||||||
|
useEffect(() => {
|
||||||
|
if (contentRef.current) {
|
||||||
|
const shouldCollapse = contentRef.current.scrollHeight > 300; // 300px threshold
|
||||||
|
setShouldCollapse(shouldCollapse);
|
||||||
|
}
|
||||||
|
}, [post?.content]);
|
||||||
return (
|
return (
|
||||||
<motion.div
|
<div className="relative bg-white rounded-b-xl p-6 pt-2 shadow-lg border border-[#97A9C4]/30">
|
||||||
initial={{ opacity: 0, y: -20 }}
|
|
||||||
animate={{ opacity: 1, y: 0 }}
|
|
||||||
transition={{ duration: 0.5 }}
|
|
||||||
className="relative bg-white rounded-b-xl p-6 pt-2 shadow-lg border border-[#97A9C4]/30">
|
|
||||||
<motion.div
|
<motion.div
|
||||||
initial={{ opacity: 0 }}
|
initial={{ opacity: 0 }}
|
||||||
animate={{ opacity: 1 }}
|
animate={{ opacity: 1 }}
|
||||||
transition={{ delay: 0.6 }}
|
transition={{ delay: 0.6 }}
|
||||||
className="text-secondary-700">
|
className="text-secondary-700">
|
||||||
<div
|
<div
|
||||||
className="ql-editor p-0 space-y-1 leading-relaxed duration-300"
|
ref={contentRef}
|
||||||
|
className={`ql-editor p-0 space-y-1 leading-relaxed duration-300 ${
|
||||||
|
shouldCollapse && !isExpanded
|
||||||
|
? "max-h-[300px] overflow-hidden"
|
||||||
|
: ""
|
||||||
|
}`}
|
||||||
dangerouslySetInnerHTML={{
|
dangerouslySetInnerHTML={{
|
||||||
__html: post?.content || "",
|
__html: post?.content || "",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<PostResources post={post}></PostResources>
|
{shouldCollapse && (
|
||||||
{/* <div>{post.resources?.map((resource) => {})}</div> */}
|
<button
|
||||||
|
onClick={() => setIsExpanded(!isExpanded)}
|
||||||
|
className="mt-2 text-blue-500 hover:text-blue-700">
|
||||||
|
{isExpanded ? "Collapse" : "Expand"}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
<PostResources post={post} />
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
{/* Stats Section */}
|
{/* Stats Section */}
|
||||||
<StatsSection></StatsSection>
|
<StatsSection />
|
||||||
</motion.div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@ import { useContext } from "react";
|
||||||
import { PostDetailContext } from "../context/PostDetailContext";
|
import { PostDetailContext } from "../context/PostDetailContext";
|
||||||
import { Space, Typography } from "antd";
|
import { Space, Typography } from "antd";
|
||||||
import { PostBadge } from "../badge/PostBadge";
|
import { PostBadge } from "../badge/PostBadge";
|
||||||
|
import { MailOutlined, SendOutlined } from "@ant-design/icons";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
CalendarOutlined,
|
CalendarOutlined,
|
||||||
ClockCircleOutlined,
|
ClockCircleOutlined,
|
||||||
|
@ -10,25 +12,26 @@ import {
|
||||||
UserOutlined,
|
UserOutlined,
|
||||||
} from "@ant-design/icons";
|
} from "@ant-design/icons";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
|
import { CornerBadge } from "../badge/CornerBadeg";
|
||||||
const { Title, Paragraph, Text } = Typography;
|
const { Title, Paragraph, Text } = Typography;
|
||||||
export default function Header() {
|
export default function Header() {
|
||||||
const { post, user } = useContext(PostDetailContext);
|
const { post, user } = useContext(PostDetailContext);
|
||||||
return (
|
return (
|
||||||
<header className=" rounded-t-xl bg-gradient-to-r from-primary to-primary-400 text-white p-6">
|
<header className="rounded-t-xl bg-gradient-to-r from-primary to-primary-400 text-white p-6 relative">
|
||||||
<div className="flex flex-col space-y-6">
|
{/* 右上角标签 */}
|
||||||
|
{/* <CornerBadge type="state" value={post?.state}></CornerBadge> */}
|
||||||
|
|
||||||
|
<div className="flex flex-col space-b-1">
|
||||||
{/* 主标题 */}
|
{/* 主标题 */}
|
||||||
<div>
|
<div>
|
||||||
<h1 className="text-3xl font-bold tracking-wider flex items-center gap-2">
|
<h1 className="text-3xl font-bold tracking-wider flex items-center gap-2">
|
||||||
{post?.title}
|
{post?.title}
|
||||||
|
|
||||||
<PostBadge type="category" value={post?.term?.name} />
|
|
||||||
<PostBadge type="state" value={post?.state} />
|
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-4">
|
<div className="space-y-1">
|
||||||
{/* 收件人信息行 */}
|
{/* 收件人信息行 */}
|
||||||
<Space>
|
<Space className="mr-4">
|
||||||
<UserOutlined className="text-white" />
|
<MailOutlined className="text-white" />
|
||||||
<span className="text-white">收件人:</span>
|
<span className="text-white">收件人:</span>
|
||||||
|
|
||||||
{post?.receivers?.map((receiver, index) => (
|
{post?.receivers?.map((receiver, index) => (
|
||||||
|
@ -40,20 +43,15 @@ export default function Header() {
|
||||||
</Text>
|
</Text>
|
||||||
))}
|
))}
|
||||||
</Space>
|
</Space>
|
||||||
|
<Space className="mr-4">
|
||||||
{/* First Row - Basic Info */}
|
<SendOutlined className="text-white" />
|
||||||
<div className="flex flex-wrap items-center gap-1">
|
<span className="text-white">发件人:</span>
|
||||||
{/* Author Info Badge */}
|
|
||||||
<Space>
|
|
||||||
<UserOutlined className="text-white" />
|
|
||||||
<span className="text-white">发件人:</span>
|
|
||||||
<Text className="text-white" strong>
|
<Text className="text-white" strong>
|
||||||
{post?.author?.showname || "匿名用户"}
|
{post?.author?.showname || "匿名用户"}
|
||||||
</Text>
|
</Text>
|
||||||
</Space>
|
</Space>
|
||||||
<Text type="secondary">|</Text>
|
|
||||||
{/* Date Info Badge */}
|
{/* Date Info Badge */}
|
||||||
<Space>
|
<Space className="mr-4">
|
||||||
<CalendarOutlined className="text-white" />
|
<CalendarOutlined className="text-white" />
|
||||||
|
|
||||||
<Text className="text-white">
|
<Text className="text-white">
|
||||||
|
@ -61,18 +59,16 @@ export default function Header() {
|
||||||
{dayjs(post?.createdAt).format("YYYY-MM-DD")}
|
{dayjs(post?.createdAt).format("YYYY-MM-DD")}
|
||||||
</Text>
|
</Text>
|
||||||
</Space>
|
</Space>
|
||||||
<Text type="secondary">|</Text>
|
|
||||||
{/* Last Updated Badge */}
|
{/* Last Updated Badge */}
|
||||||
<Space>
|
<Space className="mr-4">
|
||||||
<ClockCircleOutlined className="text-white" />
|
<ClockCircleOutlined className="text-white" />
|
||||||
<Text className="text-white">
|
<Text className="text-white">
|
||||||
更新于:
|
更新于:
|
||||||
{dayjs(post?.updatedAt).format("YYYY-MM-DD")}
|
{dayjs(post?.updatedAt).format("YYYY-MM-DD")}
|
||||||
</Text>
|
</Text>
|
||||||
</Space>
|
</Space>
|
||||||
<Text type="secondary">|</Text>
|
|
||||||
{/* Visibility Status Badge */}
|
{/* Visibility Status Badge */}
|
||||||
<Space>
|
<Space className="mr-4">
|
||||||
{post?.isPublic ? (
|
{post?.isPublic ? (
|
||||||
<UnlockOutlined className="text-white" />
|
<UnlockOutlined className="text-white" />
|
||||||
) : (
|
) : (
|
||||||
|
@ -82,17 +78,31 @@ export default function Header() {
|
||||||
{post?.isPublic ? "公开" : "私信"}
|
{post?.isPublic ? "公开" : "私信"}
|
||||||
</Text>
|
</Text>
|
||||||
</Space>
|
</Space>
|
||||||
|
|
||||||
|
{/* First Row - Basic Info */}
|
||||||
|
<div className="flex flex-wrap items-center gap-1">
|
||||||
|
{/* Author Info Badge */}
|
||||||
</div>
|
</div>
|
||||||
{/* Second Row - Term and Tags */}
|
{/* Second Row - Term and Tags */}
|
||||||
{post?.meta?.tags?.length > 0 && (
|
{post?.meta?.tags?.length > 0 && (
|
||||||
<div className="flex flex-wrap gap-1">
|
<div className="flex flex-wrap gap-1">
|
||||||
{/* Tags Badges */}
|
{/* Tags Badges */}
|
||||||
|
|
||||||
|
<Space>
|
||||||
|
<PostBadge type="state" value={post?.state} />
|
||||||
|
</Space>
|
||||||
|
<Space>
|
||||||
|
<PostBadge
|
||||||
|
type="category"
|
||||||
|
value={post?.term?.name}
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
{post.meta.tags.length > 0 &&
|
{post.meta.tags.length > 0 &&
|
||||||
post.meta.tags.map((tag, index) => (
|
post.meta.tags.map((tag, index) => (
|
||||||
<Space key={index}>
|
<Space key={index}>
|
||||||
<PostBadge
|
<PostBadge
|
||||||
type="tag"
|
type="tag"
|
||||||
value={`#${tag}`}></PostBadge>
|
value={`${tag}`}></PostBadge>
|
||||||
</Space>
|
</Space>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,32 +1,39 @@
|
||||||
import React, { useContext, useMemo } from "react";
|
import React, { useContext, useMemo } from "react";
|
||||||
import { Image, Button } from "antd";
|
import { Image, Button } from "antd";
|
||||||
import { DownloadOutlined } from "@ant-design/icons";
|
import { DownloadOutlined, PaperClipOutlined } from "@ant-design/icons";
|
||||||
import { PostDetailContext } from "./context/PostDetailContext";
|
import { PostDetailContext } from "./context/PostDetailContext";
|
||||||
import { env } from "@web/src/env";
|
import { env } from "@web/src/env";
|
||||||
import dayjs from "dayjs";
|
import { PostDto } from "@nice/common";
|
||||||
import { PostDto } from "packages/common/dist";
|
|
||||||
|
|
||||||
export default function PostResources({ post }: { post: PostDto }) {
|
export default function PostResources({ post }: { post: PostDto }) {
|
||||||
const { user } = useContext(PostDetailContext);
|
|
||||||
const resources = useMemo(() => {
|
const resources = useMemo(() => {
|
||||||
return post?.resources?.map((resource) => ({
|
if (!post?.resources) return [];
|
||||||
url: `${env.SERVER_IP}/uploads/${resource.url}`,
|
|
||||||
title: resource.title,
|
|
||||||
}));
|
|
||||||
}, [post]);
|
|
||||||
|
|
||||||
const isImage = (url: string) => {
|
const isImage = (url: string) => {
|
||||||
return /\.(png|jpg|jpeg|gif|webp)$/i.test(url);
|
return /\.(png|jpg|jpeg|gif|webp)$/i.test(url);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
return post.resources
|
||||||
|
.map((resource) => ({
|
||||||
|
url: `${env.SERVER_IP}/uploads/${resource.url}`,
|
||||||
|
title: resource.title,
|
||||||
|
isImage: isImage(resource.url),
|
||||||
|
}))
|
||||||
|
.sort((a, b) => {
|
||||||
|
// 图片排在前面,非图片排在后面
|
||||||
|
if (a.isImage && !b.isImage) return -1;
|
||||||
|
if (!a.isImage && b.isImage) return 1;
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
}, [post]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
{resources?.map((resource) => (
|
<div className="flex flex-col gap-4">
|
||||||
<div
|
{resources
|
||||||
key={resource.url}
|
?.filter((resource) => resource.isImage)
|
||||||
className="flex items-center gap-4 mt-2 rounded-lg">
|
.map((resource) => (
|
||||||
{isImage(resource.url) ? (
|
<div key={resource.url} className="mt-2">
|
||||||
<>
|
|
||||||
<Image
|
<Image
|
||||||
src={resource.url}
|
src={resource.url}
|
||||||
alt={resource.title}
|
alt={resource.title}
|
||||||
|
@ -35,19 +42,29 @@ export default function PostResources({ post }: { post: PostDto }) {
|
||||||
height={"auto"}
|
height={"auto"}
|
||||||
style={{ objectFit: "cover" }}
|
style={{ objectFit: "cover" }}
|
||||||
/>
|
/>
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
icon={<DownloadOutlined />}
|
|
||||||
href={resource.url}
|
|
||||||
download
|
|
||||||
className="bg-blue-600 hover:bg-blue-700">
|
|
||||||
{resource.title || "下载"}
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
<div className="flex flex-wrap gap-4">
|
||||||
|
{resources
|
||||||
|
?.filter((resource) => !resource.isImage)
|
||||||
|
.map((resource) => (
|
||||||
|
<Button
|
||||||
|
key={resource.url}
|
||||||
|
type="text"
|
||||||
|
icon={
|
||||||
|
<PaperClipOutlined className="text-gray-500" />
|
||||||
|
}
|
||||||
|
href={resource.url}
|
||||||
|
download
|
||||||
|
className="flex items-center justify-start p-2 hover:bg-gray-100 transition-colors duration-200">
|
||||||
|
<span className="mr-2 text-gray-600 truncate max-w-[150px]">
|
||||||
|
{resource.title || "附件"}
|
||||||
|
</span>
|
||||||
|
<DownloadOutlined className="text-blue-600" />
|
||||||
|
</Button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
import { PostState, PostStateLabels } from "@nice/common";
|
||||||
|
|
||||||
|
export function CornerBadge({
|
||||||
|
type,
|
||||||
|
value,
|
||||||
|
className = "",
|
||||||
|
}: {
|
||||||
|
type: "priority" | "category" | "state" | "tag";
|
||||||
|
value: string;
|
||||||
|
className?: string;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
value && (
|
||||||
|
<div className="absolute top-1 right-1 ">
|
||||||
|
<div
|
||||||
|
className={` px-6 ${getBadgeStyle(type, value)} ${className} py-1.5 rounded-tr-xl rounded-bl-2xl`}>
|
||||||
|
{type === "state"
|
||||||
|
? PostStateLabels?.[value]
|
||||||
|
: value?.toUpperCase()}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const BADGE_STYLES = {
|
||||||
|
priority: {
|
||||||
|
high: "bg-white text-red-800",
|
||||||
|
medium: "bg-white text-yellow-800",
|
||||||
|
low: "bg-white text-green-800",
|
||||||
|
},
|
||||||
|
category: {
|
||||||
|
complaint: "bg-white text-orange-800",
|
||||||
|
suggestion: "bg-white text-blue-800",
|
||||||
|
request: "bg-white text-purple-800",
|
||||||
|
feedback: "bg-white text-teal-800",
|
||||||
|
},
|
||||||
|
state: {
|
||||||
|
[PostState.PENDING]: "bg-white text-yellow-800",
|
||||||
|
[PostState.PROCESSING]: "bg-white text-blue-800",
|
||||||
|
[PostState.RESOLVED]: "bg-white text-green-800",
|
||||||
|
},
|
||||||
|
tag: {
|
||||||
|
_: "bg-white text-primary-800",
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
const getBadgeStyle = (
|
||||||
|
type: keyof typeof BADGE_STYLES,
|
||||||
|
value: string
|
||||||
|
): string => {
|
||||||
|
if (type === "tag") {
|
||||||
|
return "bg-white text-primary";
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
BADGE_STYLES[type][value as keyof (typeof BADGE_STYLES)[typeof type]] ||
|
||||||
|
"bg-white text-gray-800"
|
||||||
|
);
|
||||||
|
};
|
|
@ -9,18 +9,18 @@ export function PostBadge({
|
||||||
value: string;
|
value: string;
|
||||||
className?: string;
|
className?: string;
|
||||||
}) {
|
}) {
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
value && (
|
value && (
|
||||||
<span
|
<span
|
||||||
className={`
|
className={`
|
||||||
inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium
|
inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium
|
||||||
${getBadgeStyle(type, value)}
|
${getBadgeStyle(type, value)}
|
||||||
transition-all duration-200 ease-in-out transform hover:scale-105
|
|
||||||
${className}
|
${className}
|
||||||
`}>
|
`}>
|
||||||
{type === "state" ? PostStateLabels?.[value] : value?.toUpperCase()}
|
{type === "state"
|
||||||
|
? PostStateLabels?.[value]
|
||||||
|
: value?.toUpperCase()}
|
||||||
</span>
|
</span>
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -28,23 +28,23 @@ export function PostBadge({
|
||||||
|
|
||||||
const BADGE_STYLES = {
|
const BADGE_STYLES = {
|
||||||
priority: {
|
priority: {
|
||||||
high: "bg-red-100 text-red-800",
|
high: "bg-white text-red-800",
|
||||||
medium: "bg-yellow-100 text-yellow-800",
|
medium: "bg-white text-yellow-800",
|
||||||
low: "bg-green-100 text-green-800",
|
low: "bg-white text-green-800",
|
||||||
},
|
},
|
||||||
category: {
|
category: {
|
||||||
complaint: "bg-orange-100 text-orange-800",
|
complaint: "bg-white text-orange-800",
|
||||||
suggestion: "bg-blue-100 text-blue-800",
|
suggestion: "bg-white text-blue-800",
|
||||||
request: "bg-purple-100 text-purple-800",
|
request: "bg-white text-purple-800",
|
||||||
feedback: "bg-teal-100 text-teal-800",
|
feedback: "bg-white text-teal-800",
|
||||||
},
|
},
|
||||||
state: {
|
state: {
|
||||||
[PostState.PENDING]: "bg-yellow-100 text-yellow-800",
|
[PostState.PENDING]: "bg-white text-yellow-800",
|
||||||
[PostState.PROCESSING]: "bg-blue-100 text-blue-800",
|
[PostState.PROCESSING]: "bg-white text-blue-800",
|
||||||
[PostState.RESOLVED]: "bg-green-100 text-green-800",
|
[PostState.RESOLVED]: "bg-white text-green-800",
|
||||||
},
|
},
|
||||||
tag: {
|
tag: {
|
||||||
_: "bg-primary-100 text-primary-800",
|
_: "bg-white text-primary-800",
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
@ -53,10 +53,10 @@ const getBadgeStyle = (
|
||||||
value: string
|
value: string
|
||||||
): string => {
|
): string => {
|
||||||
if (type === "tag") {
|
if (type === "tag") {
|
||||||
return "bg-primary-100 text-primary";
|
return "bg-white text-primary";
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
BADGE_STYLES[type][value as keyof (typeof BADGE_STYLES)[typeof type]] ||
|
BADGE_STYLES[type][value as keyof (typeof BADGE_STYLES)[typeof type]] ||
|
||||||
"bg-gray-100 text-gray-800"
|
"bg-white text-gray-800"
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -54,7 +54,6 @@ export function LetterFormProvider({
|
||||||
data: {
|
data: {
|
||||||
...data,
|
...data,
|
||||||
type: PostType.POST,
|
type: PostType.POST,
|
||||||
|
|
||||||
terms: {
|
terms: {
|
||||||
connect: (terms || [])?.filter(Boolean).map((id) => ({
|
connect: (terms || [])?.filter(Boolean).map((id) => ({
|
||||||
id,
|
id,
|
||||||
|
|
|
@ -38,7 +38,7 @@ export const routes: CustomRouteObject[] = [
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
index: true,
|
index: true,
|
||||||
element: <LetterListPage></LetterListPage>
|
element: <LetterListPage></LetterListPage>,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: ":id?/detail",
|
path: ":id?/detail",
|
||||||
|
@ -53,17 +53,17 @@ export const routes: CustomRouteObject[] = [
|
||||||
element: <WriteLetterPage></WriteLetterPage>,
|
element: <WriteLetterPage></WriteLetterPage>,
|
||||||
},
|
},
|
||||||
|
|
||||||
, {
|
{
|
||||||
path: 'letter-progress',
|
path: "letter-progress",
|
||||||
element: <LetterProgressPage></LetterProgressPage>
|
element: <LetterProgressPage></LetterProgressPage>,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'help',
|
path: "help",
|
||||||
element: <HelpPage></HelpPage>
|
element: <HelpPage></HelpPage>,
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
adminRoute
|
adminRoute,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue