Skip to content

Commit 15539c6

Browse files
authored
Merge pull request #3652 from dannon/fix-tease-markdown-rendering
[astro] Render tease/summary as markdown and deduplicate utilities
2 parents 3f0cee6 + 37b9d50 commit 15539c6

11 files changed

Lines changed: 109 additions & 96 deletions

File tree

astro/src/components/events/EventsList.vue

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
import { ref, computed, onMounted, watch } from 'vue';
33
import { useStore } from '@nanostores/vue';
44
import { currentSubsite, type SubsiteId } from '@/stores/subsiteStore';
5+
import { renderMarkdownInline } from '@/utils/markdown';
6+
import { formatDateRange } from '@/utils/dateUtils';
57
import ExternalIcon from '../common/ExternalIcon.vue';
68
79
interface EventData {
@@ -185,24 +187,6 @@ watch(selectedPastYear, (year) => {
185187
updateUrl(year);
186188
});
187189
188-
function formatDate(date: string | undefined): string {
189-
if (!date) return '';
190-
return new Date(date).toLocaleDateString('en-US', {
191-
year: 'numeric',
192-
month: 'short',
193-
day: 'numeric',
194-
});
195-
}
196-
197-
function formatDateRange(start: string | undefined, end?: string): string {
198-
if (!start) return '';
199-
const startDate = new Date(start);
200-
if (!end) return formatDate(start);
201-
const endDate = new Date(end);
202-
if (startDate.getTime() === endDate.getTime()) return formatDate(start);
203-
return `${formatDate(start)} - ${formatDate(end)}`;
204-
}
205-
206190
function getLocationText(location: EventData['location']): string {
207191
if (!location) return '';
208192
if (typeof location === 'string') return location;
@@ -246,7 +230,7 @@ function buildUrl(slug: string): string {
246230
{{ event.title || 'Untitled Event' }}
247231
<ExternalIcon v-if="event.externalUrl" :href="event.externalUrl" />
248232
</h3>
249-
<p v-if="event.tease" class="text-gray-600 mt-1">{{ event.tease }}</p>
233+
<p v-if="event.tease" class="text-gray-600 mt-1" v-html="renderMarkdownInline(event.tease)"></p>
250234
<p v-if="event.location" class="text-sm text-gray-500 mt-2 flex items-center gap-1">
251235
<svg
252236
xmlns="http://www.w3.org/2000/svg"

astro/src/components/layout/PageHeader.astro

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
* Supports optional article metadata (date, authors, tags)
66
*/
77
8+
import { formatDate } from '../../utils/dateUtils';
9+
810
interface Props {
911
title: string;
1012
description?: string;
@@ -46,21 +48,13 @@ function toDate(d: Date | string | undefined): Date | null {
4648
return d instanceof Date ? d : new Date(d);
4749
}
4850
49-
// Format date for display
50-
function formatDate(d: Date | string | undefined): string {
51-
const dateObj = toDate(d);
52-
if (!dateObj) return '';
53-
return dateObj.toLocaleDateString('en-US', {
54-
year: 'numeric',
55-
month: 'long',
56-
day: 'numeric',
57-
});
58-
}
59-
6051
function toISOString(d: Date | string | undefined): string {
6152
const dateObj = toDate(d);
6253
return dateObj ? dateObj.toISOString() : '';
6354
}
55+
56+
// Use long format (full month names) for standalone page headers
57+
const formattedDate = formatDate(date, false);
6458
---
6559

6660
<header class="page-header">
@@ -77,7 +71,7 @@ function toISOString(d: Date | string | undefined): string {
7771
<div class="flex flex-wrap items-center gap-4 text-sm text-white/70 mt-4">
7872
{date && (
7973
<time datetime={toISOString(date)} class="font-medium">
80-
{formatDate(date)}
74+
{formattedDate}
8175
</time>
8276
)}
8377
{normalizedAuthors.length > 0 && (

astro/src/components/news/NewsList.vue

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
import { ref, computed, onMounted, watch } from 'vue';
33
import { useStore } from '@nanostores/vue';
44
import { currentSubsite, type SubsiteId } from '@/stores/subsiteStore';
5+
import { renderMarkdownInline } from '@/utils/markdown';
6+
import { formatDate } from '@/utils/dateUtils';
57
import ExternalIcon from '../common/ExternalIcon.vue';
68
79
interface NewsArticle {
@@ -140,17 +142,6 @@ function loadMore() {
140142
displayCount.value += pageSize;
141143
}
142144
143-
function formatDate(dateStr: string | undefined): string {
144-
if (!dateStr) return '';
145-
const date = new Date(dateStr);
146-
if (isNaN(date.getTime())) return '';
147-
return date.toLocaleDateString('en-US', {
148-
year: 'numeric',
149-
month: 'short',
150-
day: 'numeric',
151-
});
152-
}
153-
154145
function buildUrl(slug: string): string {
155146
return `/${slug}/`;
156147
}
@@ -233,9 +224,7 @@ function buildUrl(slug: string): string {
233224
<time v-if="article.date" class="text-sm text-gray-500 mb-2 block">
234225
{{ formatDate(article.date) }}
235226
</time>
236-
<p v-if="article.tease" class="text-gray-600">
237-
{{ article.tease }}
238-
</p>
227+
<p v-if="article.tease" class="text-gray-600" v-html="renderMarkdownInline(article.tease)"></p>
239228
<div v-if="article.tags?.length" class="flex flex-wrap gap-2 mt-3">
240229
<span
241230
v-for="tag in article.tags.slice(0, 5)"

astro/src/components/platforms/PlatformDirectory.vue

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
<script setup lang="ts">
22
import { ref, computed } from 'vue';
3-
import { marked } from 'marked';
43
import { Input } from '@/components/ui/input';
54
import { Button } from '@/components/ui/button';
65
import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card';
6+
import { renderMarkdownInline } from '@/utils/markdown';
77
88
interface Platform {
99
slug: string;
@@ -102,8 +102,6 @@ function getHostname(url: string): string {
102102
return url;
103103
}
104104
}
105-
106-
const renderSummary = (summary?: string): string => (summary ? marked.parseInline(summary) : '');
107105
</script>
108106

109107
<template>
@@ -176,7 +174,7 @@ const renderSummary = (summary?: string): string => (summary ? marked.parseInlin
176174
<p
177175
v-if="platform.summary"
178176
class="text-sm text-gray-600 line-clamp-3 mb-3 prose prose-sm max-w-none"
179-
v-html="renderSummary(platform.summary)"
177+
v-html="renderMarkdownInline(platform.summary)"
180178
></p>
181179
<div class="flex items-center justify-between text-xs text-gray-500">
182180
<span v-if="platform.url" class="truncate max-w-[60%]">

astro/src/components/search/SearchPage.vue

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<script setup lang="ts">
22
import { ref, computed, onMounted, watch } from 'vue';
33
import { Input } from '@/components/ui/input';
4+
import { formatDate } from '@/utils/dateUtils';
45
import ExternalIcon from '../common/ExternalIcon.vue';
56
67
interface SearchEntry {
@@ -87,17 +88,6 @@ const results = computed(() => {
8788
.slice(0, 100);
8889
});
8990
90-
function formatDate(dateStr: string): string {
91-
if (!dateStr) return '';
92-
const date = new Date(dateStr);
93-
if (isNaN(date.getTime())) return '';
94-
return date.toLocaleDateString('en-US', {
95-
year: 'numeric',
96-
month: 'short',
97-
day: 'numeric',
98-
});
99-
}
100-
10191
function getCollectionLabel(collection: string): string {
10292
const labels: Record<string, string> = {
10393
articles: 'Article',

astro/src/layouts/PlatformLayout.astro

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
* Displays platform info, instances table, and various metadata sections
66
*/
77
import BaseLayout from './BaseLayout.astro';
8-
import { marked } from 'marked';
98
import Icon from '../components/ui/Icon.astro';
9+
import { renderMarkdownInline } from '../utils/markdown';
1010
1111
interface PlatformInstance {
1212
platform_group?: string;
@@ -71,8 +71,6 @@ const scopeNames: Record<string, string> = {
7171
'tool-publishing': 'Tool Publishing',
7272
};
7373
74-
const renderMarkdown = (value?: string): string => (value ? marked.parseInline(value) : '');
75-
7674
// Sections to render
7775
const sections = [
7876
{ key: 'comments', name: 'Comments', items: comments },
@@ -201,7 +199,7 @@ const sections = [
201199
<th class="px-4 py-3 text-left text-sm font-medium text-gray-900 w-40 align-top">Summary:</th>
202200
<td
203201
class="px-4 py-3 text-sm text-gray-700 prose prose-sm max-w-none"
204-
set:html={renderMarkdown(summary)}
202+
set:html={renderMarkdownInline(summary)}
205203
/>
206204
</tr>
207205
)}
@@ -223,7 +221,7 @@ const sections = [
223221
<h2 class="text-xl font-semibold text-gray-900 mb-3 capitalize">{section.name}</h2>
224222
<ul class="list-disc list-inside space-y-1 text-gray-700">
225223
{section.items.map((item: string) => (
226-
<li class="prose prose-sm max-w-none" set:html={renderMarkdown(item)} />
224+
<li class="prose prose-sm max-w-none" set:html={renderMarkdownInline(item)} />
227225
))}
228226
{section.key === 'citations' && pub_libraries && pub_libraries.length > 0 && (
229227
<>

astro/src/pages/bare/fr/latest/events.astro

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,20 +34,21 @@ const upcomingEvents = allEvents
3434
})
3535
.slice(0, 5);
3636
37-
function formatDate(date: Date | string | undefined): string {
37+
// Compact date format without year for embedded feed display
38+
function formatCompactDate(date: Date | string | undefined): string {
3839
if (!date) return '';
3940
const d = typeof date === 'string' ? new Date(date) : date;
4041
return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
4142
}
4243
43-
function formatDateRange(start: Date | string | undefined, end: Date | string | undefined): string {
44+
function formatCompactDateRange(start: Date | string | undefined, end: Date | string | undefined): string {
4445
if (!start) return '';
45-
const startStr = formatDate(start);
46+
const startStr = formatCompactDate(start);
4647
if (!end) return startStr;
4748
const startD = typeof start === 'string' ? new Date(start) : start;
4849
const endD = typeof end === 'string' ? new Date(end) : end;
4950
if (startD.toDateString() === endD.toDateString()) return startStr;
50-
return `${startStr} - ${formatDate(end)}`;
51+
return `${startStr} - ${formatCompactDate(end)}`;
5152
}
5253
---
5354

@@ -136,7 +137,7 @@ function formatDateRange(start: Date | string | undefined, end: Date | string |
136137
<a href={`https://galaxyproject.org/events/${slug}/`} target="_blank">
137138
{event.data.title}
138139
</a>
139-
<span class="event-date">{formatDateRange(event.data.date, event.data.date_end)}</span>
140+
<span class="event-date">{formatCompactDateRange(event.data.date, event.data.date_end)}</span>
140141
{locationStr && <span class="event-location"> · {locationStr}</span>}
141142
</div>
142143
);

astro/src/pages/bare/fr/latest/news.astro

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ const newsArticles = allArticles
2727
})
2828
.slice(0, 5);
2929
30-
function formatDate(date: Date | string | undefined): string {
30+
// Format date without year for compact display
31+
function formatCompactDate(date: Date | string | undefined): string {
3132
if (!date) return '';
3233
const d = typeof date === 'string' ? new Date(date) : date;
3334
return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
@@ -111,7 +112,7 @@ function formatDate(date: Date | string | undefined): string {
111112
<a href={`https://galaxyproject.org/news/${slug}/`} target="_blank">
112113
{article.data.title}
113114
</a>
114-
<span class="news-date">{formatDate(article.data.date)}</span>
115+
<span class="news-date">{formatCompactDate(article.data.date)}</span>
115116
</div>
116117
);
117118
})

astro/src/utils/content.ts

Lines changed: 7 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*/
55

66
import { getCollection, type CollectionEntry } from 'astro:content';
7-
import { isPublishedDate } from './dateUtils';
7+
import { isPublishedDate, formatDate as formatDateUtil, formatDateRange as formatDateRangeUtil } from './dateUtils';
88

99
type ArticleEntry = CollectionEntry<'articles'>;
1010
type EventEntry = CollectionEntry<'events'>;
@@ -253,35 +253,18 @@ export async function getEventBySlug(slug: string): Promise<EventEntry | undefin
253253

254254
/**
255255
* Format a date for display
256+
* Re-exported from dateUtils for backward compatibility
257+
* Uses long format (full month names) by default for content pages
256258
*/
257259
export function formatDate(date: Date | string | undefined): string {
258-
if (!date) return '';
259-
const d = typeof date === 'string' ? new Date(date) : date;
260-
return d.toLocaleDateString('en-US', {
261-
year: 'numeric',
262-
month: 'long',
263-
day: 'numeric',
264-
});
260+
return formatDateUtil(date, false);
265261
}
266262

267263
/**
268264
* Format a date range for events
265+
* Re-exported from dateUtils for backward compatibility
266+
* Uses long format (full month names) by default for content pages
269267
*/
270268
export function formatDateRange(start: Date | string | undefined, end: Date | string | undefined): string {
271-
if (!start) return '';
272-
273-
const startDate = typeof start === 'string' ? new Date(start) : start;
274-
const endDate = end ? (typeof end === 'string' ? new Date(end) : end) : null;
275-
276-
if (!endDate || startDate.getTime() === endDate.getTime()) {
277-
return formatDate(startDate);
278-
}
279-
280-
// Same month
281-
if (startDate.getMonth() === endDate.getMonth() && startDate.getFullYear() === endDate.getFullYear()) {
282-
return `${startDate.toLocaleDateString('en-US', { month: 'long', day: 'numeric' })} - ${endDate.getDate()}, ${endDate.getFullYear()}`;
283-
}
284-
285-
// Different months
286-
return `${formatDate(startDate)} - ${formatDate(endDate)}`;
269+
return formatDateRangeUtil(start, end, false);
287270
}

astro/src/utils/dateUtils.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,64 @@ export function isPublishedDate(date: Date | string | undefined, now: Date = new
1212
const d = date instanceof Date ? date : new Date(date);
1313
return d <= now;
1414
}
15+
16+
/**
17+
* Convert a date value to a Date object
18+
*/
19+
function toDate(d: Date | string | undefined): Date | null {
20+
if (!d) return null;
21+
return d instanceof Date ? d : new Date(d);
22+
}
23+
24+
/**
25+
* Format a date for display
26+
* @param date - Date to format
27+
* @param short - If true, use short month names (Jan, Feb). Default true for lists.
28+
* @returns Formatted date string like "Jan 15, 2024" or "January 15, 2024"
29+
*/
30+
export function formatDate(date: Date | string | undefined, short: boolean = true): string {
31+
const d = toDate(date);
32+
if (!d || isNaN(d.getTime())) return '';
33+
return d.toLocaleDateString('en-US', {
34+
year: 'numeric',
35+
month: short ? 'short' : 'long',
36+
day: 'numeric',
37+
});
38+
}
39+
40+
/**
41+
* Format a date range for events
42+
* @param start - Start date
43+
* @param end - End date (optional)
44+
* @param short - If true, use short month names. Default true for lists.
45+
* @returns Formatted date range like "Jan 15 - 17, 2024" or "Jan 15 - Feb 2, 2024"
46+
*/
47+
export function formatDateRange(
48+
start: Date | string | undefined,
49+
end?: Date | string | undefined,
50+
short: boolean = true
51+
): string {
52+
if (!start) return '';
53+
54+
const startDate = toDate(start);
55+
const endDate = toDate(end);
56+
57+
if (!startDate || isNaN(startDate.getTime())) return '';
58+
59+
// No end date or same as start
60+
if (!endDate || startDate.getTime() === endDate.getTime()) {
61+
return formatDate(startDate, short);
62+
}
63+
64+
// Same month and year - show "Jan 15 - 17, 2024"
65+
if (startDate.getMonth() === endDate.getMonth() && startDate.getFullYear() === endDate.getFullYear()) {
66+
const monthDay = startDate.toLocaleDateString('en-US', {
67+
month: short ? 'short' : 'long',
68+
day: 'numeric',
69+
});
70+
return `${monthDay} - ${endDate.getDate()}, ${endDate.getFullYear()}`;
71+
}
72+
73+
// Different months - show full dates
74+
return `${formatDate(startDate, short)} - ${formatDate(endDate, short)}`;
75+
}

0 commit comments

Comments
 (0)