aboutsummaryrefslogtreecommitdiff
path: root/apps/web/components/new/document-cards
diff options
context:
space:
mode:
Diffstat (limited to 'apps/web/components/new/document-cards')
-rw-r--r--apps/web/components/new/document-cards/file-preview.tsx102
-rw-r--r--apps/web/components/new/document-cards/google-docs-preview.tsx51
-rw-r--r--apps/web/components/new/document-cards/note-preview.tsx130
-rw-r--r--apps/web/components/new/document-cards/website-preview.tsx33
4 files changed, 43 insertions, 273 deletions
diff --git a/apps/web/components/new/document-cards/file-preview.tsx b/apps/web/components/new/document-cards/file-preview.tsx
index 93e53463..f30645dc 100644
--- a/apps/web/components/new/document-cards/file-preview.tsx
+++ b/apps/web/components/new/document-cards/file-preview.tsx
@@ -5,71 +5,12 @@ import type { DocumentsWithMemoriesResponseSchema } from "@repo/validation/api"
import type { z } from "zod"
import { dmSansClassName } from "@/lib/fonts"
import { cn } from "@lib/utils"
-import { PDF } from "@ui/assets/icons"
-import { FileText, Image, Video } from "lucide-react"
+import { DocumentIcon } from "@/components/new/document-icon"
type DocumentsResponse = z.infer<typeof DocumentsWithMemoriesResponseSchema>
type DocumentWithMemories = DocumentsResponse["documents"][0]
-function PDFIcon() {
- return (
- <svg
- width="8"
- height="10"
- viewBox="0 0 8 10"
- fill="none"
- xmlns="http://www.w3.org/2000/svg"
- >
- <title>PDF Icon</title>
- <g filter="url(#filter0_i_719_6586)">
- <path
- d="M1 10C0.725 10 0.489583 9.90208 0.29375 9.70625C0.0979167 9.51042 0 9.275 0 9V1C0 0.725 0.0979167 0.489583 0.29375 0.29375C0.489583 0.0979167 0.725 0 1 0H5L8 3V9C8 9.275 7.90208 9.51042 7.70625 9.70625C7.51042 9.90208 7.275 10 7 10H1ZM4.5 3.5V1H1V9H7V3.5H4.5Z"
- fill="#FF7673"
- />
- </g>
- <defs>
- <filter
- id="filter0_i_719_6586"
- x="0"
- y="0"
- width="8.25216"
- height="10.2522"
- filterUnits="userSpaceOnUse"
- color-interpolation-filters="sRGB"
- >
- <feFlood flood-opacity="0" result="BackgroundImageFix" />
- <feBlend
- mode="normal"
- in="SourceGraphic"
- in2="BackgroundImageFix"
- result="shape"
- />
- <feColorMatrix
- in="SourceAlpha"
- type="matrix"
- values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
- result="hardAlpha"
- />
- <feOffset dx="0.252163" dy="0.252163" />
- <feGaussianBlur stdDeviation="0.504325" />
- <feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1" />
- <feColorMatrix
- type="matrix"
- values="0 0 0 0 0.0431373 0 0 0 0 0.0588235 0 0 0 0 0.0823529 0 0 0 0.4 0"
- />
- <feBlend
- mode="normal"
- in2="shape"
- result="effect1_innerShadow_719_6586"
- />
- </filter>
- </defs>
- </svg>
- )
-}
-
function getFileTypeInfo(document: DocumentWithMemories): {
- icon: React.ReactNode
extension: string
color?: string
} {
@@ -78,56 +19,33 @@ function getFileTypeInfo(document: DocumentWithMemories): {
if (mimeType) {
if (mimeType === "application/pdf") {
- return {
- icon: <PDFIcon />,
- extension: ".pdf",
- color: "#FF7673",
- }
+ return { extension: ".pdf", color: "#FF7673" }
}
if (mimeType.startsWith("image/")) {
const ext = mimeType.split("/")[1] || "jpg"
- return {
- icon: <Image className="w-4 h-4" style={{ color: "#FAFAFA" }} />,
- extension: `.${ext}`,
- }
+ return { extension: `.${ext}` }
}
if (mimeType.startsWith("video/")) {
const ext = mimeType.split("/")[1] || "mp4"
- return {
- icon: <Video className="w-4 h-4" style={{ color: "#FAFAFA" }} />,
- extension: `.${ext}`,
- }
+ return { extension: `.${ext}` }
}
}
switch (type) {
case "pdf":
- return {
- icon: <PDF className="w-4 h-4 text-[#FF7673]" />,
- extension: ".pdf",
- color: "#FF7673",
- }
+ return { extension: ".pdf", color: "#FF7673" }
case "image":
- return {
- icon: <Image className="w-4 h-4" style={{ color: "#FAFAFA" }} />,
- extension: ".jpg",
- }
+ return { extension: ".jpg" }
case "video":
- return {
- icon: <Video className="w-4 h-4" style={{ color: "#FAFAFA" }} />,
- extension: ".mp4",
- }
+ return { extension: ".mp4" }
default:
- return {
- icon: <FileText className="w-4 h-4" style={{ color: "#FAFAFA" }} />,
- extension: ".file",
- }
+ return { extension: ".file" }
}
}
export function FilePreview({ document }: { document: DocumentWithMemories }) {
const [imageError, setImageError] = useState(false)
- const { icon, extension, color } = getFileTypeInfo(document)
+ const { extension, color } = getFileTypeInfo(document)
const type = document.type?.toLowerCase()
const mimeType = document.metadata?.mimeType as string | undefined
@@ -168,7 +86,7 @@ export function FilePreview({ document }: { document: DocumentWithMemories }) {
) : (
<div className="p-3">
<div className="flex items-center gap-1 mb-2">
- {icon}
+ <DocumentIcon type={document.type} url={document.url} className="w-4 h-4" />
<p
className={cn(dmSansClassName(), "text-[10px] font-semibold")}
style={{ color: color }}
diff --git a/apps/web/components/new/document-cards/google-docs-preview.tsx b/apps/web/components/new/document-cards/google-docs-preview.tsx
index 6c783c7d..50a56a16 100644
--- a/apps/web/components/new/document-cards/google-docs-preview.tsx
+++ b/apps/web/components/new/document-cards/google-docs-preview.tsx
@@ -4,6 +4,10 @@ import type { DocumentsWithMemoriesResponseSchema } from "@repo/validation/api"
import type { z } from "zod"
import { dmSansClassName } from "@/lib/fonts"
import { cn } from "@lib/utils"
+import {
+ DocumentIcon,
+ getDocumentTypeLabel,
+} from "@/components/new/document-icon"
type DocumentsResponse = z.infer<typeof DocumentsWithMemoriesResponseSchema>
type DocumentWithMemories = DocumentsResponse["documents"][0]
@@ -13,49 +17,28 @@ export function GoogleDocsPreview({
}: {
document: DocumentWithMemories
}) {
+ const label = getDocumentTypeLabel(document.type)
+
return (
<div className="bg-[#0B1017] p-3 rounded-[18px] gap-3">
<div className="flex items-center gap-2 mb-2">
- <svg
- className="w-4 h-4"
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 87.3 78"
- aria-label="Google Docs"
- >
- <title>Google Docs</title>
- <path
- fill="#0066da"
- d="m6.6 66.85 3.85 6.65c.8 1.4 1.95 2.5 3.3 3.3L27.5 53H0c0 1.55.4 3.1 1.2 4.5z"
- />
- <path
- fill="#00ac47"
- d="M43.65 25 29.9 1.2c-1.35.8-2.5 1.9-3.3 3.3l-25.4 44A9.06 9.06 0 0 0 0 53h27.5z"
- />
- <path
- fill="#ea4335"
- d="M73.55 76.8c1.35-.8 2.5-1.9 3.3-3.3l1.6-2.75L86.1 57.5c.8-1.4 1.2-2.95 1.2-4.5H59.798l5.852 11.5z"
- />
- <path
- fill="#00832d"
- d="M43.65 25 57.4 1.2C56.05.4 54.5 0 52.9 0H34.4c-1.6 0-3.15.45-4.5 1.2z"
- />
- <path
- fill="#2684fc"
- d="M59.8 53H27.5L13.75 76.8c1.35.8 2.9 1.2 4.5 1.2h50.8c1.6 0 3.15-.45 4.5-1.2z"
- />
- <path
- fill="#ffba00"
- d="m73.4 26.5-12.7-22c-.8-1.4-1.95-2.5-3.3-3.3L43.65 25 59.8 53h27.45c0-1.55-.4-3.1-1.2-4.5z"
- />
- </svg>
+ <DocumentIcon type={document.type} url={document.url} className="w-4 h-4" />
<p className={cn(dmSansClassName(), "text-[12px] font-semibold")}>
- Google Docs
+ {label}
</p>
</div>
- {document.content && (
+ {document.summary ? (
+ <p className="text-[10px] text-[#737373] line-clamp-4">
+ {document.summary}
+ </p>
+ ) : document.content ? (
<p className="text-[10px] text-[#737373] line-clamp-4">
{document.content}
</p>
+ ) : (
+ <p className="text-[10px] text-[#737373] line-clamp-4">
+ No summary available
+ </p>
)}
</div>
)
diff --git a/apps/web/components/new/document-cards/note-preview.tsx b/apps/web/components/new/document-cards/note-preview.tsx
index c2b767b0..3e684a88 100644
--- a/apps/web/components/new/document-cards/note-preview.tsx
+++ b/apps/web/components/new/document-cards/note-preview.tsx
@@ -4,138 +4,16 @@ import type { DocumentsWithMemoriesResponseSchema } from "@repo/validation/api"
import type { z } from "zod"
import { dmSansClassName } from "@/lib/fonts"
import { cn } from "@lib/utils"
-import { useMemo } from "react"
+import { DocumentIcon } from "@/components/new/document-icon"
type DocumentsResponse = z.infer<typeof DocumentsWithMemoriesResponseSchema>
type DocumentWithMemories = DocumentsResponse["documents"][0]
-type TipTapNode = {
- type: string
- text?: string
- content?: TipTapNode[]
- attrs?: Record<string, unknown>
-}
-
-function extractTextFromTipTapContent(content: string): string {
- try {
- const json = JSON.parse(content) as TipTapNode
- return extractTextFromNode(json)
- } catch {
- return content
- }
-}
-
-function extractTextFromNode(node: TipTapNode): string {
- if (node.type === "text" && node.text) {
- return node.text
- }
-
- if (!node.content) {
- return ""
- }
-
- const texts: string[] = []
- for (const child of node.content) {
- const text = extractTextFromNode(child)
- if (text) {
- texts.push(text)
- }
- }
-
- const blockTypes = [
- "paragraph",
- "heading",
- "listItem",
- "blockquote",
- "codeBlock",
- ]
- if (blockTypes.includes(node.type)) {
- return `${texts.join("")}\n`
- }
-
- return texts.join("")
-}
-
-function NoteIcon() {
- return (
- <svg
- width="14"
- height="14"
- viewBox="0 0 14 14"
- fill="none"
- xmlns="http://www.w3.org/2000/svg"
- >
- <title>Note Icon</title>
- <mask
- id="mask0_344_4970"
- style={{ maskType: "alpha" }}
- maskUnits="userSpaceOnUse"
- x="0"
- y="0"
- width="14"
- height="14"
- >
- <rect width="14" height="14" fill="#D9D9D9" />
- </mask>
- <g mask="url(#mask0_344_4970)">
- <g filter="url(#filter0_i_344_4970)">
- <path
- d="M3.50002 8.75008H7.58335L8.75002 7.58341H3.50002V8.75008ZM3.50002 6.41675H7.00002V5.25008H3.50002V6.41675ZM2.33335 4.08341V9.91675H6.41669L5.25002 11.0834H1.16669V2.91675H12.8334V4.66675H11.6667V4.08341H2.33335ZM13.3584 7.17508C13.407 7.22369 13.4313 7.27716 13.4313 7.3355C13.4313 7.39383 13.407 7.4473 13.3584 7.49591L12.8334 8.02091L11.8125 7.00008L12.3375 6.47508C12.3861 6.42647 12.4396 6.40216 12.4979 6.40216C12.5563 6.40216 12.6097 6.42647 12.6584 6.47508L13.3584 7.17508ZM7.58335 12.2501V11.2292L11.4625 7.35008L12.4834 8.37091L8.60419 12.2501H7.58335Z"
- fill="#FAFAFA"
- />
- </g>
- </g>
- <defs>
- <filter
- id="filter0_i_344_4970"
- x="1.16669"
- y="2.91675"
- width="12.6176"
- height="9.68628"
- filterUnits="userSpaceOnUse"
- colorInterpolationFilters="sRGB"
- >
- <feFlood floodOpacity="0" result="BackgroundImageFix" />
- <feBlend
- mode="normal"
- in="SourceGraphic"
- in2="BackgroundImageFix"
- result="shape"
- />
- <feColorMatrix
- in="SourceAlpha"
- type="matrix"
- values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
- result="hardAlpha"
- />
- <feOffset dx="0.353028" dy="0.353028" />
- <feGaussianBlur stdDeviation="0.706055" />
- <feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1" />
- <feColorMatrix
- type="matrix"
- values="0 0 0 0 0.0431373 0 0 0 0 0.0588235 0 0 0 0 0.0823529 0 0 0 0.4 0"
- />
- <feBlend
- mode="normal"
- in2="shape"
- result="effect1_innerShadow_344_4970"
- />
- </filter>
- </defs>
- </svg>
- )
-}
-
export function NotePreview({ document }: { document: DocumentWithMemories }) {
- const previewText = useMemo(() => {
- if (!document.content) return ""
- return extractTextFromTipTapContent(document.content).trim()
- }, [document.content])
-
return (
<div className="bg-[#0B1017] p-3 rounded-[18px] space-y-2">
<div className="flex items-center gap-1">
- <NoteIcon />
+ <DocumentIcon type="note" className="w-4 h-4" />
<p className={cn(dmSansClassName(), "text-[12px] font-semibold")}>
Note
</p>
@@ -151,9 +29,9 @@ export function NotePreview({ document }: { document: DocumentWithMemories }) {
{document.title}
</p>
)}
- {previewText && (
+ {document.summary && (
<p className="text-[10px] text-[#737373] line-clamp-4">
- {previewText}
+ {document.summary}
</p>
)}
</div>
diff --git a/apps/web/components/new/document-cards/website-preview.tsx b/apps/web/components/new/document-cards/website-preview.tsx
index ab3c5ad3..21ae9de2 100644
--- a/apps/web/components/new/document-cards/website-preview.tsx
+++ b/apps/web/components/new/document-cards/website-preview.tsx
@@ -3,50 +3,41 @@
import { useState } from "react"
import type { DocumentsWithMemoriesResponseSchema } from "@repo/validation/api"
import type { z } from "zod"
-import { dmSansClassName } from "@/lib/fonts"
-import { cn } from "@lib/utils"
type DocumentsResponse = z.infer<typeof DocumentsWithMemoriesResponseSchema>
type DocumentWithMemories = DocumentsResponse["documents"][0]
+type OgData = {
+ title?: string
+ image?: string
+}
+
export function WebsitePreview({
document,
+ ogData,
}: {
document: DocumentWithMemories
+ ogData?: OgData | null
}) {
const [imageError, setImageError] = useState(false)
+
const ogImage = (document as DocumentWithMemories & { ogImage?: string })
.ogImage
+ const displayOgImage = ogImage || ogData?.image
return (
<div className="bg-[#0B1017] rounded-[18px] overflow-hidden">
- {ogImage && !imageError ? (
+ {displayOgImage && !imageError ? (
<div className="relative w-full aspect-video bg-gray-100 overflow-hidden">
<img
- src={ogImage}
+ src={displayOgImage}
alt={document.title || "Website preview"}
className="w-full h-full object-cover"
onError={() => setImageError(true)}
loading="lazy"
/>
</div>
- ) : (
- <div className="p-3 gap-2">
- <p
- className={cn(
- dmSansClassName(),
- "text-[12px] font-semibold text-[#E5E5E5] line-clamp-2 mb-1",
- )}
- >
- {document.title || "Untitled Document"}
- </p>
- {document.content && (
- <p className="text-[10px] text-[#737373] line-clamp-3">
- {document.content}
- </p>
- )}
- </div>
- )}
+ ) : null}
</div>
)
}