From e2824d9d92c8add4f356da0db2f21ccec2b8fa36 Mon Sep 17 00:00:00 2001 From: Jordan Dalby Date: Thu, 14 Nov 2024 00:07:55 +0000 Subject: [PATCH] General layout improvements, sub menu is now hybrid, edit and delete are easy access and other options moved to the dropdown --- .../common/modals/ConfirmationModal.tsx | 10 +- .../components/snippets/list/SnippetCard.tsx | 30 ++-- .../snippets/list/SnippetCardMenu.tsx | 130 ++++++++++-------- client/src/utils/helpers/dateUtils.ts | 18 --- 4 files changed, 99 insertions(+), 89 deletions(-) delete mode 100644 client/src/utils/helpers/dateUtils.ts diff --git a/client/src/components/common/modals/ConfirmationModal.tsx b/client/src/components/common/modals/ConfirmationModal.tsx index a8457ac..ecde116 100644 --- a/client/src/components/common/modals/ConfirmationModal.tsx +++ b/client/src/components/common/modals/ConfirmationModal.tsx @@ -30,18 +30,18 @@ export const ConfirmationModal: React.FC = ({ return ( -
-

{message}

-
+
+

{message}

+
diff --git a/client/src/components/snippets/list/SnippetCard.tsx b/client/src/components/snippets/list/SnippetCard.tsx index 0d0443c..d65dbec 100644 --- a/client/src/components/snippets/list/SnippetCard.tsx +++ b/client/src/components/snippets/list/SnippetCard.tsx @@ -1,13 +1,13 @@ import React, { useState } from 'react'; import { Clock, Users, FileCode, ChevronLeft, ChevronRight } from 'lucide-react'; -import { dateUtils } from '../../../utils/helpers/dateUtils'; -import { SnippetCardMenu } from './SnippetCardMenu'; +import SnippetCardMenu from './SnippetCardMenu'; import { ConfirmationModal } from '../../common/modals/ConfirmationModal'; import { Snippet } from '../../../types/snippets'; import CategoryList from '../../categories/CategoryList'; import { PreviewCodeBlock } from '../../editor/PreviewCodeBlock'; import Linkify from 'linkify-react'; import { linkifyOptions } from '../../../constants/linkify'; +import { formatDistanceToNow } from 'date-fns'; interface SnippetCardProps { snippet: Snippet; @@ -43,6 +43,16 @@ export const SnippetCard: React.FC = ({ const [currentFragmentIndex, setCurrentFragmentIndex] = useState(0); const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); + const getRelativeUpdateTime = (updatedAt: string): string => { + try { + const updateDate = new Date(updatedAt); + return `Updated ${formatDistanceToNow(updateDate)} ago`; + } catch (error) { + console.error('Error formatting update date:', error); + return 'Unknown update time'; + } + }; + const handleDeleteConfirm = () => { onDelete(snippet.id); setIsDeleteModalOpen(false); @@ -91,7 +101,7 @@ export const SnippetCard: React.FC = ({
- Updated {dateUtils.formatRelativeTime(snippet.updated_at)} + {getRelativeUpdateTime(snippet.updated_at)}
{(snippet.share_count || 0) > 0 && (
@@ -102,12 +112,14 @@ export const SnippetCard: React.FC = ({
- onEdit(snippet)} - onDelete={() => setIsDeleteModalOpen(true)} - onShare={() => onShare(snippet)} - onOpenInNewTab={handleOpenInNewTab} - /> +
+ onEdit(snippet)} + onDelete={() => setIsDeleteModalOpen(true)} + onShare={() => onShare(snippet)} + onOpenInNewTab={handleOpenInNewTab} + /> +
{!compactView && ( diff --git a/client/src/components/snippets/list/SnippetCardMenu.tsx b/client/src/components/snippets/list/SnippetCardMenu.tsx index 352e6a4..37ed7ef 100644 --- a/client/src/components/snippets/list/SnippetCardMenu.tsx +++ b/client/src/components/snippets/list/SnippetCardMenu.tsx @@ -1,7 +1,7 @@ -import React, { useRef, useState } from 'react'; -import { MoreVertical, Share, Pencil, Trash2, ExternalLink } from 'lucide-react'; -import { useOutsideClick } from '../../../hooks/useOutsideClick'; +import React, { useState, useRef } from 'react'; +import { Share, Pencil, Trash2, ExternalLink, MoreVertical } from 'lucide-react'; import { IconButton } from '../../common/buttons/IconButton'; +import { useOutsideClick } from '../../../hooks/useOutsideClick'; interface SnippetCardMenuProps { onEdit: () => void; @@ -10,74 +10,90 @@ interface SnippetCardMenuProps { onOpenInNewTab: () => void; } -export const SnippetCardMenu: React.FC = ({ +const SnippetCardMenu: React.FC = ({ onEdit, onDelete, onShare, onOpenInNewTab }) => { - const [isOpen, setIsOpen] = useState(false); - const menuRef = useRef(null); + const [isDropdownOpen, setIsDropdownOpen] = useState(false); + const dropdownRef = useRef(null); const buttonRef = useRef(null); - useOutsideClick(menuRef, () => setIsOpen(false), [buttonRef]); - - const handleItemClick = (handler: () => void) => { - setIsOpen(false); - handler(); - }; - - const handleMenuToggle = (e: React.MouseEvent) => { - e.stopPropagation(); - setIsOpen(!isOpen); - }; + useOutsideClick(dropdownRef, () => setIsDropdownOpen(false), [buttonRef]); return ( -
e.stopPropagation()}> +
+ {/* Primary Actions - Always Visible */} + } + onClick={(e: React.MouseEvent) => { + e.stopPropagation(); + onEdit(); + }} + variant="custom" + size="sm" + className="bg-gray-700 hover:bg-gray-600" + /> } - onClick={handleMenuToggle} + icon={} + onClick={(e: React.MouseEvent) => { + e.stopPropagation(); + onDelete(); + }} variant="custom" size="sm" - className="opacity-0 group-hover:opacity-100 bg-gray-700 hover:bg-gray-600" + className="bg-gray-700 hover:bg-gray-600" /> - {isOpen && ( -
- - - - -
- )} + + +
+ )} +
); -}; \ No newline at end of file +}; + +export default SnippetCardMenu; \ No newline at end of file diff --git a/client/src/utils/helpers/dateUtils.ts b/client/src/utils/helpers/dateUtils.ts deleted file mode 100644 index 900ce8c..0000000 --- a/client/src/utils/helpers/dateUtils.ts +++ /dev/null @@ -1,18 +0,0 @@ -export const dateUtils = { - formatRelativeTime: (date: string | Date): string => { - const now = new Date(); - const then = new Date(date); - const diffInSeconds = Math.floor((now.getTime() - then.getTime()) / 1000); - - if (diffInSeconds < 60) return 'just now'; - if (diffInSeconds < 3600) return `${Math.floor(diffInSeconds / 60)}m ago`; - if (diffInSeconds < 86400) return `${Math.floor(diffInSeconds / 3600)}h ago`; - if (diffInSeconds < 2592000) return `${Math.floor(diffInSeconds / 86400)}d ago`; - - return then.toLocaleDateString(); - }, - - formatDateTime: (date: string | Date): string => { - return new Date(date).toLocaleString(); - } -}; \ No newline at end of file