feat: dot unread indicator

This commit is contained in:
DIYgod 2024-06-25 22:13:41 +08:00
parent 1d2d58da88
commit 562e69910e
No known key found for this signature in database
9 changed files with 32 additions and 14 deletions

View File

@ -11,7 +11,7 @@ export const views = [
{
name: "Articles",
icon: <i className="i-mgc-paper-cute-fi" />,
className: "text-amber-700",
className: "text-orange-600",
translation: "title,description",
},
{

View File

@ -18,7 +18,7 @@ export function ArticleItem({ entryId, entryPreview, translation }: UniversalIte
if (!entry) return <ReactVirtuosoItemPlaceholder />
return (
<div className="flex px-2 py-3">
<div className={cn("relative flex px-2 py-3", !asRead && "before:absolute before:-left-1 before:top-[18px] before:block before:size-2 before:rounded-full before:bg-blue-500")}>
<FeedIcon feed={entry.feeds} entry={entry.entries} />
<div className="-mt-0.5 line-clamp-4 flex-1 text-sm leading-tight">
<div className={cn("flex gap-1 text-[10px] font-bold", asRead ? "text-zinc-400" : "text-zinc-500")}>

View File

@ -1,4 +1,5 @@
import { FeedIcon } from "@renderer/components/feed-icon"
import { useAsRead } from "@renderer/hooks"
import dayjs from "@renderer/lib/dayjs"
import { cn } from "@renderer/lib/utils"
import { EntryTranslation } from "@renderer/modules/entry-column/translation"
@ -9,13 +10,16 @@ import type { UniversalItemProps } from "./types"
export function AudioItem({ entryId, entryPreview, translation }: UniversalItemProps) {
const entry = useEntry(entryId) || entryPreview
const asRead = useAsRead(entry)
if (!entry) return <ReactVirtuosoItemPlaceholder />
return (
<div className="flex px-2 py-4">
<div className={cn("relative flex px-2 py-3", !asRead && "before:absolute before:-left-1 before:top-[18px] before:block before:size-2 before:rounded-full before:bg-blue-500")}>
<FeedIcon feed={entry.feeds} entry={entry.entries} />
<div className="-mt-0.5 line-clamp-5 flex-1 text-sm leading-tight">
<div className="space-x-1 text-[10px] text-zinc-500">
<span>{entry.feeds.title}</span>
<div className={cn("flex gap-1 text-[10px] font-bold", asRead ? "text-zinc-400" : "text-zinc-500")}>
<span className="truncate">{entry.feeds.title}</span>
<span>·</span>
<span>
{dayjs

View File

@ -122,7 +122,7 @@ function EntryItemImpl({ entry, view }: { entry: EntryModel, view?: number }) {
!views[view || 0].wideMode &&
isActive &&
"bg-theme-item-active",
asRead ? "text-zinc-500/90" : "text-zinc-900 dark:text-white/90",
asRead ? "text-zinc-700" : "text-zinc-900 dark:text-white/90",
)}
onClick={handleClick}
onDoubleClick={handleDoubleClick}

View File

@ -1,4 +1,5 @@
import { FeedIcon } from "@renderer/components/feed-icon"
import { useAsRead } from "@renderer/hooks"
import dayjs from "@renderer/lib/dayjs"
import { cn } from "@renderer/lib/utils"
import { EntryTranslation } from "@renderer/modules/entry-column/translation"
@ -9,13 +10,16 @@ import type { UniversalItemProps } from "./types"
export function NotificationItem({ entryId, entryPreview, translation }: UniversalItemProps) {
const entry = useEntry(entryId) || entryPreview
const asRead = useAsRead(entry)
if (!entry) return <ReactVirtuosoItemPlaceholder />
return (
<div className="flex px-2 py-4">
<div className={cn("relative flex px-2 py-3", !asRead && "before:absolute before:-left-1 before:top-[18px] before:block before:size-2 before:rounded-full before:bg-blue-500")}>
<FeedIcon feed={entry.feeds} entry={entry.entries} />
<div className="-mt-0.5 line-clamp-5 flex-1 text-sm leading-tight">
<div className="space-x-1 text-[10px] text-zinc-500">
<span>{entry.feeds.title}</span>
<div className={cn("flex gap-1 text-[10px] font-bold", asRead ? "text-zinc-400" : "text-zinc-500")}>
<span className="truncate">{entry.feeds.title}</span>
<span>·</span>
<span>
{dayjs

View File

@ -1,6 +1,7 @@
import { FeedIcon } from "@renderer/components/feed-icon"
import { SwipeImages } from "@renderer/components/ui/image/swipe-images"
import { ReactVirtuosoItemPlaceholder } from "@renderer/components/ui/placeholder"
import { useAsRead } from "@renderer/hooks"
import dayjs from "@renderer/lib/dayjs"
import { cn } from "@renderer/lib/utils"
import { EntryTranslation } from "@renderer/modules/entry-column/translation"
@ -11,6 +12,9 @@ import type { UniversalItemProps } from "./types"
export function PictureItem({ entryId, entryPreview, translation }: UniversalItemProps) {
const entry = useEntry(entryId) || entryPreview
const asRead = useAsRead(entry)
const previewImage = usePreviewImages()
if (!entry) return <ReactVirtuosoItemPlaceholder />
return (
@ -26,7 +30,7 @@ export function PictureItem({ entryId, entryPreview, translation }: UniversalIte
}}
/>
</div>
<div className="flex-1 px-2 pb-3 pt-1 text-sm">
<div className={cn("relative flex-1 px-2 pb-3 pt-1 text-sm", !asRead && "before:absolute before:-left-1 before:top-[15px] before:block before:size-2 before:rounded-full before:bg-blue-500")}>
<div
className={cn(
"relative mb-0.5 mt-1 truncate font-medium",

View File

@ -1,5 +1,6 @@
import { FeedIcon } from "@renderer/components/feed-icon"
import { Image } from "@renderer/components/ui/image"
import { useAsRead } from "@renderer/hooks"
import dayjs from "@renderer/lib/dayjs"
import { cn } from "@renderer/lib/utils"
import { useEntry } from "@renderer/store/entry/hooks"
@ -11,10 +12,12 @@ import type { UniversalItemProps } from "./types"
export function SocialMediaItem({ entryId, entryPreview, translation }: UniversalItemProps) {
const entry = useEntry(entryId) || entryPreview
const asRead = useAsRead(entry)
// NOTE: prevent 0 height element, react virtuoso will not stop render any more
if (!entry) return <ReactVirtuosoItemPlaceholder />
return (
<div className="flex w-full px-2 py-3">
<div className={cn("relative flex w-full px-2 py-3", !asRead && "before:absolute before:-left-1 before:top-[18px] before:block before:size-2 before:rounded-full before:bg-blue-500")}>
<FeedIcon feed={entry.feeds} entry={entry.entries} />
<div className="min-w-0 flex-1">
<div className="-mt-0.5 line-clamp-5 flex-1 text-sm">

View File

@ -1,5 +1,6 @@
import { FeedIcon } from "@renderer/components/feed-icon"
import { Image } from "@renderer/components/ui/image"
import { useAsRead } from "@renderer/hooks"
import dayjs from "@renderer/lib/dayjs"
import { urlToIframe } from "@renderer/lib/url-to-iframe"
import { cn } from "@renderer/lib/utils"
@ -13,6 +14,8 @@ import type { UniversalItemProps } from "./types"
export function VideoItem({ entryId, entryPreview, translation }: UniversalItemProps) {
const entry = useEntry(entryId) || entryPreview
const asRead = useAsRead(entry)
const iframeSrc = useMemo(() => urlToIframe(entry?.entries.url), [entry?.entries.url])
const ref = useRef<HTMLDivElement>(null)
@ -50,7 +53,7 @@ export function VideoItem({ entryId, entryPreview, translation }: UniversalItemP
/>
)}
</div>
<div className="flex-1 px-2 pb-3 pt-1 text-sm">
<div className={cn("relative flex-1 px-2 pb-3 pt-1 text-sm", !asRead && "before:absolute before:-left-1 before:top-[14px] before:block before:size-2 before:rounded-full before:bg-blue-500")}>
<div className={cn("relative mb-0.5 mt-1 truncate font-medium", !!entry.collections && "pr-4")}>
{translation?.title || entry.entries.title}
{!!entry.collections && (

View File

@ -1,6 +1,6 @@
:root {
--fo-vibrancy-background: theme(colors.native.active);
--fo-vibrancy-foreground: 0, 0%, 50%;
--fo-vibrancy-foreground: 0, 0%, 45%;
--fo-text-primary: 0, 0%, 10%;
/* TODO replace with own color */
@ -17,7 +17,7 @@
}
[data-theme="dark"] {
--fo-vibrancy-foreground: 0, 0%, 63%;
--fo-vibrancy-foreground: 0, 0%, 83%;
--fo-vibrancy-background: theme(colors.native.active);