diff --git a/components/LinkViews/LinkComponents/LinkDate.tsx b/components/LinkViews/LinkComponents/LinkDate.tsx index e512dcb..7bed676 100644 --- a/components/LinkViews/LinkComponents/LinkDate.tsx +++ b/components/LinkViews/LinkComponents/LinkDate.tsx @@ -6,14 +6,13 @@ export default function LinkDate({ }: { link: LinkIncludingShortenedCollectionAndTags; }) { - const formattedDate = new Date(link.createdAt as string).toLocaleString( - "en-US", - { - year: "numeric", - month: "short", - day: "numeric", - } - ); + const formattedDate = new Date( + (link.importDate || link.createdAt) as string + ).toLocaleString("en-US", { + year: "numeric", + month: "short", + day: "numeric", + }); return (
diff --git a/components/ReadableView.tsx b/components/ReadableView.tsx index f8eb3b6..9c7ce17 100644 --- a/components/ReadableView.tsx +++ b/components/ReadableView.tsx @@ -34,6 +34,8 @@ export default function ReadableView({ link }: Props) { const [imageError, setImageError] = useState(false); const [colorPalette, setColorPalette] = useState(); + const [date, setDate] = useState(); + const colorThief = new ColorThief(); const router = useRouter(); @@ -54,6 +56,8 @@ export default function ReadableView({ link }: Props) { }; fetchLinkContent(); + + setDate(link.importDate || link.createdAt); }, [link]); useEffect(() => { @@ -211,8 +215,8 @@ export default function ReadableView({ link }: Props) {

- {link?.createdAt - ? new Date(link?.createdAt).toLocaleString("en-US", { + {date + ? new Date(date).toLocaleString("en-US", { year: "numeric", month: "long", day: "numeric", diff --git a/lib/api/controllers/migration/importFromHTMLFile.ts b/lib/api/controllers/migration/importFromHTMLFile.ts index 4398600..21fb3c4 100644 --- a/lib/api/controllers/migration/importFromHTMLFile.ts +++ b/lib/api/controllers/migration/importFromHTMLFile.ts @@ -2,6 +2,7 @@ import { prisma } from "@/lib/api/db"; import createFolder from "@/lib/api/storage/createFolder"; import { JSDOM } from "jsdom"; import { parse, Node, Element, TextNode } from "himalaya"; +import { writeFileSync } from "fs"; const MAX_LINKS_PER_USER = Number(process.env.MAX_LINKS_PER_USER) || 30000; @@ -36,7 +37,9 @@ export default async function importFromHTMLFile( const jsonData = parse(document.documentElement.outerHTML); - for (const item of jsonData) { + const processedArray = processNodes(jsonData); + + for (const item of processedArray) { console.log(item); await processBookmarks(userId, item as Element); } @@ -74,7 +77,9 @@ async function processBookmarks( } else if (item.type === "element" && item.tagName === "a") { // process link - const linkUrl = item?.attributes.find((e) => e.key === "href")?.value; + const linkUrl = item?.attributes.find( + (e) => e.key.toLowerCase() === "href" + )?.value; const linkName = ( item?.children.find((e) => e.type === "text") as TextNode )?.content; @@ -82,14 +87,33 @@ async function processBookmarks( .find((e) => e.key === "tags") ?.value.split(","); + // set date if available + const linkDateValue = item?.attributes.find( + (e) => e.key.toLowerCase() === "add_date" + )?.value; + + const linkDate = linkDateValue + ? new Date(Number(linkDateValue) * 1000) + : undefined; + + let linkDesc = + ( + ( + item?.children?.find( + (e) => e.type === "element" && e.tagName === "dd" + ) as Element + )?.children[0] as TextNode + )?.content || ""; + if (linkUrl && parentCollectionId) { await createLink( userId, linkUrl, parentCollectionId, linkName, - "", - linkTags + linkDesc, + linkTags, + linkDate ); } else if (linkUrl) { // create a collection named "Imported Bookmarks" and add the link to it @@ -100,8 +124,9 @@ async function processBookmarks( linkUrl, collectionId, linkName, - "", - linkTags + linkDesc, + linkTags, + linkDate ); } @@ -160,7 +185,8 @@ const createLink = async ( collectionId: number, name?: string, description?: string, - tags?: string[] + tags?: string[], + importDate?: Date ) => { await prisma.link.create({ data: { @@ -193,6 +219,48 @@ const createLink = async ( }), } : undefined, + importDate: importDate || undefined, }, }); }; + +function processNodes(nodes: Node[]) { + const findAndProcessDL = (node: Node) => { + if (node.type === "element" && node.tagName === "dl") { + processDLChildren(node); + } else if ( + node.type === "element" && + node.children && + node.children.length + ) { + node.children.forEach((child) => findAndProcessDL(child)); + } + }; + + const processDLChildren = (dlNode: Element) => { + dlNode.children.forEach((child, i) => { + if (child.type === "element" && child.tagName === "dt") { + const nextSibling = dlNode.children[i + 1]; + if ( + nextSibling && + nextSibling.type === "element" && + nextSibling.tagName === "dd" + ) { + const aElement = child.children.find( + (el) => el.type === "element" && el.tagName === "a" + ); + if (aElement && aElement.type === "element") { + // Add the 'dd' element as a child of the 'a' element + aElement.children.push(nextSibling); + // Remove the 'dd' from the parent 'dl' to avoid duplicate processing + dlNode.children.splice(i + 1, 1); + // Adjust the loop counter due to the removal + } + } + } + }); + }; + + nodes.forEach(findAndProcessDL); + return nodes; +} diff --git a/prisma/migrations/20240327070238_add_import_date_field_for_links/migration.sql b/prisma/migrations/20240327070238_add_import_date_field_for_links/migration.sql new file mode 100644 index 0000000..7ebb1fe --- /dev/null +++ b/prisma/migrations/20240327070238_add_import_date_field_for_links/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Link" ADD COLUMN "importDate" TIMESTAMP(3); diff --git a/prisma/schema.prisma b/prisma/schema.prisma index da73115..26d6dc9 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -128,6 +128,7 @@ model Link { pdf String? readable String? lastPreserved DateTime? + importDate DateTime? createdAt DateTime @default(now()) updatedAt DateTime @default(now()) @updatedAt }