The source code of the example can be found here. You can install it here.
Who doesn't like a good morning read on Hacker News with a warm coffee?! In this example, we create a simple list with the top stories on the frontpage.
Load top stories
First, let's get the latest top stories. For this we use a RSS feed:
import { Action, ActionPanel, List, showToast, Toast } from "@raycast/api";
import { useEffect, useState } from "react";
import Parser from "rss-parser";
const parser = new Parser();
interface State {
items?: Parser.Item[];
error?: Error;
}
export default function Command() {
const [state, setState] = useState<State>({});
useEffect(() => {
async function fetchStories() {
try {
const feed = await parser.parseURL("https://hnrss.org/frontpage?description=0&count=25");
setState({ items: feed.items });
} catch (error) {
setState({
error: error instanceof Error ? error : new Error("Something went wrong"),
});
}
}
fetchStories();
}, []);
console.log(state.items); // Prints stories
return <List isLoading={!state.items && !state.error} />;
}
Breaking this down:
We use a third-party dependency to parse the RSS feed and intially the parser.
We define our command state as a TypeScript interface.
We use React's useEffect hook to parse the RSS feed after the command did mount.
We print the top stories to the console.
We render a list and show the loading indicator as long as we load the stories.
Render stories
Now that we got the data from Hacker News, we want to render the stories. For this, we create a new React component and a few helper functions that render a story:
To give the list item a nice look, we use a simple number emoji as icon, add the creator's name as subtitle and the points and comments as accessory title. Now we can render the <StoryListItem>:
When we select a story in the list, we want to be able to open it in the browser and also copy it's link so that we can share it in our watercooler Slack channel. For this, we create a new React Component:
The component takes a story and renders an <ActionPanel> with our required actions. We add the actions to the <StoryListItem>:
function StoryListItem(props: { item: Parser.Item; index: number }) {
// ...
return (
<List.Item
icon={icon}
title={props.item.title ?? "No title"}
subtitle={props.item.creator}
accessories={[{ text: `👍 ${points}` }, { text: `💬 ${comments}` }]}
// Wire up actions
actions={<Actions item={props.item} />}
/>
);
}
Handle errors
Lastly, we want to be a good citizen and handle errors appropriately to guarantee a smooth experience. We'll show a toast whenever our network request fails:
That's it, you have a working extension to read the frontpage of Hacker News. As next steps, you can add another command to show the jobs feed or add an action to copy a Markdown formatted link.