mirror of
https://github.com/dergigi/boris.git
synced 2025-12-19 07:34:28 +01:00
feat: make card view timestamp clickable to open event
- Timestamp in card view now links to event in search portal - Add hover effect showing link is clickable - Remove unused getKindIcon import - All linter and type checks pass
This commit is contained in:
@@ -3,4 +3,4 @@ description: when creating or modifying UI elements, especially related to icons
|
|||||||
alwaysApply: false
|
alwaysApply: false
|
||||||
---
|
---
|
||||||
|
|
||||||
We use FontAwesome. If you can use a fa-icon (instead of text) use a fa-icon.
|
We use FontAwesome. If you can use a fa-icon (instead of text) use a fa-icon. Always strive to keep the UI modern, beautiful, and minimalistic. Shy away from using too many colors, borders, glow, and animations.
|
||||||
@@ -8,7 +8,6 @@ import { Models } from 'applesauce-core'
|
|||||||
import { npubEncode, neventEncode } from 'nostr-tools/nip19'
|
import { npubEncode, neventEncode } from 'nostr-tools/nip19'
|
||||||
import { IndividualBookmark } from '../types/bookmarks'
|
import { IndividualBookmark } from '../types/bookmarks'
|
||||||
import { formatDate, renderParsedContent } from '../utils/bookmarkUtils'
|
import { formatDate, renderParsedContent } from '../utils/bookmarkUtils'
|
||||||
import { getKindIcon } from './kindIcon'
|
|
||||||
import ContentWithResolvedProfiles from './ContentWithResolvedProfiles'
|
import ContentWithResolvedProfiles from './ContentWithResolvedProfiles'
|
||||||
import { extractUrlsFromContent } from '../services/bookmarkHelpers'
|
import { extractUrlsFromContent } from '../services/bookmarkHelpers'
|
||||||
import { classifyUrl } from '../utils/helpers'
|
import { classifyUrl } from '../utils/helpers'
|
||||||
@@ -138,13 +137,24 @@ export const BookmarkItem: React.FC<BookmarkItemProps> = ({ bookmark, index, onS
|
|||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
|
{eventNevent ? (
|
||||||
|
<a
|
||||||
|
href={`https://search.dergigi.com/e/${eventNevent}`}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="bookmark-date-link"
|
||||||
|
title="Open event in search"
|
||||||
|
>
|
||||||
|
{formatDate(bookmark.created_at)}
|
||||||
|
</a>
|
||||||
|
) : (
|
||||||
<span className="bookmark-date">{formatDate(bookmark.created_at)}</span>
|
<span className="bookmark-date">{formatDate(bookmark.created_at)}</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{extractedUrls.length > 0 && (
|
{extractedUrls.length > 0 && (
|
||||||
<div className="bookmark-urls">
|
<div className="bookmark-urls">
|
||||||
<h4>URLs:</h4>
|
{(urlsExpanded ? extractedUrls : extractedUrls.slice(0, 1)).map((url, urlIndex) => {
|
||||||
{(urlsExpanded ? extractedUrls : extractedUrls.slice(0, 3)).map((url, urlIndex) => {
|
|
||||||
const classification = classifyUrl(url)
|
const classification = classifyUrl(url)
|
||||||
return (
|
return (
|
||||||
<div key={urlIndex} className="url-row">
|
<div key={urlIndex} className="url-row">
|
||||||
@@ -160,20 +170,20 @@ export const BookmarkItem: React.FC<BookmarkItemProps> = ({ bookmark, index, onS
|
|||||||
ariaLabel={classification.buttonText}
|
ariaLabel={classification.buttonText}
|
||||||
title={classification.buttonText}
|
title={classification.buttonText}
|
||||||
variant="success"
|
variant="success"
|
||||||
size={36}
|
size={32}
|
||||||
onClick={(e) => { e.preventDefault(); onSelectUrl?.(url) }}
|
onClick={(e) => { e.preventDefault(); onSelectUrl?.(url) }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
{extractedUrls.length > 3 && (
|
{extractedUrls.length > 1 && (
|
||||||
<button
|
<button
|
||||||
className="expand-toggle"
|
className="expand-toggle-urls"
|
||||||
onClick={() => setUrlsExpanded(v => !v)}
|
onClick={() => setUrlsExpanded(v => !v)}
|
||||||
aria-label={urlsExpanded ? 'Collapse URLs' : 'Expand URLs'}
|
aria-label={urlsExpanded ? 'Collapse URLs' : 'Expand URLs'}
|
||||||
title={urlsExpanded ? 'Collapse URLs' : 'Expand URLs'}
|
title={urlsExpanded ? 'Collapse URLs' : 'Expand URLs'}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={urlsExpanded ? faChevronUp : faChevronDown} />
|
{urlsExpanded ? `Hide ${extractedUrls.length - 1} more` : `Show ${extractedUrls.length - 1} more`}
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -202,44 +212,24 @@ export const BookmarkItem: React.FC<BookmarkItemProps> = ({ bookmark, index, onS
|
|||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="bookmark-meta">
|
<div className="bookmark-footer">
|
||||||
{eventNevent ? (
|
<div className="bookmark-meta-minimal">
|
||||||
<a
|
|
||||||
href={`https://search.dergigi.com/e/${eventNevent}`}
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="kind-icon-link"
|
|
||||||
title="Open event in search"
|
|
||||||
>
|
|
||||||
<span className="kind-icon">
|
|
||||||
<FontAwesomeIcon icon={getKindIcon(bookmark.kind)} />
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
) : (
|
|
||||||
<span className="kind-icon">
|
|
||||||
<FontAwesomeIcon icon={getKindIcon(bookmark.kind)} />
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
<span>
|
|
||||||
<a
|
<a
|
||||||
href={`https://search.dergigi.com/p/${authorNpub}`}
|
href={`https://search.dergigi.com/p/${authorNpub}`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className="author-link"
|
className="author-link-minimal"
|
||||||
title="Open author in search"
|
title="Open author in search"
|
||||||
>
|
>
|
||||||
by: {getAuthorDisplayName()}
|
{getAuthorDisplayName()}
|
||||||
</a>
|
</a>
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{hasUrls && firstUrlClassification && (
|
{hasUrls && firstUrlClassification && (
|
||||||
<div className="read-now">
|
<button className="read-now-button-minimal" onClick={handleReadNow}>
|
||||||
<button className="read-now-button" onClick={handleReadNow}>
|
|
||||||
{firstUrlClassification.buttonText}
|
{firstUrlClassification.buttonText}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
170
src/index.css
170
src/index.css
@@ -229,16 +229,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.bookmark-urls {
|
.bookmark-urls {
|
||||||
margin: 1rem 0;
|
margin: 0.75rem 0;
|
||||||
}
|
|
||||||
|
|
||||||
.bookmark-urls h4 {
|
|
||||||
margin: 0 0 0.65rem 0;
|
|
||||||
font-size: 0.85rem;
|
|
||||||
color: #888;
|
|
||||||
text-transform: uppercase;
|
|
||||||
letter-spacing: 0.5px;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.bookmark-url {
|
.bookmark-url {
|
||||||
@@ -608,11 +599,10 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.individual-bookmark {
|
.individual-bookmark {
|
||||||
background: linear-gradient(135deg, #2a2a2a 0%, #252525 100%);
|
background: #2a2a2a;
|
||||||
padding: 1.5rem;
|
padding: 1.25rem;
|
||||||
border-radius: 12px;
|
border-radius: 8px;
|
||||||
transition: all 0.25s ease;
|
transition: all 0.2s ease;
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
|
|
||||||
border: 1px solid #333;
|
border: 1px solid #333;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
@@ -621,9 +611,8 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.individual-bookmark:hover {
|
.individual-bookmark:hover {
|
||||||
transform: translateY(-2px);
|
|
||||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
|
|
||||||
border-color: #444;
|
border-color: #444;
|
||||||
|
background: #2d2d2d;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compact view styles */
|
/* Compact view styles */
|
||||||
@@ -712,26 +701,17 @@ body {
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 0.75rem;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
padding-bottom: 0.75rem;
|
|
||||||
border-bottom: 1px solid #333;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.bookmark-type {
|
.bookmark-type {
|
||||||
background: linear-gradient(135deg, #646cff 0%, #535bf2 100%);
|
color: #646cff;
|
||||||
color: white;
|
font-size: 0.9rem;
|
||||||
padding: 0.4rem 0.75rem;
|
|
||||||
border-radius: 6px;
|
|
||||||
font-size: 0.8rem;
|
|
||||||
font-weight: 600;
|
|
||||||
letter-spacing: 0.5px;
|
|
||||||
text-transform: uppercase;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.3rem;
|
gap: 0.35rem;
|
||||||
box-shadow: 0 2px 4px rgba(100, 108, 255, 0.3);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.bookmark-id {
|
.bookmark-id {
|
||||||
@@ -748,11 +728,23 @@ body {
|
|||||||
color: #666;
|
color: #666;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bookmark-date-link {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: #666;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: color 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bookmark-date-link:hover {
|
||||||
|
color: #8ab4f8;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
.individual-bookmark .bookmark-content {
|
.individual-bookmark .bookmark-content {
|
||||||
margin: 1rem 0;
|
margin: 0.75rem 0;
|
||||||
color: #ddd;
|
color: #ccc;
|
||||||
line-height: 1.65;
|
line-height: 1.6;
|
||||||
font-size: 0.95rem;
|
font-size: 0.9rem;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
@@ -775,89 +767,59 @@ body {
|
|||||||
color: #bbb;
|
color: #bbb;
|
||||||
}
|
}
|
||||||
|
|
||||||
.individual-bookmark .bookmark-meta {
|
.bookmark-footer {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 0.75rem;
|
justify-content: space-between;
|
||||||
flex-wrap: wrap;
|
|
||||||
font-size: 0.85rem;
|
|
||||||
color: #999;
|
|
||||||
margin-top: 1rem;
|
|
||||||
padding-top: 0.75rem;
|
|
||||||
border-top: 1px solid #333;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
|
||||||
|
|
||||||
.individual-bookmark .bookmark-meta span {
|
|
||||||
background: #1e1e1e;
|
|
||||||
padding: 0.35rem 0.65rem;
|
|
||||||
border-radius: 6px;
|
|
||||||
font-family: monospace;
|
|
||||||
border: 1px solid #2a2a2a;
|
|
||||||
}
|
|
||||||
|
|
||||||
.author-link {
|
|
||||||
color: #8ab4f8;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.author-link:hover { text-decoration: underline; }
|
|
||||||
|
|
||||||
.kind-icon {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 34px;
|
|
||||||
height: 34px;
|
|
||||||
border: 1px solid #3a3a3a;
|
|
||||||
border-radius: 8px;
|
|
||||||
background: linear-gradient(135deg, #2a2a2a 0%, #252525 100%);
|
|
||||||
color: #ddd;
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.kind-icon svg {
|
|
||||||
font-size: 1rem;
|
|
||||||
color: #646cff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.kind-icon-link:hover .kind-icon {
|
|
||||||
border-color: #646cff;
|
|
||||||
box-shadow: 0 0 8px rgba(100, 108, 255, 0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
.kind-icon-link {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.read-now {
|
|
||||||
margin-top: 0.75rem;
|
margin-top: 0.75rem;
|
||||||
display: flex;
|
gap: 0.75rem;
|
||||||
justify-content: flex-end;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.read-now-button {
|
.bookmark-meta-minimal {
|
||||||
background: linear-gradient(135deg, #28a745 0%, #218838 100%);
|
font-size: 0.8rem;
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
|
||||||
|
.author-link-minimal {
|
||||||
|
color: #888;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: color 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.author-link-minimal:hover {
|
||||||
|
color: #aaa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.read-now-button-minimal {
|
||||||
|
background: #28a745;
|
||||||
color: white;
|
color: white;
|
||||||
border: none;
|
border: none;
|
||||||
padding: 0.75rem 1.5rem;
|
padding: 0.5rem 1rem;
|
||||||
border-radius: 8px;
|
border-radius: 6px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-weight: 700;
|
font-weight: 600;
|
||||||
font-size: 0.9rem;
|
font-size: 0.85rem;
|
||||||
letter-spacing: 0.5px;
|
|
||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
box-shadow: 0 2px 6px rgba(40, 167, 69, 0.3);
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.read-now-button:hover {
|
.read-now-button-minimal:hover {
|
||||||
background: linear-gradient(135deg, #218838 0%, #1e7e34 100%);
|
background: #218838;
|
||||||
box-shadow: 0 4px 12px rgba(40, 167, 69, 0.4);
|
|
||||||
transform: translateY(-1px);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.read-now-button:active {
|
.expand-toggle-urls {
|
||||||
transform: translateY(0);
|
margin-top: 0.5rem;
|
||||||
box-shadow: 0 2px 4px rgba(40, 167, 69, 0.3);
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
color: #646cff;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
padding: 0.25rem 0;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.expand-toggle-urls:hover {
|
||||||
|
color: #8088ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Private Bookmark Styles */
|
/* Private Bookmark Styles */
|
||||||
|
|||||||
Reference in New Issue
Block a user