diff --git a/app/chat/page.tsx b/app/chat/page.tsx
index ea64cb3..d88a9e4 100644
--- a/app/chat/page.tsx
+++ b/app/chat/page.tsx
@@ -128,7 +128,7 @@ export default function ChatPage() {
};
// Handler for Manual/Save button
- const handleManualOrSave = () => {
+ const handleManualOrSave = async () => {
if (hasPendingDraft && pendingNodeDraft) {
// If we have a draft, navigate to edit with it
appActor.send({
@@ -136,22 +136,53 @@ export default function ChatPage() {
draft: pendingNodeDraft,
});
} else {
- // Create an empty draft for manual entry
- const emptyDraft = {
- title: '',
- content: '',
- conversationContext: messages.map((m) => {
- if ('parts' in m && Array.isArray((m as any).parts)) {
- return `${m.role}: ${(m as any).parts.find((p: any) => p.type === 'text')?.text || ''}`;
- }
- return `${m.role}: ${(m as any).content || ''}`;
- }).join('\n'),
- };
+ // Generate a draft from the conversation
+ if (messages.length === 0) {
+ notifications.show({
+ title: 'No conversation',
+ message: 'Start a conversation before creating a node',
+ color: 'red',
+ });
+ return;
+ }
- appActor.send({
- type: 'CREATE_NODE_FROM_CONVERSATION',
- draft: emptyDraft,
- });
+ setIsCreatingNode(true);
+
+ try {
+ const response = await fetch('/api/generate-node-draft', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ credentials: 'include',
+ body: JSON.stringify({ messages }),
+ });
+
+ if (!response.ok) {
+ const errorData = await response.json();
+ throw new Error(errorData.error || 'Failed to generate node draft');
+ }
+
+ const { draft } = await response.json();
+
+ appActor.send({
+ type: 'CREATE_NODE_FROM_CONVERSATION',
+ draft,
+ });
+
+ notifications.show({
+ title: 'Node draft created',
+ message: 'Review and edit your node before publishing',
+ color: 'green',
+ });
+ } catch (error) {
+ console.error('[Create Node] Error:', error);
+ notifications.show({
+ title: 'Error',
+ message: error instanceof Error ? error.message : 'Failed to create node draft',
+ color: 'red',
+ });
+ } finally {
+ setIsCreatingNode(false);
+ }
}
};
@@ -416,6 +447,8 @@ export default function ChatPage() {
variant={hasPendingDraft ? 'filled' : 'light'}
color={hasPendingDraft ? 'blue' : 'gray'}
leftSection={}
+ loading={isCreatingNode}
+ disabled={isCreatingNode}
>
{hasPendingDraft ? 'Save Draft' : 'Save'}
diff --git a/app/layout.tsx b/app/layout.tsx
index 247793b..0a4889b 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -1,5 +1,5 @@
import type { Metadata } from "next";
-import { Inter } from "next/font/google";
+import { Forum } from "next/font/google";
import "./globals.css";
import { MantineProvider, ColorSchemeScript } from "@mantine/core";
import { Notifications } from "@mantine/notifications";
@@ -7,7 +7,12 @@ import "@mantine/notifications/styles.css";
import { theme } from "./theme";
import { AppLayout } from "@/components/AppLayout";
-const inter = Inter({ subsets: ["latin"] });
+// Forum for headings/titles
+const forum = Forum({
+ weight: '400',
+ subsets: ["latin"],
+ variable: '--font-forum',
+});
export const metadata: Metadata = {
title: "Ponderants",
@@ -28,8 +33,12 @@ export default function RootLayout({
{/* Enforce dark scheme as per our theme */}
+ {/* Load Zalando Sans from Google Fonts */}
+
+
+
-
+
{children}
diff --git a/app/theme.ts b/app/theme.ts
index 22d5d2c..76d867a 100644
--- a/app/theme.ts
+++ b/app/theme.ts
@@ -24,7 +24,12 @@ export const theme = createTheme({
},
// Set default dark mode and grayscale for the "minimalist" look
defaultRadius: 'md',
- fontFamily: 'Inter, sans-serif',
+ // Body text font (Zalando Sans from Google Fonts via link tag)
+ fontFamily: '"Zalando Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
+ // Headings font (Forum from Google Fonts via next/font)
+ headings: {
+ fontFamily: 'var(--font-forum), serif',
+ },
// Set default component props for a consistent look
components: {
diff --git a/components/Navigation/DesktopSidebar.tsx b/components/Navigation/DesktopSidebar.tsx
index 80c6402..90ab52e 100644
--- a/components/Navigation/DesktopSidebar.tsx
+++ b/components/Navigation/DesktopSidebar.tsx
@@ -8,7 +8,7 @@
* Highlights the active mode based on app state machine.
*/
-import { Stack, NavLink, Box, Text, Group, Image, Divider } from '@mantine/core';
+import { Stack, NavLink, Box, Title, Group, Divider, Text } from '@mantine/core';
import { IconMessageCircle, IconEdit, IconChartBubbleFilled } from '@tabler/icons-react';
import { useSelector } from '@xstate/react';
import { useAppMachine } from '@/hooks/useAppMachine';
@@ -51,17 +51,17 @@ export function DesktopSidebar() {
}}
>
-
-
-
-
-
+
+
+
Ponderants
-
+
-
-
-
-
-
+
+
+
Ponderants
-
+
);
diff --git a/scripts/apply-schema-prod.js b/scripts/apply-schema-prod.js
index e00a687..be33ea1 100755
--- a/scripts/apply-schema-prod.js
+++ b/scripts/apply-schema-prod.js
@@ -83,14 +83,18 @@ async function applySchema() {
if (result) {
console.log(`[Schema] Executed ${result.length} queries`);
- // Log any errors
- result.forEach((r, i) => {
- if (r.status === 'ERR') {
- console.error(`[Schema] Error in query ${i + 1}:`, r.result);
- } else {
- console.log(`[Schema] ✓ Query ${i + 1} succeeded`);
- }
- });
+ // Log any errors (if results have status property)
+ if (Array.isArray(result)) {
+ result.forEach((r, i) => {
+ if (r && typeof r === 'object') {
+ if (r.status === 'ERR') {
+ console.error(`[Schema] Error in query ${i + 1}:`, r.result);
+ } else if (r.status === 'OK') {
+ console.log(`[Schema] ✓ Query ${i + 1} succeeded`);
+ }
+ }
+ });
+ }
}
console.log('[Schema] ✓ Schema applied successfully!');
diff --git a/todo.md b/todo.md
index 124ca2e..73dd622 100644
--- a/todo.md
+++ b/todo.md
@@ -10,3 +10,5 @@ Upcoming items that should be implemented (time-permitting):
maybe four simple shapes max)
- let's have, in the top-center, something that indicates we're in "Convo" mode
- let's stream the AI output to deepgram for faster synthesis
+- we should link bluesky posts back to ponderants
+- long posts should be broken up into threads