diff --git a/apps/rowboat/app/globals.css b/apps/rowboat/app/globals.css
index 15a69aae..8befa83b 100644
--- a/apps/rowboat/app/globals.css
+++ b/apps/rowboat/app/globals.css
@@ -75,6 +75,30 @@ html, body {
body {
@apply bg-background text-foreground;
}
+
+ /* Add these new utility classes */
+ .card-shadow {
+ @apply shadow-sm dark:shadow-none dark:border-border;
+ }
+
+ .hover-effect {
+ @apply hover:bg-accent/10 dark:hover:bg-accent/20 transition-colors;
+ }
+
+ .border-subtle {
+ @apply border-border dark:border-border/50;
+ }
+}
+
+/* Add this to disable color transitions */
+* {
+ -webkit-transition: background-color 0.2s ease-in-out, border-color 0.2s ease-in-out, opacity 0.2s ease-in-out !important;
+ transition: background-color 0.2s ease-in-out, border-color 0.2s ease-in-out, opacity 0.2s ease-in-out !important;
+}
+
+/* Ensure smooth transitions */
+* {
+ @apply transition-colors duration-200;
}
/* Add these styles alongside your other global styles */
@@ -86,6 +110,40 @@ html, body {
z-index: 1000;
}
+/* Base dark mode styles */
+.dark .ql-mention-list-container {
+ background-color: #1f2937;
+ border-color: #374151;
+}
+
+.dark .ql-mention-list-container * {
+ background-color: #1f2937 !important;
+ color: #f9fafb !important;
+}
+
+/* Target individual items */
+.dark .ql-mention-list-item {
+ color: #f9fafb !important;
+ background-color: #1f2937 !important;
+}
+
+/* Target hover and selected states for individual items */
+.dark .ql-mention-list-container .ql-mention-list-item.selected,
+.dark .ql-mention-list-container .ql-mention-list-item:hover {
+ background-color: #6b7280 !important;
+}
+
+/* Ensure the background color only applies to the item itself */
+.dark .ql-mention-list-item > * {
+ background-color: inherit !important;
+}
+
+/* Additional catch-all for any other possible class combinations */
+.dark [class*="mention"].selected,
+.dark [class*="mention"]:hover {
+ background-color: #6b7280 !important;
+}
+
.ql-mention-list {
padding: 0.5rem 0;
}
@@ -108,4 +166,29 @@ html, body {
.ql-editor .mention .invalid {
color: red;
+}
+
+/* Add custom scrollbar styling */
+.dark *::-webkit-scrollbar {
+ width: 8px;
+ height: 8px;
+}
+
+.dark *::-webkit-scrollbar-track {
+ background: #1f2937; /* dark gray background */
+}
+
+.dark *::-webkit-scrollbar-thumb {
+ background: #4b5563; /* medium gray thumb */
+ border-radius: 4px;
+}
+
+.dark *::-webkit-scrollbar-thumb:hover {
+ background: #6b7280; /* lighter gray on hover */
+}
+
+/* For Firefox */
+.dark * {
+ scrollbar-width: thin;
+ scrollbar-color: #4b5563 #1f2937;
}
\ No newline at end of file
diff --git a/apps/rowboat/app/layout.tsx b/apps/rowboat/app/layout.tsx
index 0b66eb1f..1e9933db 100644
--- a/apps/rowboat/app/layout.tsx
+++ b/apps/rowboat/app/layout.tsx
@@ -1,4 +1,5 @@
import "./globals.css";
+import { ThemeProvider } from "./providers/theme-provider";
import { UserProvider } from '@auth0/nextjs-auth0/client';
import { Inter } from "next/font/google";
import { Providers } from "./providers";
@@ -20,11 +21,13 @@ export default function RootLayout({
}>) {
return
-
-
- {children}
-
-
+
+
+
+ {children}
+
+
+
;
}
diff --git a/apps/rowboat/app/lib/components/dropdown.tsx b/apps/rowboat/app/lib/components/dropdown.tsx
new file mode 100644
index 00000000..892eaf3e
--- /dev/null
+++ b/apps/rowboat/app/lib/components/dropdown.tsx
@@ -0,0 +1,37 @@
+import { Select, SelectItem } from "@nextui-org/react";
+import { ReactNode } from "react";
+
+export interface DropdownOption {
+ key: string;
+ label: string;
+}
+
+interface DropdownProps {
+ options: DropdownOption[];
+ value: string;
+ onChange: (value: string) => void;
+ className?: string;
+}
+
+export function Dropdown({
+ options,
+ value,
+ onChange,
+ className = "w-60"
+}: DropdownProps) {
+ return (
+
+ );
+}
diff --git a/apps/rowboat/app/lib/components/editable-field.tsx b/apps/rowboat/app/lib/components/editable-field.tsx
index 5a71545e..69a1c0c9 100644
--- a/apps/rowboat/app/lib/components/editable-field.tsx
+++ b/apps/rowboat/app/lib/components/editable-field.tsx
@@ -6,6 +6,7 @@ import clsx from "clsx";
import { Label } from "./label";
import dynamic from "next/dynamic";
import { Match } from "./mentions_editor";
+import { SparklesIcon } from "lucide-react";
const MentionsEditor = dynamic(() => import('./mentions_editor'), { ssr: false });
interface EditableFieldProps {
@@ -22,7 +23,13 @@ interface EditableFieldProps {
mentions?: boolean;
mentionsAtValues?: Match[];
showSaveButton?: boolean;
+ showDiscardButton?: boolean;
error?: string | null;
+ inline?: boolean;
+ showGenerateButton?: {
+ show: boolean;
+ setShow: (show: boolean) => void;
+ };
}
export function EditableField({
@@ -33,13 +40,16 @@ export function EditableField({
markdown = false,
multiline = false,
locked = false,
- className = "flex flex-col gap-1",
+ className = "flex flex-col gap-1 w-full",
validate,
light = false,
mentions = false,
mentionsAtValues = [],
- showSaveButton = multiline,
+ showSaveButton = false,
+ showDiscardButton = false,
error,
+ inline = false,
+ showGenerateButton,
}: EditableFieldProps) {
const [isEditing, setIsEditing] = useState(false);
const [localValue, setLocalValue] = useState(value);
@@ -70,7 +80,11 @@ export function EditableField({
variant: "bordered" as const,
labelPlacement: "outside" as const,
placeholder: markdown ? '' : placeholder,
- radius: "sm" as const,
+ classNames: {
+ input: "rounded-md",
+ inputWrapper: "rounded-md border-medium"
+ },
+ radius: "md" as const,
isInvalid: !isValid,
errorMessage: validationResult?.errorMessage,
onKeyDown: (e: React.KeyboardEvent) => {
@@ -97,80 +111,147 @@ export function EditableField({
},
};
- return (
-
- {(label || isEditing && showSaveButton) &&
- {label &&
}
- {isEditing && showSaveButton &&
-
-
-
}
-
}
- {isEditing ? <>
- {mentions &&
}
+ if (isEditing) {
+ const hasChanges = localValue !== value;
+
+ return (
+
+ {label && (
+
+
+
+ {showGenerateButton && (
+ }
+ onPress={() => showGenerateButton.setShow(true)}
+ >
+ Generate
+
+ )}
+ {hasChanges && (
+ <>
+ {showDiscardButton && (
+
+ )}
+ {showSaveButton && (
+
+ )}
+ >
+ )}
+
+
+ )}
+ {mentions && (
+
+
+
+ )}
{multiline && !mentions &&
}
- {!multiline &&
}
- > : (
-
!locked && setIsEditing(true)}
- className={clsx("text-sm px-2 py-1 rounded-md", {
- "bg-gray-50": (markdown && !locked) || light,
- "hover:bg-blue-50 cursor-pointer": light && !locked,
- "hover:bg-gray-100 cursor-pointer": !light && !locked,
- "cursor-default": locked,
- })}
- >
- {value ? (<>
+ {!multiline && }
+
+ );
+ }
+
+ return (
+
+ {label && (
+
+
+ {showGenerateButton && (
+ }
+ onPress={() => showGenerateButton.setShow(true)}
+ >
+ Generate
+
+ )}
+
+ )}
+
!locked && setIsEditing(true)}
+ >
+ {value ? (
+ <>
{markdown &&
}
{!markdown &&
}
- >) : (
- <>
- {markdown &&
-
-
}
- {!markdown &&
{placeholder}}
- >
- )}
-
- )}
- {error && (
-
- {error}
-
- )}
+ >
+ ) : (
+ <>
+ {markdown &&
+
+
}
+ {!markdown &&
{placeholder}}
+ >
+ )}
+ {error && (
+
+ {error}
+
+ )}
+
);
}
\ No newline at end of file
diff --git a/apps/rowboat/app/lib/components/form-section.tsx b/apps/rowboat/app/lib/components/form-section.tsx
index d15c7d6d..1c74852e 100644
--- a/apps/rowboat/app/lib/components/form-section.tsx
+++ b/apps/rowboat/app/lib/components/form-section.tsx
@@ -1,18 +1,22 @@
import { Divider } from "@nextui-org/react";
+import { Label } from "./label";
export function FormSection({
+ label,
children,
- className = "",
+ showDivider = false,
}: {
+ label?: string;
children: React.ReactNode;
- className?: string;
+ showDivider?: boolean;
}) {
return (
<>
-
+
+ {label && }
{children}
-
+ {showDivider &&
}
>
);
}
\ No newline at end of file
diff --git a/apps/rowboat/app/lib/components/FormStatusButton.tsx b/apps/rowboat/app/lib/components/form-status-button.tsx
similarity index 100%
rename from apps/rowboat/app/lib/components/FormStatusButton.tsx
rename to apps/rowboat/app/lib/components/form-status-button.tsx
diff --git a/apps/rowboat/app/lib/components/mentions-editor.css b/apps/rowboat/app/lib/components/mentions-editor.css
new file mode 100644
index 00000000..8a4eb524
--- /dev/null
+++ b/apps/rowboat/app/lib/components/mentions-editor.css
@@ -0,0 +1,36 @@
+/* Target both edit mode and view mode mentions */
+.mention,
+.ql-editor p span[class*="bg-[#e"], /* Matches both #e8f2fe and #e0f2fe */
+span[class*="bg-[#e"] { /* For view mode */
+ background-color: #e8f2fe !important;
+ color: #1e40af !important;
+}
+
+/* Dark mode overrides */
+.dark .mention,
+.dark .ql-editor p span[class*="bg-[#e"],
+.dark span[class*="bg-[#e"] {
+ background-color: rgb(31 41 55) !important; /* bg-gray-800 */
+ color: rgb(243 244 246) !important; /* text-gray-100 */
+}
+
+/* Handle Next.js dark mode class if needed */
+:global(.dark) .mention,
+:global(.dark) .ql-editor p span[class*="bg-[#e"],
+:global(.dark) span[class*="bg-[#e"] {
+ background-color: rgb(31 41 55) !important;
+ color: rgb(243 244 246) !important;
+}
+
+/* Override the inline styles */
+.ql-editor p span[class*="bg-[#e0f2fe]"],
+.ql-editor p span[class*="bg-[#e8f2fe]"] {
+ background-color: rgb(31 41 55) !important; /* bg-gray-800 */
+ color: rgb(243 244 246) !important; /* text-gray-100 */
+}
+
+/* Target our custom class */
+.dark .mention-tag {
+ background-color: rgb(31 41 55) !important; /* bg-gray-800 */
+ color: rgb(243 244 246) !important; /* text-gray-100 */
+}
\ No newline at end of file
diff --git a/apps/rowboat/app/lib/components/mentions_editor.tsx b/apps/rowboat/app/lib/components/mentions_editor.tsx
index e36f7354..aded55fd 100644
--- a/apps/rowboat/app/lib/components/mentions_editor.tsx
+++ b/apps/rowboat/app/lib/components/mentions_editor.tsx
@@ -3,6 +3,7 @@ import { useEffect, useRef } from 'react';
import Quill, { Delta, Op } from 'quill';
import { Mention, MentionBlot, MentionBlotData } from "quill-mention";
import "quill/dist/quill.snow.css";
+import "./mentions-editor.css";
import { CopyIcon } from 'lucide-react';
import { CopyButton } from './copy-button';
diff --git a/apps/rowboat/app/lib/components/menu-item.tsx b/apps/rowboat/app/lib/components/menu-item.tsx
new file mode 100644
index 00000000..9e41ab53
--- /dev/null
+++ b/apps/rowboat/app/lib/components/menu-item.tsx
@@ -0,0 +1,31 @@
+import React from 'react';
+import clsx from 'clsx';
+
+interface MenuItemProps {
+ icon: React.ReactNode;
+ children: React.ReactNode;
+ selected: boolean;
+ onClick: () => void;
+}
+
+const MenuItem: React.FC
= ({ icon, children, selected, onClick }) => {
+ return (
+
+ );
+};
+
+export default MenuItem;
\ No newline at end of file
diff --git a/apps/rowboat/app/lib/components/PageSection.tsx b/apps/rowboat/app/lib/components/page-section.tsx
similarity index 100%
rename from apps/rowboat/app/lib/components/PageSection.tsx
rename to apps/rowboat/app/lib/components/page-section.tsx
diff --git a/apps/rowboat/app/lib/components/structured-list.tsx b/apps/rowboat/app/lib/components/structured-list.tsx
new file mode 100644
index 00000000..adb4b962
--- /dev/null
+++ b/apps/rowboat/app/lib/components/structured-list.tsx
@@ -0,0 +1,50 @@
+import clsx from "clsx";
+import { ActionButton } from "./structured-panel";
+
+export function SectionHeader({ title, onAdd }: { title: string; onAdd: () => void }) {
+ return (
+
+
{title}
+
+
+ }
+ onClick={onAdd}
+ >
+ Add
+
+
+ );
+}
+
+export function ListItem({
+ name,
+ isSelected,
+ onClick,
+ disabled,
+ rightElement,
+ selectedRef
+}: {
+ name: string;
+ isSelected: boolean;
+ onClick: () => void;
+ disabled?: boolean;
+ rightElement?: React.ReactNode;
+ selectedRef?: React.RefObject;
+}) {
+ return (
+
+ );
+}
\ No newline at end of file
diff --git a/apps/rowboat/app/lib/components/structured-panel.tsx b/apps/rowboat/app/lib/components/structured-panel.tsx
index 562d8b85..7107a4b4 100644
--- a/apps/rowboat/app/lib/components/structured-panel.tsx
+++ b/apps/rowboat/app/lib/components/structured-panel.tsx
@@ -18,9 +18,9 @@ export function ActionButton({
const onClickProp = onClick ? { onClick } : {};
return