mirror of
https://github.com/dergigi/boris.git
synced 2026-01-30 04:04:42 +01:00
feat(bookmarks): classify URLs by type and adjust action buttons
- Add URL classification system (article, video, youtube, image) - Classify based on domain (youtube) and file extensions - Update button text: 'READ NOW' for articles, 'WATCH NOW' for videos, 'VIEW NOW' for images - Update icons: faBookOpen for articles, faPlay for videos, faEye for images - Apply classification to both individual URL buttons and main action button
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import React, { useState } from 'react'
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||
import { faBookmark, faUserLock } from '@fortawesome/free-solid-svg-icons'
|
||||
import { faChevronDown, faChevronUp, faBookOpen } from '@fortawesome/free-solid-svg-icons'
|
||||
import { faChevronDown, faChevronUp, faBookOpen, faPlay, faEye } from '@fortawesome/free-solid-svg-icons'
|
||||
import IconButton from './IconButton'
|
||||
import { useEventModel } from 'applesauce-react/hooks'
|
||||
import { Models } from 'applesauce-core'
|
||||
@@ -11,6 +11,7 @@ import { formatDate, renderParsedContent } from '../utils/bookmarkUtils'
|
||||
import { getKindIcon } from './kindIcon'
|
||||
import ContentWithResolvedProfiles from './ContentWithResolvedProfiles'
|
||||
import { extractUrlsFromContent } from '../services/bookmarkHelpers'
|
||||
import { classifyUrl } from '../utils/helpers'
|
||||
|
||||
interface BookmarkItemProps {
|
||||
bookmark: IndividualBookmark
|
||||
@@ -47,6 +48,19 @@ export const BookmarkItem: React.FC<BookmarkItemProps> = ({ bookmark, index, onS
|
||||
|
||||
// use helper from kindIcon.ts
|
||||
|
||||
const getIconForUrlType = (url: string) => {
|
||||
const classification = classifyUrl(url)
|
||||
switch (classification.type) {
|
||||
case 'youtube':
|
||||
case 'video':
|
||||
return faPlay
|
||||
case 'image':
|
||||
return faEye
|
||||
default:
|
||||
return faBookOpen
|
||||
}
|
||||
}
|
||||
|
||||
const handleReadNow = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
if (!hasUrls) return
|
||||
const firstUrl = extractedUrls[0]
|
||||
@@ -58,6 +72,9 @@ export const BookmarkItem: React.FC<BookmarkItemProps> = ({ bookmark, index, onS
|
||||
}
|
||||
}
|
||||
|
||||
// Get classification for the first URL (for the main button)
|
||||
const firstUrlClassification = hasUrls ? classifyUrl(extractedUrls[0]) : null
|
||||
|
||||
return (
|
||||
<div key={`${bookmark.id}-${index}`} className={`individual-bookmark ${bookmark.isPrivate ? 'private-bookmark' : ''}`}>
|
||||
<div className="bookmark-header">
|
||||
@@ -78,26 +95,29 @@ export const BookmarkItem: React.FC<BookmarkItemProps> = ({ bookmark, index, onS
|
||||
{extractedUrls.length > 0 && (
|
||||
<div className="bookmark-urls">
|
||||
<h4>URLs:</h4>
|
||||
{(urlsExpanded ? extractedUrls : extractedUrls.slice(0, 3)).map((url, urlIndex) => (
|
||||
<div key={urlIndex} className="url-row">
|
||||
<a
|
||||
href={url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="bookmark-url"
|
||||
>
|
||||
{url}
|
||||
</a>
|
||||
<IconButton
|
||||
icon={faBookOpen}
|
||||
ariaLabel="Read now"
|
||||
title="Read now"
|
||||
variant="success"
|
||||
size={36}
|
||||
onClick={(e) => { e.preventDefault(); onSelectUrl?.(url) }}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
{(urlsExpanded ? extractedUrls : extractedUrls.slice(0, 3)).map((url, urlIndex) => {
|
||||
const classification = classifyUrl(url)
|
||||
return (
|
||||
<div key={urlIndex} className="url-row">
|
||||
<a
|
||||
href={url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="bookmark-url"
|
||||
>
|
||||
{url}
|
||||
</a>
|
||||
<IconButton
|
||||
icon={getIconForUrlType(url)}
|
||||
ariaLabel={classification.buttonText}
|
||||
title={classification.buttonText}
|
||||
variant="success"
|
||||
size={36}
|
||||
onClick={(e) => { e.preventDefault(); onSelectUrl?.(url) }}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
{extractedUrls.length > 3 && (
|
||||
<button
|
||||
className="expand-toggle"
|
||||
@@ -165,10 +185,10 @@ export const BookmarkItem: React.FC<BookmarkItemProps> = ({ bookmark, index, onS
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{hasUrls && (
|
||||
{hasUrls && firstUrlClassification && (
|
||||
<div className="read-now">
|
||||
<button className="read-now-button" onClick={handleReadNow}>
|
||||
READ NOW
|
||||
{firstUrlClassification.buttonText}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -10,4 +10,34 @@ export const extractNprofilePubkeys = (content: string): string[] => {
|
||||
return Array.from(unique)
|
||||
}
|
||||
|
||||
export type UrlType = 'video' | 'image' | 'youtube' | 'article'
|
||||
|
||||
export interface UrlClassification {
|
||||
type: UrlType
|
||||
buttonText: string
|
||||
}
|
||||
|
||||
export const classifyUrl = (url: string): UrlClassification => {
|
||||
const urlLower = url.toLowerCase()
|
||||
|
||||
// Check for YouTube
|
||||
if (urlLower.includes('youtube.com') || urlLower.includes('youtu.be')) {
|
||||
return { type: 'youtube', buttonText: 'WATCH NOW' }
|
||||
}
|
||||
|
||||
// Check for video extensions
|
||||
const videoExtensions = ['.mp4', '.webm', '.ogg', '.mov', '.avi', '.mkv', '.m4v']
|
||||
if (videoExtensions.some(ext => urlLower.includes(ext))) {
|
||||
return { type: 'video', buttonText: 'WATCH NOW' }
|
||||
}
|
||||
|
||||
// Check for image extensions
|
||||
const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.svg', '.bmp', '.ico']
|
||||
if (imageExtensions.some(ext => urlLower.includes(ext))) {
|
||||
return { type: 'image', buttonText: 'VIEW NOW' }
|
||||
}
|
||||
|
||||
// Default to article
|
||||
return { type: 'article', buttonText: 'READ NOW' }
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user