parent
ff162722a9
commit
67d9559229
|
|
@ -21,6 +21,7 @@
|
|||
"!unused-imports/no-unused-imports",
|
||||
"!@stylistic/jsx-self-closing-comp",
|
||||
"!tailwindcss/classnames-order",
|
||||
"!arrow-body-style",
|
||||
"*"
|
||||
],
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ export function ErrorElement() {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="m-auto flex min-h-full max-w-prose select-text flex-col p-8 pt-12">
|
||||
<div className="m-auto flex min-h-full max-w-prose select-text flex-col p-8 pt-24">
|
||||
<div className="drag-region fixed inset-x-0 top-0 h-12" />
|
||||
<div className="center flex flex-col">
|
||||
<i className="i-mgc-bug-cute-re size-12 text-red-400" />
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
import { CollapseGroup } from "@renderer/components/ui/collapse"
|
||||
import { useCollapseGroupItemState } from "@renderer/components/ui/collapse/hooks"
|
||||
import { cn } from "@renderer/lib/utils"
|
||||
import { setEntryContentPlaceholderLogoShow } from "@renderer/modules/entry-content/atoms"
|
||||
import { useEffect } from "react"
|
||||
|
||||
import { DayOf } from "./constants"
|
||||
import { DailyItem } from "./daily"
|
||||
import type { DailyView } from "./types"
|
||||
|
||||
export const EntryPlaceholderDaily = ({
|
||||
view,
|
||||
className,
|
||||
}: {
|
||||
view: DailyView
|
||||
className?: string
|
||||
}) => (
|
||||
<div className={cn(className, "mx-auto flex w-[75ch] flex-col gap-6")}>
|
||||
<CollapseGroup>
|
||||
<CtxConsumer />
|
||||
<DailyItem day={DayOf.Today} view={view} />
|
||||
<DailyItem day={DayOf.Yesterday} view={view} />
|
||||
</CollapseGroup>
|
||||
</div>
|
||||
)
|
||||
const CtxConsumer = () => {
|
||||
const status = useCollapseGroupItemState()
|
||||
const isAllCollapsed = Object.values(status).every((v) => !v)
|
||||
useEffect(() => {
|
||||
setEntryContentPlaceholderLogoShow(isAllCollapsed)
|
||||
}, [isAllCollapsed])
|
||||
return null
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
import { AutoResizeHeight } from "@renderer/components/ui/auto-resize-height"
|
||||
import {
|
||||
Tabs,
|
||||
TabsContent,
|
||||
TabsList,
|
||||
TabsTrigger,
|
||||
} from "@renderer/components/ui/tabs"
|
||||
import { FeedViewType } from "@renderer/lib/enum"
|
||||
|
||||
import { DayOf } from "./constants"
|
||||
import { DailyReportContent, DailyReportTitle } from "./daily"
|
||||
import { useParseDailyDate } from "./hooks"
|
||||
|
||||
const tabs = [DayOf.Today, DayOf.Yesterday]
|
||||
|
||||
export const FeedDailyModalContent = () => {
|
||||
const today = useParseDailyDate(DayOf.Today)
|
||||
const yesterday = useParseDailyDate(DayOf.Yesterday)
|
||||
|
||||
return (
|
||||
<Tabs defaultValue={DayOf.Today as any}>
|
||||
<TabsList className="w-full">
|
||||
{tabs.map((tab: any) => (
|
||||
<TabsTrigger key={tab} value={tab}>
|
||||
{/* {tab} */}
|
||||
<DailyReportTitle {...(tab === DayOf.Today ? today : yesterday)} />
|
||||
</TabsTrigger>
|
||||
))}
|
||||
</TabsList>
|
||||
<AutoResizeHeight spring>
|
||||
{tabs.map((tab: any) => (
|
||||
<TabsContent key={tab} value={tab} className="mt-8">
|
||||
<DailyReportContent
|
||||
// TODO support other view types
|
||||
view={FeedViewType.SocialMedia}
|
||||
{...(tab === DayOf.Today ? today : yesterday)}
|
||||
/>
|
||||
</TabsContent>
|
||||
))}
|
||||
</AutoResizeHeight>
|
||||
</Tabs>
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
export enum DayOf {
|
||||
Today,
|
||||
Yesterday,
|
||||
}
|
||||
|
|
@ -0,0 +1,160 @@
|
|||
import { AutoResizeHeight } from "@renderer/components/ui/auto-resize-height"
|
||||
import { Card, CardHeader } from "@renderer/components/ui/card"
|
||||
import { Collapse } from "@renderer/components/ui/collapse"
|
||||
import { LoadingCircle } from "@renderer/components/ui/loading"
|
||||
import { ScrollArea } from "@renderer/components/ui/scroll-area"
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipPortal,
|
||||
TooltipTrigger,
|
||||
} from "@renderer/components/ui/tooltip"
|
||||
import { useAuthQuery } from "@renderer/hooks/common"
|
||||
import { apiClient } from "@renderer/lib/api-fetch"
|
||||
import { defineQuery } from "@renderer/lib/defineQuery"
|
||||
import { parseMarkdown } from "@renderer/lib/parse-markdown"
|
||||
import { MarkAllButton } from "@renderer/modules/entry-column/mark-all-button"
|
||||
import type { FC } from "react"
|
||||
import { useMemo, useState } from "react"
|
||||
|
||||
import { useParseDailyDate } from "./hooks"
|
||||
import type { DailyItemProps, DailyView } from "./types"
|
||||
|
||||
export const DailyItem = ({ view, day }: DailyItemProps) => {
|
||||
const { title, startDate, endDate } = useParseDailyDate(day)
|
||||
return (
|
||||
<Collapse
|
||||
hideArrow
|
||||
title={
|
||||
<DailyReportTitle title={title} startDate={startDate} endDate={endDate} />
|
||||
}
|
||||
className="mx-auto w-full max-w-lg border-b pb-6 last:border-b-0"
|
||||
>
|
||||
<DailyReportContent endDate={endDate} view={view} startDate={startDate} />
|
||||
</Collapse>
|
||||
)
|
||||
}
|
||||
|
||||
export const DailyReportTitle = ({
|
||||
endDate,
|
||||
startDate,
|
||||
title,
|
||||
}: {
|
||||
title: string
|
||||
startDate: number
|
||||
endDate: number
|
||||
}) => (
|
||||
<div className="flex items-center justify-center gap-2 text-base">
|
||||
<i className="i-mgc-magic-2-cute-re" />
|
||||
<div className="font-medium">
|
||||
{title}
|
||||
's Top News
|
||||
</div>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<i className="i-mgc-question-cute-re translate-y-px" />
|
||||
</TooltipTrigger>
|
||||
<TooltipPortal>
|
||||
<TooltipContent>
|
||||
<ul className="list-outside list-decimal text-wrap pl-6 text-left text-sm">
|
||||
<li>
|
||||
Here is news selected by AI from your timeline
|
||||
{" ("}
|
||||
{new Date(startDate).toLocaleTimeString("en-US", {
|
||||
weekday: "short",
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
})}
|
||||
{" "}
|
||||
-
|
||||
{" "}
|
||||
{new Date(endDate + 1).toLocaleTimeString("en-US", {
|
||||
weekday: "short",
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
})}
|
||||
{") "}
|
||||
that may be important to you.
|
||||
</li>
|
||||
<li>Update daily at 8 AM and 8 PM.</li>
|
||||
</ul>
|
||||
</TooltipContent>
|
||||
</TooltipPortal>
|
||||
</Tooltip>
|
||||
</div>
|
||||
)
|
||||
|
||||
export const DailyReportContent: FC<{
|
||||
view: DailyView
|
||||
startDate: number
|
||||
endDate: number
|
||||
}> = ({ endDate, startDate, view }) => {
|
||||
const content = useAuthQuery(
|
||||
defineQuery(["daily", view, startDate, endDate], async () => {
|
||||
const res = await apiClient.ai.daily.$get({
|
||||
query: {
|
||||
startDate: `${+startDate}`,
|
||||
view: `${view}`,
|
||||
},
|
||||
})
|
||||
return res.data
|
||||
}),
|
||||
{
|
||||
meta: {
|
||||
persist: true,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
const [markAllButtonRef, setMarkAllButtonRef] =
|
||||
useState<HTMLButtonElement | null>(null)
|
||||
|
||||
const eleContent = useMemo(() => {
|
||||
if (!content.data) return null
|
||||
const { content: _content } = parseMarkdown(content.data)
|
||||
return _content
|
||||
}, [content.data])
|
||||
|
||||
return (
|
||||
<Card className="border-none bg-transparent">
|
||||
<CardHeader className="space-y-0 p-0">
|
||||
<ScrollArea.ScrollArea
|
||||
mask={false}
|
||||
flex
|
||||
viewportClassName="max-h-[calc(100vh-500px)]"
|
||||
>
|
||||
<AutoResizeHeight spring>
|
||||
{content.isLoading ? (
|
||||
<LoadingCircle size="large" className="mt-8 text-center" />
|
||||
) : (
|
||||
eleContent && (
|
||||
<div className="prose-sm mt-4 px-6 prose-p:my-1 prose-ul:my-1 prose-ul:list-outside prose-ul:list-disc prose-li:marker:text-theme-accent">
|
||||
{eleContent}
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
</AutoResizeHeight>
|
||||
</ScrollArea.ScrollArea>
|
||||
{eleContent && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
markAllButtonRef?.click()
|
||||
}}
|
||||
className="!mt-4 ml-auto flex items-center rounded-lg py-1 pr-2 duration-200 hover:!bg-theme-button-hover"
|
||||
>
|
||||
<MarkAllButton
|
||||
ref={setMarkAllButtonRef}
|
||||
filter={{
|
||||
startTime: startDate,
|
||||
endTime: endDate,
|
||||
}}
|
||||
className="pointer-events-none text-[1.05rem]"
|
||||
/>
|
||||
<span>Mark all as read</span>
|
||||
</button>
|
||||
)}
|
||||
</CardHeader>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
import { useModalStack } from "@renderer/components/ui/modal"
|
||||
import { useCallback, useMemo } from "react"
|
||||
|
||||
import { DayOf } from "./constants"
|
||||
import { FeedDailyModalContent } from "./FeedDailyModalContent"
|
||||
|
||||
export const useParseDailyDate = (day: DayOf) =>
|
||||
useMemo(() => {
|
||||
const dateObj = new Date()
|
||||
|
||||
const nowHour = dateObj.getHours()
|
||||
let startDate: number
|
||||
let endDate: number
|
||||
let title: string
|
||||
|
||||
const today8AM = dateObj.setHours(8, 0, 0, 0)
|
||||
const today8PM = dateObj.setHours(20, 0, 0, 0)
|
||||
dateObj.setDate(dateObj.getDate() - 1)
|
||||
const yesterday8AM = dateObj.setHours(8, 0, 0, 0)
|
||||
const yesterday8PM = dateObj.setHours(20, 0, 0, 0)
|
||||
dateObj.setDate(dateObj.getDate() - 1)
|
||||
const dayBeforeYesterday8PM = dateObj.setHours(20, 0, 0, 0)
|
||||
|
||||
const isToday = day === DayOf.Today
|
||||
// For index 0, get the last past 8 AM or 8 PM; for index 1, get the second last past 8 AM or 8 PM.
|
||||
if (nowHour >= 20) {
|
||||
if (isToday) {
|
||||
endDate = today8PM - 1
|
||||
startDate = today8AM
|
||||
title = "Today"
|
||||
} else {
|
||||
endDate = today8AM - 1
|
||||
startDate = yesterday8PM
|
||||
title = "Last Night"
|
||||
}
|
||||
} else if (nowHour >= 8) {
|
||||
if (isToday) {
|
||||
endDate = today8AM - 1
|
||||
startDate = yesterday8PM
|
||||
title = "Last Night"
|
||||
} else {
|
||||
endDate = yesterday8PM - 1
|
||||
startDate = yesterday8AM
|
||||
title = "Yesterday"
|
||||
}
|
||||
} else {
|
||||
if (isToday) {
|
||||
endDate = yesterday8PM - 1
|
||||
startDate = yesterday8AM
|
||||
title = "Yesterday"
|
||||
} else {
|
||||
endDate = yesterday8AM - 1
|
||||
startDate = dayBeforeYesterday8PM
|
||||
title = "The Night Before Last"
|
||||
}
|
||||
}
|
||||
|
||||
return { title, startDate, endDate }
|
||||
}, [day])
|
||||
|
||||
export const useAIDailyReportModal = () => {
|
||||
const { present } = useModalStack()
|
||||
|
||||
return useCallback(() => {
|
||||
present({
|
||||
content: () => <FeedDailyModalContent />,
|
||||
title: "AI Daily Report",
|
||||
clickOutsideToDismiss: true,
|
||||
})
|
||||
}, [present])
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
import type { FeedViewType } from "@renderer/lib/enum"
|
||||
|
||||
import type { DayOf } from "./constants"
|
||||
|
||||
export type DailyView = Extract<
|
||||
FeedViewType,
|
||||
FeedViewType.Articles | FeedViewType.SocialMedia
|
||||
>
|
||||
export interface DailyItemProps {
|
||||
view: DailyView
|
||||
day: DayOf
|
||||
}
|
||||
|
|
@ -5,7 +5,6 @@ import {
|
|||
import { useWhoami } from "@renderer/atoms/user"
|
||||
import { ActionButton } from "@renderer/components/ui/button"
|
||||
import { DividerVertical } from "@renderer/components/ui/divider"
|
||||
import { useModalStack } from "@renderer/components/ui/modal"
|
||||
import { EllipsisHorizontalTextWithTooltip } from "@renderer/components/ui/typography"
|
||||
import {
|
||||
FEED_COLLECTION_LIST,
|
||||
|
|
@ -23,7 +22,7 @@ import { useRefreshFeedMutation } from "@renderer/queries/feed"
|
|||
import { useFeedById, useFeedHeaderTitle } from "@renderer/store/feed"
|
||||
import type { FC } from "react"
|
||||
|
||||
import { Daily } from "../entry-content/daily"
|
||||
import { useAIDailyReportModal } from "../ai/ai-daily/hooks"
|
||||
import { EntryHeader } from "../entry-content/header"
|
||||
import { MarkAllButton } from "./mark-all-button"
|
||||
|
||||
|
|
@ -169,21 +168,10 @@ export const EntryListHeader: FC<{
|
|||
}
|
||||
|
||||
const DailyReportButton: FC = () => {
|
||||
const { present } = useModalStack()
|
||||
|
||||
const present = useAIDailyReportModal()
|
||||
return (
|
||||
<ActionButton
|
||||
onClick={() => {
|
||||
present({
|
||||
title: "Daily Report",
|
||||
content: () => (
|
||||
<Daily
|
||||
view={FeedViewType.SocialMedia}
|
||||
|
||||
/>
|
||||
),
|
||||
})
|
||||
}}
|
||||
onClick={present}
|
||||
tooltip="Daily Report"
|
||||
>
|
||||
<i className="i-mgc-magic-2-cute-re" />
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { Slot } from "@radix-ui/react-slot"
|
||||
import { FeedIcon } from "@renderer/components/feed-icon"
|
||||
import { ActionButton } from "@renderer/components/ui/button"
|
||||
import { RelativeTime } from "@renderer/components/ui/datetime"
|
||||
import { RelativeDay, RelativeTime } from "@renderer/components/ui/datetime"
|
||||
import { Media } from "@renderer/components/ui/media"
|
||||
import { usePreviewMedia } from "@renderer/components/ui/media/hooks"
|
||||
import { Skeleton } from "@renderer/components/ui/skeleton"
|
||||
|
|
@ -121,7 +121,9 @@ const ActionBar = ({ entryId }: { entryId: string }) => {
|
|||
return (
|
||||
<div className="flex origin-right scale-90 items-center gap-1">
|
||||
{items
|
||||
.filter((item) => !item.hide && (item.key !== "read" && item.key !== "unread"))
|
||||
.filter(
|
||||
(item) => !item.hide && item.key !== "read" && item.key !== "unread",
|
||||
)
|
||||
.map((item) => (
|
||||
<ActionButton
|
||||
icon={
|
||||
|
|
@ -175,20 +177,26 @@ export const SocialMediaDateItem = ({
|
|||
className?: string
|
||||
}) => {
|
||||
const dateObj = new Date(date)
|
||||
const dateString = dateObj.toLocaleDateString("en-US", { weekday: "long", month: "short", day: "numeric" })
|
||||
|
||||
const startOfDay = new Date(dateObj.setHours(0, 0, 0, 0)).getTime()
|
||||
const endOfDay = new Date(dateObj.setHours(23, 59, 59, 999)).getTime()
|
||||
const view = useRouteParamsSelector((s) => s.view)
|
||||
|
||||
return (
|
||||
<div className={cn(className, "m-auto w-[75ch] gap-3 pl-5 text-base", views[view].wideMode && "flex justify-center")}>
|
||||
<div
|
||||
className={cn(
|
||||
className,
|
||||
"m-auto w-[75ch] gap-3 pl-5 text-base",
|
||||
views[view].wideMode && "flex justify-center",
|
||||
)}
|
||||
>
|
||||
<MarkAllButton
|
||||
filter={{
|
||||
startTime: startOfDay,
|
||||
endTime: endOfDay,
|
||||
}}
|
||||
/>
|
||||
{dateString}
|
||||
<RelativeDay date={dateObj} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,235 +0,0 @@
|
|||
import { AutoResizeHeight } from "@renderer/components/ui/auto-resize-height"
|
||||
import { Card, CardHeader } from "@renderer/components/ui/card"
|
||||
import { Collapse, CollapseGroup } from "@renderer/components/ui/collapse"
|
||||
import {
|
||||
useCollapseGroupItemState,
|
||||
} from "@renderer/components/ui/collapse/hooks"
|
||||
import { LoadingCircle } from "@renderer/components/ui/loading"
|
||||
import { ScrollArea } from "@renderer/components/ui/scroll-area"
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from "@renderer/components/ui/tooltip"
|
||||
import { useAuthQuery } from "@renderer/hooks/common"
|
||||
import { apiClient } from "@renderer/lib/api-fetch"
|
||||
import { defineQuery } from "@renderer/lib/defineQuery"
|
||||
import type { FeedViewType } from "@renderer/lib/enum"
|
||||
import { parseMarkdown } from "@renderer/lib/parse-markdown"
|
||||
import { cn } from "@renderer/lib/utils"
|
||||
import { MarkAllButton } from "@renderer/modules/entry-column/mark-all-button"
|
||||
import type { FC } from "react"
|
||||
import { useEffect, useMemo, useState } from "react"
|
||||
|
||||
import { setEntryContentPlaceholderLogoShow } from "./atoms"
|
||||
|
||||
type DailyView = Extract<
|
||||
FeedViewType,
|
||||
FeedViewType.Articles | FeedViewType.SocialMedia
|
||||
>
|
||||
enum DayOf {
|
||||
Today,
|
||||
Yesterday,
|
||||
}
|
||||
interface DailyItemProps {
|
||||
view: DailyView
|
||||
day: DayOf
|
||||
}
|
||||
|
||||
const DailyItem = ({ view, day }: DailyItemProps) => {
|
||||
const dateObj = new Date()
|
||||
|
||||
const nowHour = dateObj.getHours()
|
||||
let startDate: number
|
||||
let endDate: number
|
||||
let title: string
|
||||
|
||||
const today8AM = dateObj.setHours(8, 0, 0, 0)
|
||||
const today8PM = dateObj.setHours(20, 0, 0, 0)
|
||||
dateObj.setDate(dateObj.getDate() - 1)
|
||||
const yesterday8AM = dateObj.setHours(8, 0, 0, 0)
|
||||
const yesterday8PM = dateObj.setHours(20, 0, 0, 0)
|
||||
dateObj.setDate(dateObj.getDate() - 1)
|
||||
const dayBeforeYesterday8PM = dateObj.setHours(20, 0, 0, 0)
|
||||
|
||||
const isToday = day === DayOf.Today
|
||||
// For index 0, get the last past 8 AM or 8 PM; for index 1, get the second last past 8 AM or 8 PM.
|
||||
if (nowHour >= 20) {
|
||||
if (isToday) {
|
||||
endDate = today8PM - 1
|
||||
startDate = today8AM
|
||||
title = "Today"
|
||||
} else {
|
||||
endDate = today8AM - 1
|
||||
startDate = yesterday8PM
|
||||
title = "Last Night"
|
||||
}
|
||||
} else if (nowHour >= 8) {
|
||||
if (isToday) {
|
||||
endDate = today8AM - 1
|
||||
startDate = yesterday8PM
|
||||
title = "Last Night"
|
||||
} else {
|
||||
endDate = yesterday8PM - 1
|
||||
startDate = yesterday8AM
|
||||
title = "Yesterday"
|
||||
}
|
||||
} else {
|
||||
if (isToday) {
|
||||
endDate = yesterday8PM - 1
|
||||
startDate = yesterday8AM
|
||||
title = "Yesterday"
|
||||
} else {
|
||||
endDate = yesterday8AM - 1
|
||||
startDate = dayBeforeYesterday8PM
|
||||
title = "The Night Before Last"
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Collapse
|
||||
hideArrow
|
||||
title={(
|
||||
<div className="flex items-center justify-center gap-2 text-base">
|
||||
<i className="i-mgc-magic-2-cute-re" />
|
||||
<div className="font-medium">
|
||||
{title}
|
||||
's Top News
|
||||
</div>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<i className="i-mgc-question-cute-re translate-y-px" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<ul className="list-decimal text-wrap pl-4 text-left text-sm">
|
||||
<li>
|
||||
Here is news selected by AI from your timeline
|
||||
{" ("}
|
||||
{new Date(startDate).toLocaleTimeString("en-US", {
|
||||
weekday: "short",
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
})}
|
||||
{" "}
|
||||
-
|
||||
{" "}
|
||||
{new Date(endDate + 1).toLocaleTimeString("en-US", {
|
||||
weekday: "short",
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
})}
|
||||
{") "}
|
||||
that may be important to you.
|
||||
</li>
|
||||
<li>Update daily at 8 AM and 8 PM.</li>
|
||||
</ul>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
)}
|
||||
className="mx-auto w-full max-w-lg border-b pb-6 last:border-b-0"
|
||||
>
|
||||
<DailyReportContent endDate={endDate} view={view} startDate={startDate} />
|
||||
</Collapse>
|
||||
)
|
||||
}
|
||||
|
||||
const DailyReportContent: FC<{
|
||||
view: DailyView
|
||||
startDate: number
|
||||
endDate: number
|
||||
}> = ({ endDate, startDate, view }) => {
|
||||
const content = useAuthQuery(
|
||||
defineQuery(["daily", view, startDate, endDate], async () => {
|
||||
const res = await apiClient.ai.daily.$get({
|
||||
query: {
|
||||
startDate: `${+startDate}`,
|
||||
view: `${view}`,
|
||||
},
|
||||
})
|
||||
return res.data
|
||||
}),
|
||||
{
|
||||
meta: {
|
||||
persist: true,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
const [markAllButtonRef, setMarkAllButtonRef] =
|
||||
useState<HTMLButtonElement | null>(null)
|
||||
|
||||
const eleContent = useMemo(() => {
|
||||
if (!content.data) return null
|
||||
const { content: _content } = parseMarkdown(content.data)
|
||||
return _content
|
||||
}, [content.data])
|
||||
|
||||
return (
|
||||
<Card className="border-none bg-transparent">
|
||||
<CardHeader className="space-y-0 p-0">
|
||||
<ScrollArea.ScrollArea
|
||||
mask={false}
|
||||
flex
|
||||
viewportClassName="max-h-[calc(100vh-500px)]"
|
||||
>
|
||||
<AutoResizeHeight spring>
|
||||
{content.isLoading ? (
|
||||
<LoadingCircle size="large" className="mt-8 text-center" />
|
||||
) : (
|
||||
eleContent && (
|
||||
<div className="prose-sm mt-4 px-6 prose-p:my-1 prose-ul:my-1 prose-ul:list-outside prose-ul:list-disc prose-li:marker:text-theme-accent">
|
||||
{eleContent}
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
</AutoResizeHeight>
|
||||
</ScrollArea.ScrollArea>
|
||||
{eleContent && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
markAllButtonRef?.click()
|
||||
}}
|
||||
className="!mt-4 ml-auto flex items-center rounded-lg py-1 pr-2 duration-200 hover:!bg-theme-button-hover"
|
||||
>
|
||||
<MarkAllButton
|
||||
ref={setMarkAllButtonRef}
|
||||
filter={{
|
||||
startTime: startDate,
|
||||
endTime: endDate,
|
||||
}}
|
||||
className="pointer-events-none text-[1.05rem]"
|
||||
/>
|
||||
<span>Mark all as read</span>
|
||||
</button>
|
||||
)}
|
||||
</CardHeader>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
export const Daily = ({
|
||||
view,
|
||||
className,
|
||||
}: {
|
||||
view: DailyView
|
||||
className?: string
|
||||
}) => (
|
||||
<div className={cn(className, "mx-auto flex w-[75ch] flex-col gap-6")}>
|
||||
<CollapseGroup>
|
||||
<CtxConsumer />
|
||||
<DailyItem day={DayOf.Today} view={view} />
|
||||
<DailyItem day={DayOf.Yesterday} view={view} />
|
||||
</CollapseGroup>
|
||||
</div>
|
||||
)
|
||||
|
||||
const CtxConsumer = () => {
|
||||
const status = useCollapseGroupItemState()
|
||||
const isAllCollapsed = Object.values(status).every((v) => !v)
|
||||
useEffect(() => {
|
||||
setEntryContentPlaceholderLogoShow(isAllCollapsed)
|
||||
}, [isAllCollapsed])
|
||||
return null
|
||||
}
|
||||
|
|
@ -32,9 +32,9 @@ import type { FC, ReactNode } from "react"
|
|||
import { useEffect, useLayoutEffect, useState } from "react"
|
||||
|
||||
import { LoadingCircle } from "../../components/ui/loading"
|
||||
import { EntryPlaceholderDaily } from "../ai/ai-daily/EntryPlaceholderDaily"
|
||||
import { EntryTranslation } from "../entry-column/translation"
|
||||
import { setEntryContentScrollToTop, setEntryTitleMeta } from "./atoms"
|
||||
import { Daily } from "./daily"
|
||||
import { EntryPlaceholderLogo } from "./entry-placeholder"
|
||||
import { EntryHeader } from "./header"
|
||||
import { EntryContentProvider } from "./provider"
|
||||
|
|
@ -53,7 +53,7 @@ export const EntryContent = ({ entryId }: { entryId: ActiveEntryId }) => {
|
|||
>
|
||||
<EntryPlaceholderLogo />
|
||||
{feedId === ROUTE_FEED_PENDING && view === FeedViewType.Articles && (
|
||||
<Daily view={view} />
|
||||
<EntryPlaceholderDaily view={view} />
|
||||
)}
|
||||
</m.div>
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in New Issue