Skip to content

Commit

Permalink
update styles
Browse files Browse the repository at this point in the history
  • Loading branch information
abvthecity committed Nov 8, 2024
1 parent a584e48 commit a53dffd
Show file tree
Hide file tree
Showing 21 changed files with 529 additions and 179 deletions.
4 changes: 4 additions & 0 deletions packages/ui/fern-docs-search-ui/.depcheckrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"ignores": ["autoprefixer", "postcss"],
"ignore-patterns": ["dist"]
}
11 changes: 10 additions & 1 deletion packages/ui/fern-docs-search-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"private": true,
"type": "module",
"scripts": {
"dev": "next dev --turbo",
"dev": "next dev",
"dev:build": "next build",
"dev:start": "next start",
"dev:lint": "next lint"
Expand All @@ -17,7 +17,9 @@
"devDependencies": {
"@types/react": "^18.0.20",
"@types/react-dom": "^18.2.18",
"autoprefixer": "^10.4.16",
"next": "^14",
"postcss": "^8.4.33",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"swr": "^2.2.5",
Expand All @@ -27,18 +29,25 @@
"dependencies": {
"@ai-sdk/anthropic": "^0.0.56",
"@date-fns/tz": "^1.1.2",
"@fern-ui/chatbot": "workspace:*",
"@fern-ui/fern-docs-search-server": "workspace:*",
"@fern-ui/fern-http-method-tag": "workspace:*",
"@radix-ui/react-dialog": "^1.1.1",
"@radix-ui/react-slot": "^1.1.0",
"ai": "^3.4.33",
"algoliasearch": "^5.10.2",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"cmdk": "^1.0.4",
"date-fns": "^2.30.0",
"es-toolkit": "^1.24.0",
"instantsearch.css": "8.5.1",
"instantsearch.js": "4.75.3",
"lucide-react": "^0.378.0",
"react-instantsearch": "7.13.3",
"react-instantsearch-nextjs": "0.3.16",
"server-only": "^0.0.1",
"tailwind-merge": "^2.3.0",
"ts-essentials": "^10.0.1",
"zod": "^3.23.8"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,9 @@ export async function POST(request: Request): Promise<Response> {
const records: string[] = [];

for (const { objectID, ...hit } of allHits.values()) {
records.push(`* ObjectID=\`${objectID}\`, Record=\`${JSON.stringify(toContent(hit))}\``);
records.push(`${objectID}, ${JSON.stringify(toContent(hit))}`);
}

const { object } = await generateObject({
model: smallModel,
system: "You are a reference extractor.",
Expand All @@ -114,6 +115,7 @@ export async function POST(request: Request): Promise<Response> {
${text}
## Records
ObjectID, Record
${records.join("\n")}`,
});

Expand Down
16 changes: 15 additions & 1 deletion packages/ui/fern-docs-search-ui/src/app/client-component.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
"use client";

import { DesktopInstantSearch } from "@/components/desktop/DesktopInstantSearch";
import { Dialog, DialogContent } from "@/components/ui/dialog";
import { useInitialResults } from "@/hooks/useInitialResults";
import { ReactElement } from "react";
import { ChatbotModal } from "@fern-ui/chatbot";
import { ReactElement, useState } from "react";
import useSWR from "swr";

export function DesktopInstantSearchClient({ appId, domain }: { appId: string; domain: string }): ReactElement | false {
const [isChatOpen, setIsChatOpen] = useState(false);

const handleSubmit = (path: string) => {
window.open(`https://${domain}${path}`, "_blank", "noopener,noreferrer");
};
Expand All @@ -20,6 +24,10 @@ export function DesktopInstantSearchClient({ appId, domain }: { appId: string; d

const { initialResults } = useInitialResults(domain);

const chatStream = async (_message: string, _conversationId: string) => {
return [undefined, new AbortController()] as const;
};

if (!apiKey) {
return false;
}
Expand All @@ -39,9 +47,15 @@ export function DesktopInstantSearchClient({ appId, domain }: { appId: string; d
appId={appId}
apiKey={apiKey}
onSubmit={handleSubmit}
onAskAI={() => setIsChatOpen(true)}
// disabled={isLoading || initialResultsLoading || !apiKey}
initialResults={initialResults}
/>
<Dialog open={isChatOpen} onOpenChange={setIsChatOpen}>
<DialogContent>
<ChatbotModal chatStream={chatStream} />
</DialogContent>
</Dialog>
</>
);
}
14 changes: 8 additions & 6 deletions packages/ui/fern-docs-search-ui/src/app/component.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"use client";

import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { useRouter, useSearchParams } from "next/navigation";
import { useState, type ReactElement } from "react";
import { useFormStatus } from "react-dom";
Expand Down Expand Up @@ -31,15 +33,15 @@ export function DesktopInstantSearchWrapper({ appId }: { appId: string }): React
}
}}
>
<input
<Input
name="domain"
className="border rounded-md p-2 dark:bg-black flex-1"
className="border rounded-md p-2 bg-white dark:bg-black flex-1"
placeholder="yourdocs.docs.buildwithfern.com"
defaultValue={selectedDomain}
/>
<button type="submit" className="border rounded-md p-2">
<Button type="submit" className="border rounded-md p-2">
Set Domain
</button>
</Button>
</form>
<form action={() => handleReindex(selectedDomain)}>
<SubmitButton />
Expand All @@ -56,8 +58,8 @@ export function DesktopInstantSearchWrapper({ appId }: { appId: string }): React
function SubmitButton() {
const { pending } = useFormStatus();
return (
<button type="submit" disabled={pending} className="border rounded-md p-2 disabled:opacity-50">
<Button type="submit" disabled={pending} className="border rounded-md p-2 disabled:opacity-50">
Reindex
</button>
</Button>
);
}
88 changes: 75 additions & 13 deletions packages/ui/fern-docs-search-ui/src/app/globals.css
Original file line number Diff line number Diff line change
@@ -1,23 +1,85 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";
@import "@fern-ui/chatbot/src/index.scss";

:root {
--background: #ffffff;
--foreground: #171717;
body {
font-family:
-apple-system,
blinkmacsystemfont,
segoe ui,
roboto,
oxygen,
ubuntu,
cantarell,
open sans,
helvetica neue,
sans-serif;
}

@media (prefers-color-scheme: dark) {
@layer base {
:root {
--background: #0a0a0a;
--foreground: #ededed;
--background: 108 100% 99%;
--foreground: 120 33% 5%;
--card: 108 100% 99%;
--card-foreground: 120 33% 5%;
--popover: 108 100% 99%;
--popover-foreground: 120 33% 5%;
--primary: 127 72% 37%;
--primary-foreground: 0 0% 98%;
--secondary: 108 20% 95%;
--secondary-foreground: 0 0% 9%;
--muted: 108 20% 95%;
--muted-foreground: 0 0% 45.1%;
--accent: 108 20% 95%;
--accent-foreground: 0 0% 9%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 0 0% 98%;
--border: 0 0% 89.8%;
--input: 0 0% 89.8%;
--ring: 127 72% 37%;
--chart-1: 12 76% 61%;
--chart-2: 173 58% 39%;
--chart-3: 197 37% 24%;
--chart-4: 43 74% 66%;
--chart-5: 27 87% 67%;
--radius: 0.5rem;
}
.dark {
--background: 120 33% 5%;
--foreground: 0 0% 98%;
--card: 120 33% 5%;
--card-foreground: 0 0% 98%;
--popover: 120 33% 5%;
--popover-foreground: 0 0% 98%;
--primary: 0 0% 98%;
--primary-foreground: 0 0% 9%;
--secondary: 120 34% 12%;
--secondary-foreground: 0 0% 98%;
--muted: 120 34% 12%;
--muted-foreground: 0 0% 63.9%;
--accent: 120 34% 12%;
--accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 0% 98%;
--border: 120 34% 12%;
--input: 120 34% 12%;
--ring: 0 0% 83.1%;
--chart-1: 220 70% 50%;
--chart-2: 160 60% 45%;
--chart-3: 30 80% 55%;
--chart-4: 280 65% 60%;
--chart-5: 340 75% 55%;
}
}

body {
color: var(--foreground);
background: var(--background);
font-family: Arial, Helvetica, sans-serif;
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
}

@layer components {
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/fern-docs-search-ui/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { DesktopInstantSearchWrapper } from "./component";

export default async function Home(): Promise<ReactElement> {
return (
<div className="grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20 font-[family-name:var(--font-geist-sans)]">
<div className="grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20">
<main className="flex flex-col gap-8 row-start-2 items-center sm:items-start">
<Suspense fallback={<div>Loading...</div>}>
<DesktopInstantSearchWrapper appId={algoliaAppId()} />
Expand Down
27 changes: 27 additions & 0 deletions packages/ui/fern-docs-search-ui/src/components/chat.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"use client";

import { useChat } from "ai/react";
import { ReactElement } from "react";

export default function Chat(): ReactElement {
const { messages, input, handleInputChange, handleSubmit } = useChat();
return (
<div className="flex flex-col w-full max-w-md py-24 mx-auto stretch">
{messages.map((m) => (
<div key={m.id} className="whitespace-pre-wrap">
{m.role === "user" ? "User: " : "AI: "}
{m.content}
</div>
))}

<form onSubmit={handleSubmit}>
<input
className="fixed bottom-0 w-full max-w-md p-2 mb-8 border border-gray-300 rounded shadow-xl"
value={input}
placeholder="Say something..."
onChange={handleInputChange}
/>
</form>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { InitialResultsResponse } from "@/server/browse-results";
import { AlgoliaRecord } from "@fern-ui/fern-docs-search-server/types";
import { Command } from "cmdk";
import { FileText, History, MessageCircle } from "lucide-react";
import { ReactElement, useDeferredValue } from "react";
import { useHits, useSearchBox } from "react-instantsearch";
import { MarkRequired } from "ts-essentials";
import { RegularCalendarIcon } from "../icons/RegularCalendarIcon";
import { RegularFileLinesIcon } from "../icons/RegularFileLinesIcon";
import { RemoteIcon } from "../icons/RemoteIcon";
import { HitContent } from "../shared/HitContent";
import { generateHits } from "../shared/hits";
Expand All @@ -17,10 +16,12 @@ export function DesktopCommand({
initialResults,
placeholder,
onSubmit,
onAskAI,
}: {
initialResults: InitialResultsResponse;
placeholder?: string;
onSubmit: (path: string) => void;
onAskAI?: () => void;
}): ReactElement {
const { query, refine } = useSearchBox();
const { items: rawHits } = useHits<AlgoliaRecord>();
Expand All @@ -43,22 +44,32 @@ export function DesktopCommand({
No results found
</Command.Empty>
<Command.List className="mb-3">
<Command.Group className="mt-3">
<Command.Item value="ai-chat" className="flex gap-2 cursor-default" onSelect={() => onAskAI?.()}>
<MessageCircle className={ICON_CLASS} />
<span>
Ask AI
{query.trimStart().length > 0 && (
<>
<span className="ms-1">&ldquo;</span>
<span className="font-semibold">{query}</span>
<span>&rdquo;</span>
</>
)}
</span>
</Command.Item>
</Command.Group>

{groups.map((group, index) => (
<Command.Group key={group.title ?? index} heading={group.title} className="mt-3">
<Command.Group key={group.title ?? index} heading={group.title ?? "Results"} className="mt-3">
{group.hits.map((hit) => (
<Command.Item
key={hit.path}
value={hit.path}
onSelect={() => onSubmit(hit.path)}
className="flex gap-2 cursor-default"
>
{hit.icon != null ? (
<RemoteIcon icon={hit.icon} className={ICON_CLASS} />
) : hit.record?.type === "changelog" ? (
<RegularCalendarIcon className={ICON_CLASS} />
) : (
<RegularFileLinesIcon className={ICON_CLASS} />
)}
<Icon icon={hit.icon} type={hit.record?.type} />
{hit.record != null && (
<HitContent hit={hit.record as MarkRequired<AlgoliaRecordHit, "type">} />
)}
Expand All @@ -71,3 +82,15 @@ export function DesktopCommand({
</Command>
);
}

function Icon({ icon, type }: { icon: string | undefined; type: string | undefined }): ReactElement {
if (icon) {
return <RemoteIcon icon={icon} className={ICON_CLASS} />;
}

if (type === "changelog") {
return <History className={ICON_CLASS} />;
}

return <FileText className={ICON_CLASS} />;
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ interface DesktopInstantSearchProps {
apiKey: string;
initialResults: InitialResultsResponse;
onSubmit: (path: string) => void;
onAskAI?: () => void;
}

export function DesktopInstantSearch({
appId,
apiKey,
initialResults,
onSubmit,
onAskAI,
}: DesktopInstantSearchProps): ReactElement {
const ref = useRef(algoliasearch(appId, apiKey));

Expand All @@ -38,7 +40,7 @@ export function DesktopInstantSearch({
attributesToSnippet={["description:24", "content:24"]}
ignorePlurals
/>
<DesktopCommand initialResults={initialResults} onSubmit={onSubmit} />
<DesktopCommand initialResults={initialResults} onSubmit={onSubmit} onAskAI={onAskAI} />
</InstantSearchNext>
);
}
Loading

0 comments on commit a53dffd

Please sign in to comment.