Skip to content

Commit 973452e

Browse files
committed
Add beta version of GitHubEvents component that uses Tailwind
Tweak vertical spacing.
1 parent e3b0e45 commit 973452e

File tree

14 files changed

+593
-98
lines changed

14 files changed

+593
-98
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
---
2+
import GitHubEvents from "../components/GitHubEvents/GitHubEvents";
3+
import TagOrnament from "./TagOrnament.astro";
4+
5+
// we'll pass the ID of the section to the GitHubEvents component so that it can
6+
// hide the whole section in case there's an error, rather than leave a broken
7+
// component on the page
8+
const id = "in-the-code";
9+
const showOrnament = false;
10+
---
11+
12+
<section id={id} class="mb-8">
13+
<h2 class="text-primary font-condensed font-semibold uppercase text-7xl mb-8 text-center">In the Code</h2>
14+
<GitHubEvents
15+
org="sfbrigade"
16+
sectionID={id}
17+
client:only="react"
18+
/>
19+
{showOrnament && (
20+
<div class="flex justify-center mt-16">
21+
<TagOrnament />
22+
</div>
23+
)}
24+
</section>

src/pages/beta/components/FooterNav.astro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ const columns = [
5151
<h3 class="text-primary text-lg font-condensed font-bold uppercase mb-2">{cat}</h3>
5252
<ul class="block list-none p-0 m-0">
5353
{links.map(([page, label, iconName]) => (
54-
<li class="pb-1 flex items-center gap-1">
54+
<li class="hover:text-primary pb-1 flex items-center gap-1">
5555
{iconName &&
5656
<Icon name={iconName} class="inline-block min-w-6 text-center align-baseline" />
5757
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { Component, type ErrorInfo, type ReactNode } from "react";
2+
3+
interface ErrorBoundaryProps {
4+
onError?: (error: Error, info: ErrorInfo) => void;
5+
fallback?: ReactNode;
6+
children?: ReactNode;
7+
}
8+
9+
interface ErrorBoundaryState {
10+
hasError: boolean;
11+
}
12+
13+
export default class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
14+
state: ErrorBoundaryState = {
15+
hasError: false
16+
}
17+
18+
static getDerivedStateFromError(_: Error)
19+
{
20+
return { hasError: true };
21+
}
22+
23+
componentDidCatch(
24+
error: Error,
25+
errorInfo: React.ErrorInfo)
26+
{
27+
this.props.onError?.(error, errorInfo);
28+
}
29+
30+
render()
31+
{
32+
if (this.state.hasError) {
33+
return this.props.fallback;
34+
}
35+
36+
return this.props.children;
37+
}
38+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
export const EventProcessors = [
2+
{
3+
type: "PushEvent",
4+
process(
5+
event: any,
6+
repo: string)
7+
{
8+
const { actor, payload, created_at } = event;
9+
10+
return payload.commits.map((commit: any) => ({
11+
id: commit.sha,
12+
repo,
13+
username: actor.display_login,
14+
avatar: actor.avatar_url,
15+
message: commit.message,
16+
// you can get to the html_url value if you call another API, but to
17+
// make things easier, just create that URL manually
18+
link: commit.url
19+
.replace("api.", "")
20+
.replace("/repos", "")
21+
.replace("/commits/", "/commit/"),
22+
timestamp: created_at,
23+
}));
24+
}
25+
},
26+
{
27+
type: "PullRequestEvent",
28+
process(
29+
event: any,
30+
repo: string)
31+
{
32+
const {
33+
id,
34+
actor,
35+
payload: { action, pull_request },
36+
created_at
37+
} = event;
38+
39+
return {
40+
id,
41+
repo,
42+
username: actor.login,
43+
avatar: actor.avatar_url,
44+
message: <><strong>PR {action}:</strong> {pull_request.title}</>,
45+
tooltip: `PR ${action}: ${pull_request.title}`,
46+
link: pull_request.html_url,
47+
timestamp: created_at,
48+
};
49+
}
50+
},
51+
{
52+
type: "IssuesEvent",
53+
process(
54+
event: any,
55+
repo: string)
56+
{
57+
const { id, actor, payload: { action, issue }, created_at } = event;
58+
59+
return {
60+
id,
61+
repo,
62+
username: actor.login,
63+
avatar: actor.avatar_url,
64+
message: <><strong>Issue {action}:</strong> {issue.title}</>,
65+
tooltip: `Issue ${action}: ${issue.title}`,
66+
link: issue.html_url,
67+
timestamp: created_at,
68+
};
69+
}
70+
},
71+
];
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import { intlFormatDistance } from "date-fns/intlFormatDistance";
2+
import type { GitHubEvent } from "./getRecentEvents"; // Updated import path
3+
4+
const MaxTooltipLength = 350;
5+
6+
interface GitHubEventProps {
7+
event: GitHubEvent;
8+
now?: Date;
9+
}
10+
11+
export default function GitHubEventCard({
12+
event,
13+
now = new Date() }: GitHubEventProps)
14+
{
15+
const { repo, link, avatar, username, message, tooltip = message, timestamp } = event;
16+
const messageTooltip = tooltip.length > MaxTooltipLength
17+
? tooltip.slice(0, MaxTooltipLength) + "..."
18+
: tooltip;
19+
20+
// Tailwind classes replacing GitHubEventCard.module.css
21+
// Note: Colors like text-muted, bg-form-element, border-card-border, bg-dropdown-hover need to be defined in your tailwind.config.js
22+
// Assuming default Tailwind colors for now, adjust as needed.
23+
// The width calculation is complex and relies on CSS vars and container queries in the original.
24+
// A fixed width or responsive grid approach might be better in Tailwind.
25+
// Using min-width and aspect ratio from original for now.
26+
return (
27+
<a
28+
href={link}
29+
key={link}
30+
target="_blank"
31+
rel="noopener noreferrer"
32+
className="
33+
w-[calc((100cqw-2*theme(spacing.10)-1px)/3)]
34+
block aspect-square p-4
35+
text-center no-underline text-gray-600 dark:text-gray-400
36+
flex flex-col items-center justify-between flex-shrink-0
37+
bg-gray-100 dark:bg-gray-800
38+
border border-gray-300 dark:border-gray-700
39+
transition-colors duration-300 ease-in-out
40+
hover:bg-gray-200 dark:hover:bg-gray-700 hover:text-gray-600 dark:hover:text-gray-400
41+
snap-start
42+
overflow-hidden break-words
43+
"
44+
>
45+
<header className="flex flex-col items-center">
46+
{/* Adjusted image classes */}
47+
<img
48+
src={avatar}
49+
alt={`${username}'s avatar`}
50+
className="w-14 h-14 aspect-square rounded-full mb-1"
51+
/>
52+
<h3 className="m-0 mb-1 text-base font-semibold">{username}</h3>
53+
</header>
54+
{/* Paragraph with line clamping */}
55+
<p
56+
title={messageTooltip}
57+
className="text-sm leading-[1.2] m-0 overflow-hidden text-ellipsis break-words line-clamp-2 lg:line-clamp-3"
58+
// break-words doesn't actually add word-break: break-word, which is needed to handle the long lines
59+
style={{ wordBreak: "break-word" }}
60+
>
61+
{/* Apply opacity to strong tag if needed, e.g., <strong className="opacity-75"> */}
62+
{message}
63+
</p>
64+
<footer className="text-xs opacity-75">
65+
<h4 className="mt-1 mb-0 font-bold">{repo}</h4>
66+
<time
67+
dateTime={timestamp}
68+
title={new Date(timestamp).toLocaleString()}
69+
>
70+
{intlFormatDistance(timestamp, now)}
71+
</time>
72+
</footer>
73+
</a>
74+
);
75+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { Suspense, useState } from "react";
2+
import GitHubEventsList from "./GitHubEventsList"; // Updated import path
3+
import ErrorBoundary from "./ErrorBoundary"; // Updated import path
4+
import { GitHubIcon } from "./icons"; // Updated import path
5+
import { getRecentEvents } from "./getRecentEvents"; // Updated import path
6+
7+
// Tailwind classes replacing GitHubEvents.module.css .loader
8+
const Loader = () => (
9+
<div className="w-full aspect-[3/1] flex justify-center items-center text-gray-200 dark:text-gray-700">
10+
{/* Pulse animation using Tailwind */}
11+
<div className="h-[40%] animate-pulse">
12+
<GitHubIcon />
13+
</div>
14+
</div>
15+
);
16+
17+
interface GitHubEventsProps {
18+
org: string;
19+
sectionID?: string;
20+
}
21+
22+
export default function GitHubEvents({
23+
org,
24+
sectionID = "" }: GitHubEventsProps)
25+
{
26+
// NOTE: getRecentEvents must be adapted if it uses browser-specific APIs not available during SSR
27+
// For Astro, consider fetching data within an Astro component and passing it as props,
28+
// or using techniques like useEffect for client-side fetching if SSR isn't strictly needed for this data.
29+
// Assuming getRecentEvents works or is adapted.
30+
const [eventsPromise] = useState(() => getRecentEvents(org));
31+
32+
const handleError = () => {
33+
// This relies on DOM manipulation, which might be less ideal in Astro/React.
34+
// Consider passing a callback prop or using state management to hide the section.
35+
const section = sectionID ? document.getElementById(sectionID) : null;
36+
37+
if (section) {
38+
section.style.display = "none";
39+
}
40+
};
41+
42+
return (
43+
<ErrorBoundary onError={handleError}>
44+
<Suspense fallback={<Loader />}>
45+
<GitHubEventsList eventsPromise={eventsPromise} />
46+
</Suspense>
47+
</ErrorBoundary>
48+
);
49+
}

0 commit comments

Comments
 (0)