Skip to content

Commit 5e7717d

Browse files
densumeshskeptrunedev
authored andcommitted
feature: add markdown table rendering ability
1 parent 7fc6c45 commit 5e7717d

File tree

6 files changed

+421
-7
lines changed

6 files changed

+421
-7
lines changed

clients/search-component/example/src/routeTree.gen.ts

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { createFileRoute } from "@tanstack/react-router";
1515
import { Route as rootRoute } from "./routes/__root";
1616
import { Route as SearchpageImport } from "./routes/searchpage";
1717
import { Route as RecsImport } from "./routes/recs";
18+
import { Route as InlineImport } from "./routes/inline";
1819
import { Route as EcommerceImport } from "./routes/ecommerce";
1920

2021
// Create Virtual Routes
@@ -35,6 +36,12 @@ const RecsRoute = RecsImport.update({
3536
getParentRoute: () => rootRoute,
3637
} as any);
3738

39+
const InlineRoute = InlineImport.update({
40+
id: "/inline",
41+
path: "/inline",
42+
getParentRoute: () => rootRoute,
43+
} as any);
44+
3845
const EcommerceRoute = EcommerceImport.update({
3946
id: "/ecommerce",
4047
path: "/ecommerce",
@@ -65,6 +72,13 @@ declare module "@tanstack/react-router" {
6572
preLoaderRoute: typeof EcommerceImport;
6673
parentRoute: typeof rootRoute;
6774
};
75+
"/inline": {
76+
id: "/inline";
77+
path: "/inline";
78+
fullPath: "/inline";
79+
preLoaderRoute: typeof InlineImport;
80+
parentRoute: typeof rootRoute;
81+
};
6882
"/recs": {
6983
id: "/recs";
7084
path: "/recs";
@@ -87,13 +101,15 @@ declare module "@tanstack/react-router" {
87101
export interface FileRoutesByFullPath {
88102
"/": typeof IndexLazyRoute;
89103
"/ecommerce": typeof EcommerceRoute;
104+
"/inline": typeof InlineRoute;
90105
"/recs": typeof RecsRoute;
91106
"/searchpage": typeof SearchpageRoute;
92107
}
93108

94109
export interface FileRoutesByTo {
95110
"/": typeof IndexLazyRoute;
96111
"/ecommerce": typeof EcommerceRoute;
112+
"/inline": typeof InlineRoute;
97113
"/recs": typeof RecsRoute;
98114
"/searchpage": typeof SearchpageRoute;
99115
}
@@ -102,29 +118,32 @@ export interface FileRoutesById {
102118
__root__: typeof rootRoute;
103119
"/": typeof IndexLazyRoute;
104120
"/ecommerce": typeof EcommerceRoute;
121+
"/inline": typeof InlineRoute;
105122
"/recs": typeof RecsRoute;
106123
"/searchpage": typeof SearchpageRoute;
107124
}
108125

109126
export interface FileRouteTypes {
110127
fileRoutesByFullPath: FileRoutesByFullPath;
111-
fullPaths: "/" | "/ecommerce" | "/recs" | "/searchpage";
128+
fullPaths: "/" | "/ecommerce" | "/inline" | "/recs" | "/searchpage";
112129
fileRoutesByTo: FileRoutesByTo;
113-
to: "/" | "/ecommerce" | "/recs" | "/searchpage";
114-
id: "__root__" | "/" | "/ecommerce" | "/recs" | "/searchpage";
130+
to: "/" | "/ecommerce" | "/inline" | "/recs" | "/searchpage";
131+
id: "__root__" | "/" | "/ecommerce" | "/inline" | "/recs" | "/searchpage";
115132
fileRoutesById: FileRoutesById;
116133
}
117134

118135
export interface RootRouteChildren {
119136
IndexLazyRoute: typeof IndexLazyRoute;
120137
EcommerceRoute: typeof EcommerceRoute;
138+
InlineRoute: typeof InlineRoute;
121139
RecsRoute: typeof RecsRoute;
122140
SearchpageRoute: typeof SearchpageRoute;
123141
}
124142

125143
const rootRouteChildren: RootRouteChildren = {
126144
IndexLazyRoute: IndexLazyRoute,
127145
EcommerceRoute: EcommerceRoute,
146+
InlineRoute: InlineRoute,
128147
RecsRoute: RecsRoute,
129148
SearchpageRoute: SearchpageRoute,
130149
};
@@ -141,6 +160,7 @@ export const routeTree = rootRoute
141160
"children": [
142161
"/",
143162
"/ecommerce",
163+
"/inline",
144164
"/recs",
145165
"/searchpage"
146166
]
@@ -151,6 +171,9 @@ export const routeTree = rootRoute
151171
"/ecommerce": {
152172
"filePath": "ecommerce.tsx"
153173
},
174+
"/inline": {
175+
"filePath": "inline.tsx"
176+
},
154177
"/recs": {
155178
"filePath": "recs.tsx"
156179
},
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
/* eslint-disable @typescript-eslint/no-explicit-any */
2+
import { TrieveModalSearch } from "../../../src/index";
3+
import "../../../dist/index.css";
4+
import { useState } from "react";
5+
import { createFileRoute } from "@tanstack/react-router";
6+
7+
export const Route = createFileRoute("/inline")({
8+
component: Inline,
9+
});
10+
11+
export default function Inline() {
12+
const baseUrl = import.meta.env.VITE_API_BASE_URL;
13+
const datasetId = import.meta.env.VITE_DATASET_ID;
14+
const apiKey = import.meta.env.VITE_API_KEY;
15+
const brandName = import.meta.env.VITE_BRAND_NAME;
16+
const brandLogoSrcUrl = import.meta.env.VITE_BRAND_LOGO_SRC_URL;
17+
const brandColor = import.meta.env.VITE_ACCENT_COLOR;
18+
const problemLink = import.meta.env.VITE_PROBLEM_LINK;
19+
const useGroupSearch = import.meta.env.VITE_USE_GROUP_SEARCH == "true";
20+
const showFloatingButton = import.meta.env.VITE_SHOW_FLOATING_BTN == "true";
21+
const floatingButtonPosition = import.meta.env.VITE_FLOATING_BTN_POSITION;
22+
const floatingSearchIconPosition = import.meta.env
23+
.VITE_FLOATING_SEARCH_ICON_POSITION;
24+
const showFloatingInput = import.meta.env.VITE_SHOW_FLOATING_INPUT == "true";
25+
const usePagefind = import.meta.env.VITE_USE_PAGEFIND == "true";
26+
const defaultSearchQueries: string[] = (
27+
import.meta.env.VITE_DEFAULT_SEARCH_QUERIES ?? ""
28+
).split(",");
29+
const defaultTags: any[] = JSON.parse(
30+
import.meta.env.VITE_DEFAULT_TAGS ?? "[]",
31+
);
32+
const defaultSearchMode =
33+
import.meta.env.VITE_DEFAULT_SEARCH_MODE ?? "search";
34+
const defaultAIQuestions = (
35+
import.meta.env.VITE_DEFAULT_AI_QUESTIONS ?? ""
36+
).split(",");
37+
const showResultHighlights =
38+
import.meta.env.VITE_SHOW_RESULT_HIGHLIGHTS == "true";
39+
const inlineCarousel = import.meta.env.VITE_INLINE_CAROUSEL == "true";
40+
41+
//VITE_TOPIC_ID
42+
const topicId = import.meta.env.VITE_TOPIC_ID;
43+
44+
const [theme, setTheme] = useState<"light" | "dark">("light");
45+
const [component, setComponent] = useState(0);
46+
47+
return (
48+
<>
49+
<div
50+
className={`p-12 flex flex-col items-center justify-center w-screen h-screen relative ${theme === "dark" ? "bg-zinc-900 text-zinc-50" : ""
51+
}`}
52+
>
53+
<div className="absolute top-6 right-6">
54+
<ul>
55+
<li key="theme">
56+
<button
57+
onClick={() => setTheme(theme === "light" ? "dark" : "light")}
58+
>
59+
{theme === "light" ? (
60+
<span>
61+
<i className="fa-regular fa-sun"></i>
62+
</span>
63+
) : (
64+
<span>
65+
<i className="fa-regular fa-moon"></i>
66+
</span>
67+
)}
68+
</button>
69+
</li>
70+
</ul>
71+
</div>
72+
{component === 0 ? (
73+
<>
74+
<h2 className="font-bold text-center py-8">
75+
Search Modal Component{" "}
76+
</h2>
77+
78+
<TrieveModalSearch
79+
type="ecommerce"
80+
defaultSearchMode={defaultSearchMode}
81+
apiKey={apiKey}
82+
baseUrl={baseUrl}
83+
datasetId={datasetId}
84+
problemLink={problemLink}
85+
theme={theme}
86+
brandLogoImgSrcUrl={brandLogoSrcUrl}
87+
brandName={brandName}
88+
brandColor={brandColor}
89+
allowSwitchingModes={true}
90+
useGroupSearch={useGroupSearch}
91+
responsive={false}
92+
currencyPosition="before"
93+
searchOptions={{
94+
use_autocomplete: false,
95+
search_type: "fulltext",
96+
}}
97+
inline={true}
98+
buttonTriggers={[
99+
{
100+
selector: ".random-trigger-location",
101+
mode: "chat",
102+
},
103+
]}
104+
usePagefind={usePagefind}
105+
cssRelease="none"
106+
defaultSearchQueries={defaultSearchQueries}
107+
defaultAiQuestions={defaultAIQuestions}
108+
tags={defaultTags}
109+
floatingButtonPosition={floatingButtonPosition}
110+
showFloatingButton={showFloatingButton}
111+
debounceMs={10}
112+
floatingSearchIconPosition={floatingSearchIconPosition}
113+
inlineCarousel={inlineCarousel}
114+
showFloatingInput={showFloatingInput}
115+
showResultHighlights={showResultHighlights}
116+
previewTopicId={topicId}
117+
recommendOptions={{
118+
queriesToTriggerRecommendations: [
119+
"What if this is out of stock?",
120+
],
121+
productId: "42002562449585",
122+
filter: {
123+
must: [
124+
{
125+
field: "tag_set",
126+
match_all: ["skiing_boots"],
127+
},
128+
],
129+
},
130+
}}
131+
/>
132+
</>
133+
) : (
134+
<>
135+
<h2 className="tv-font-bold tv-text-center tv-py-8">
136+
Search Results Component
137+
</h2>
138+
<h2 className="tv-font-bold tv-text-center tv-py-8">
139+
This was removed, see
140+
https://github.com/devflowinc/trieve/pull/2613
141+
</h2>
142+
</>
143+
)}
144+
145+
<ul className="tv-absolute tv-top-1/2 -tv-translate-y-1/2 tv-w-full">
146+
{component > 0 ? (
147+
<li className="tv-left-6 tv-absolute">
148+
<button onClick={() => setComponent(0)}>
149+
<i className="fa-solid fa-chevron-left"></i>
150+
</button>
151+
</li>
152+
) : (
153+
<li className="tv-right-6 tv-absolute">
154+
<button onClick={() => setComponent(1)}>
155+
<i className="fa-solid fa-chevron-right"></i>
156+
</button>
157+
</li>
158+
)}
159+
</ul>
160+
</div>
161+
</>
162+
);
163+
}

clients/search-component/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,12 @@
8383
"react-pdf-spotlight": "0.0.16",
8484
"react-scan": "^0.3.2",
8585
"react-snap-carousel": "^0.5.0",
86+
"remark-gfm": "^4.0.1",
8687
"tailwind-merge": "^3.0.2",
87-
"trieve-ts-sdk": "^0.0.92"
88+
"trieve-ts-sdk": "^0.0.93"
8889
},
8990
"peerDependencies": {
9091
"react": "^18.3.1 || ^19.0.0-rc",
9192
"react-dom": "^18.3.1 || ^19.0.0-rc"
9293
}
93-
}
94+
}

clients/search-component/src/TrieveModal/Chat/ResponseMessage.tsx

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import React, { lazy, useEffect } from "react";
1+
import React, { lazy, Suspense, useEffect } from "react";
22
const Markdown = lazy(() => import("react-markdown"));
3+
import remarkGfm from "remark-gfm";
34

45
import { useChatState } from "../../utils/hooks/chat-context";
56
import { useModalState } from "../../utils/hooks/modal-context";
@@ -75,7 +76,17 @@ export const ResponseMessage = ({
7576
</p>
7677
</span>
7778
)}
78-
<Message key={idx} message={message} idx={idx} />
79+
<Suspense
80+
fallback={
81+
<div
82+
className={`system ${props.type === "ecommerce" ? "ecommerce" : ""}`}
83+
>
84+
<LoadingIcon className="loading" />
85+
</div>
86+
}
87+
>
88+
<Message key={`msg-${idx}`} message={message} idx={idx} />
89+
</Suspense>
7990
</div>
8091
</motion.div>
8192
);
@@ -412,6 +423,7 @@ export const Message = ({
412423
);
413424
},
414425
}}
426+
remarkPlugins={[remarkGfm]}
415427
key={idx}
416428
>
417429
{message.text.length > 0

clients/search-component/src/TrieveModal/index.css

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,41 @@ body {
457457
hr {
458458
@apply tv-mb-4;
459459
}
460+
461+
table {
462+
width: 100%;
463+
border-collapse: collapse;
464+
margin-top: 1em;
465+
margin-bottom: 1em;
466+
border: 1px solid #ddd;
467+
font-size: 0.9em;
468+
469+
th,
470+
td {
471+
border: 1px solid #ddd;
472+
padding: 8px 12px;
473+
text-align: left;
474+
vertical-align: top;
475+
}
476+
477+
th {
478+
background-color: #f2f2f2;
479+
font-weight: bold;
480+
white-space: nowrap;
481+
}
482+
483+
tr {
484+
border-bottom: 1px solid #ddd;
485+
}
486+
487+
tr:nth-child(even) {
488+
background-color: #f9f9f9;
489+
}
490+
491+
tr:hover {
492+
background-color: #f1f1f1;
493+
}
494+
}
460495
}
461496

462497
.system.ecommerce {

0 commit comments

Comments
 (0)