+
+ Add RSS URL
diff --git a/components/partials/auth-form.tsx b/components/partials/auth-form.tsx
index 4b091a3..c0b43e0 100644
--- a/components/partials/auth-form.tsx
+++ b/components/partials/auth-form.tsx
@@ -37,7 +37,7 @@ export function AuthForm() {
setIsLoading(true);
},
onSuccess: () => {
- router.push("/");
+ router.push("/settings/summarize");
},
onError: (ctx) => {
toast.error(ctx.error.message);
diff --git a/components/partials/product-description.tsx b/components/partials/product-description.tsx
new file mode 100644
index 0000000..630e2f1
--- /dev/null
+++ b/components/partials/product-description.tsx
@@ -0,0 +1,51 @@
+import { RenderedMarkdown } from "../shared/rendered-markdown";
+
+const DESCRIPTION = `
+rundown crawls your subscribed RSS feeds every 15 minutes, detects new or updated articles, and generates AI-powered summaries.
+You can customize the summary language and length, and receive notifications via Discord Webhook.
+
+[GitHub](https://github.com/howyi/rundown)
+
+---
+
+## Key Features
+
+### RSS Feed Registration & Management
+
+* Register and manage multiple RSS feeds in one place.
+* Simple UI for adding, editing, and deleting feeds.
+
+
+
+### Update Detection + AI Summarization
+
+* Checks feeds every 15 minutes for new articles.
+* Summarizes using **gpt-5-nano** with multi-language and adjustable length options.
+
+
+
+### Timeline View
+
+* Browse summarized articles in chronological order.
+* Easily access past articles.
+
+
+
+### Discord Webhook Notifications
+
+* Get instant updates in your Discord channels.
+* Ideal for teams and communities.
+
+
+
+### MCP Integration
+
+* Access feed and article data programmatically via the MCP server.
+* Connect to \`rundown.sbox.studio/mcp\` using an API key generated from the settings page.
+
+
+`;
+
+export function ProductDescription() {
+ return
{DESCRIPTION};
+}
diff --git a/components/partials/summertize-setting-form.tsx b/components/partials/summertize-setting-form.tsx
index b1ca429..7d3a46a 100644
--- a/components/partials/summertize-setting-form.tsx
+++ b/components/partials/summertize-setting-form.tsx
@@ -10,7 +10,7 @@ import {
DialogTrigger,
} from "@/components/ui/dialog";
import { SummaryLengthOptions } from "@/lib/const";
-import type { Article } from "@/lib/types";
+import type { ArticleWithFeed } from "@/lib/types";
import {
PreviewSummarizeAction,
SaveSummarySettingAction,
@@ -35,7 +35,7 @@ export function SummarizeSettingForm({
language: string;
length: string;
customInstructions: string;
- articles: Article[];
+ articles: ArticleWithFeed[];
}) {
const [saved, setSaved] = useState({
language: initialLanguage,
@@ -156,40 +156,36 @@ export function SummarizeSettingForm({
-
+
Select Preview Article
-
- Select an article from{" "}
-
- the week in react
- {" "}
- RSS
-
+ Select an example article
+
{articles.map((article) => (
-
+
Preview Article:{" "}
+
+
+
+
+ Source
+
+
+
diff --git a/server/queries/list-example-article.ts b/server/queries/list-example-article.ts
index e135d2d..87f3056 100644
--- a/server/queries/list-example-article.ts
+++ b/server/queries/list-example-article.ts
@@ -2,49 +2,59 @@ import { db } from "@/database";
import type { ArticleWithFeed } from "@/lib/types";
import { AddFeed } from "../mutations/add-feed";
-const PREVIEW_RSS = "https://thisweekinreact.com/newsletter/rss.xml";
+const PREVIEW_RSS = [
+ "https://thisweekinreact.com/newsletter/rss.xml",
+ "https://rss.nytimes.com/services/xml/rss/nyt/World.xml",
+ "https://www.reddit.com/r/nextjs.rss",
+];
export async function ListExampleArticle(): Promise {
- let feedRecord = await db.query.feed.findFirst({
- where: (feed, { eq }) => eq(feed.rssUrl, PREVIEW_RSS),
- with: {
- articles: {
- orderBy: (article, { desc }) => desc(article.publishedAt),
- limit: 10,
- },
- },
- });
- if (!feedRecord) {
- await AddFeed({
- url: PREVIEW_RSS,
- });
- feedRecord = await db.query.feed.findFirst({
- where: (feed, { eq }) => eq(feed.rssUrl, PREVIEW_RSS),
+ const respones: ArticleWithFeed[] = [];
+ for (const rssUrl of PREVIEW_RSS) {
+ let feedRecord = await db.query.feed.findFirst({
+ where: (feed, { eq }) => eq(feed.rssUrl, rssUrl),
with: {
articles: {
orderBy: (article, { desc }) => desc(article.publishedAt),
- limit: 10,
+ limit: 2,
},
},
});
- }
+ if (!feedRecord) {
+ await AddFeed({
+ url: rssUrl,
+ });
+ feedRecord = await db.query.feed.findFirst({
+ where: (feed, { eq }) => eq(feed.rssUrl, rssUrl),
+ with: {
+ articles: {
+ orderBy: (article, { desc }) => desc(article.publishedAt),
+ limit: 10,
+ },
+ },
+ });
+ }
- if (!feedRecord || feedRecord.articles.length === 0) {
- return [];
- }
+ if (!feedRecord || feedRecord.articles.length === 0) {
+ return [];
+ }
- return feedRecord.articles.map((article) => ({
- id: article.id,
- title: article.title || "",
- url: article.url || "",
- summary: "",
- publishedAt: article.publishedAt,
- feed: {
- id: feedRecord.id,
- title: feedRecord.title || "",
- url: feedRecord.url || "",
- rssUrl: feedRecord.rssUrl || "",
- description: feedRecord.description || "",
- },
- }));
+ respones.push(
+ ...feedRecord.articles.map((article) => ({
+ id: article.id,
+ title: article.title || "",
+ url: article.url || "",
+ summary: "",
+ publishedAt: article.publishedAt,
+ feed: {
+ id: feedRecord.id,
+ title: feedRecord.title || "",
+ url: feedRecord.url || "",
+ rssUrl: feedRecord.rssUrl || "",
+ description: feedRecord.description || "",
+ },
+ })),
+ );
+ }
+ return respones;
}