Skip to content

Commit 79e529e

Browse files
authored
Merge pull request #1 from telerik/polish-demos
Polish demos
2 parents f43f7db + 12ccc4b commit 79e529e

23 files changed

+2896
-1043
lines changed

blazor-progress-rag-demo/Pages/AISearch.razor

Lines changed: 145 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -3,97 +3,129 @@
33
@using Telerik.Blazor
44
@using blazor_progress_rag_demo.Services
55
@inject NucliaSearchService NucliaService
6+
@inject NavigationManager NavigationManager
67

7-
<div class="k-d-flex k-flex-col k-min-h-screen k-bg-surface k-pb-20">
8-
9-
@if (!HasSearched)
8+
<div class="ai-search-container k-pos-relative k-overflow-x-hidden k-overflow-y-auto">
9+
@if (!HasResults)
1010
{
11-
@* Hero Section *@
12-
<HeroSection />
13-
}
14-
else
15-
{
16-
@* Results Header *@
17-
<div class="k-d-flex k-flex-col k-align-items-center k-pt-10 k-px-4">
18-
<h1 class="k-h1 k-font-weight-bold k-mb-4 k-text-center">
19-
Discover <span class="text-gradient-purple-blue">Progress Agentic RAG Knowledge</span>
20-
</h1>
11+
@* Decorative circle background - only show when no results *@
12+
<div class="ai-search-decorative-circle k-pos-absolute">
13+
<div class="ai-search-decorative-inner k-pos-absolute">
14+
<div class="ai-search-gradient-bg k-w-full k-h-full" />
15+
</div>
2116
</div>
17+
18+
@* Decorative network visualization image on the right *@
19+
<VectorsBackground Show="true" />
2220
}
2321

24-
@* Search Section *@
25-
<div class="k-d-flex k-flex-col k-align-items-center @(HasSearched ? "k-mt-4" : "k-mt-10") k-w-full k-px-4">
26-
27-
@* Search Bar *@
28-
<div class="search-box-container k-w-full">
29-
<TelerikTextBox @bind-Value="@SearchQuery"
30-
Placeholder="Ask about PARAG features, deployment, security, integrations..."
31-
Size="@ThemeConstants.TextBox.Size.Large"
32-
Rounded="@ThemeConstants.TextBox.Rounded.Full">
33-
<TextBoxPrefixTemplate>
34-
<div class="k-pl-2 k-color-subtle">
35-
<TelerikSvgIcon Icon="@SvgIcon.Plus" Size="@ThemeConstants.SvgIcon.Size.Large" />
22+
@* Main content container *@
23+
<div class="ai-search-content k-d-flex k-flex-column k-pos-relative k-overflow-hidden">
24+
@if (!HasResults)
25+
{
26+
@* Initial state: Large header with description *@
27+
<div class="k-d-flex k-flex-column k-gap-8 rag-hero-wrapper">
28+
<h1 class="ai-search-title !k-mb-0 k-h1">
29+
Discover
30+
<br />
31+
Progress Agentic RAG Knowledge
32+
</h1>
33+
<p class="ai-search-description !k-mb-0">
34+
Search our comprehensive Nuclia knowledge base with AI-powered intelligent search for precise, contextual results about Nuclia features, capabilities, and best practices
35+
</p>
36+
</div>
37+
38+
@* Search input section - centered horizontally *@
39+
<div class="ai-search-input-wrapper k-d-flex k-flex-column k-gap-8 search-input-wrapper k-w-full">
40+
<SearchInput Query="@Query"
41+
QueryChanged="@((value) => Query = value)"
42+
OnSearchClick="@HandleSearch"
43+
IsLoading="@IsLoading"
44+
Placeholder="Ask about PARAG features, deployment, security, integrations..." />
45+
46+
@* Popular searches section *@
47+
<div class="k-d-flex k-flex-column k-w-full k-gap-3">
48+
<p class="ai-search-popular-label !k-mb-0">
49+
Popular searches:
50+
</p>
51+
<div class="k-d-flex k-flex-wrap k-gap-1.5 k-justify-content-flex-start">
52+
@foreach (var searchText in PopularSearches)
53+
{
54+
<SearchPill Text="@searchText"
55+
OnClick="@(() => HandleExampleSearch(searchText))"
56+
Disabled="@IsLoading" />
57+
}
3658
</div>
37-
</TextBoxPrefixTemplate>
38-
<TextBoxSuffixTemplate>
39-
<div class="k-d-flex k-align-items-center k-gap-2 k-pr-1">
40-
<TelerikButton FillMode="@ThemeConstants.Button.FillMode.Flat"
41-
Icon="@SvgIcon.MicrophoneOutline"
42-
Title="Voice Search"
43-
Class="k-rounded-full k-color-subtle" />
44-
45-
<TelerikButton ThemeColor="@ThemeConstants.Button.ThemeColor.Primary"
46-
FillMode="@ThemeConstants.Button.FillMode.Solid"
47-
Icon="@SvgIcon.ArrowUp"
48-
Class="k-rounded-full k-w-10 k-h-10 k-p-0 k-d-flex k-justify-content-center k-align-items-center"
49-
OnClick="@HandleSearch" />
59+
</div>
60+
</div>
61+
}
62+
else
63+
{
64+
@* Results state: Compact header with integrated search *@
65+
<div class="ai-search-results-hero k-d-flex k-flex-column k-gap-9 k-pos-relative hero">
66+
@* Decorative elements container with overflow clipping *@
67+
<div class="ai-search-results-decorative-container k-pos-absolute k-overflow-hidden">
68+
@* Decorative gradient circle behind title *@
69+
<div class="ai-search-results-gradient-circle k-pos-absolute">
70+
<div class="ai-search-results-gradient-inner k-pos-absolute">
71+
<div class="ai-search-gradient-bg k-w-full k-h-full" />
72+
</div>
5073
</div>
51-
</TextBoxSuffixTemplate>
52-
</TelerikTextBox>
53-
</div>
5474

55-
@if (!HasSearched)
56-
{
57-
@* Popular Searches *@
58-
<div class="k-mt-10 k-d-flex k-flex-col k-align-items-center k-w-full k-max-w-screen-lg">
59-
<div class="k-font-size-sm k-color-subtle k-mb-4">Popular searches:</div>
60-
61-
<div class="k-d-flex k-justify-content-center k-flex-wrap k-gap-2 k-w-full">
62-
@foreach (var item in PopularSearchItems)
63-
{
64-
<SearchPill Text="@item.Text" OnClick="@(() => OnPillClick(item.Text))" />
65-
}
75+
@* Vertical gradient shadow *@
76+
<div class="ai-search-results-shadow k-pos-absolute" />
77+
</div>
78+
79+
<h1 class="ai-search-results-title !k-mb-0 k-text-center k-pos-relative">
80+
Discover Progress Agentic RAG Knowledge
81+
</h1>
82+
83+
@* Search input - centered and integrated *@
84+
<div class="ai-search-results-input-wrapper k-w-full k-pos-relative">
85+
<SearchInput Query="@Query"
86+
QueryChanged="@((value) => Query = value)"
87+
OnSearchClick="@HandleSearch"
88+
IsLoading="@IsLoading"
89+
Placeholder="What is PARAG and how does it work?" />
6690
</div>
6791
</div>
6892
}
69-
else
93+
94+
@* Results section *@
95+
@if (HasResults)
7096
{
71-
@* Search Results *@
72-
<div class="k-mt-10 k-w-full k-max-w-screen-lg">
73-
<div class="k-p-6">
74-
@if (IsSearching && string.IsNullOrEmpty(SearchResult?.Response))
97+
<div class="ai-search-results-section k-d-flex k-flex-column k-overflow-hidden k-w-full results-section">
98+
<div class="ai-search-results-content-wrapper k-d-flex k-flex-column k-gap-16 k-w-full results-content">
99+
@* Answer content *@
100+
@if (IsLoading)
75101
{
76-
<div class="k-d-flex k-justify-content-center k-align-items-center k-p-4">
77-
<TelerikLoader Size="@ThemeConstants.Loader.Size.Large" />
78-
</div>
102+
<GradientLoader Title="Searching<br />Knowledge Base"
103+
Subtitle="Analyzing your query..." />
79104
}
80-
else if (SearchResult != null)
105+
106+
@if (!IsLoading && !string.IsNullOrEmpty(Answer))
81107
{
82-
<div class="k-font-size-md k-line-height-md k-mb-4" style="white-space: pre-wrap;">
83-
@SearchResult.Response
108+
<div class="ai-search-answer-text markdown-content">
109+
<MarkdownContent Text="@Answer" />
84110
</div>
85111
}
86-
</div>
87-
</div>
88112

89-
@* Related Searches *@
90-
<div class="k-mt-10 k-d-flex k-flex-col k-align-items-center k-w-full k-max-w-screen-lg">
91-
<div class="k-font-size-sm k-color-subtle k-mb-4">Related searches:</div>
92-
93-
<div class="k-d-flex k-justify-content-center k-flex-wrap k-gap-2 k-w-full">
94-
@foreach (var item in PopularSearchItems)
113+
@* Related searches section *@
114+
@if (!IsLoading && !string.IsNullOrEmpty(Answer))
95115
{
96-
<SearchPill Text="@item.Text" OnClick="@(() => OnPillClick(item.Text))" />
116+
<div class="k-d-flex k-flex-column k-gap-3">
117+
<p class="ai-search-popular-label !k-mb-0">
118+
Related searches:
119+
</p>
120+
<div class="k-d-flex k-flex-wrap k-justify-content-flex-start k-gap-1">
121+
@foreach (var searchText in PopularSearches)
122+
{
123+
<SearchPill Text="@searchText"
124+
OnClick="@(() => HandleExampleSearch(searchText))"
125+
Disabled="@IsLoading" />
126+
}
127+
</div>
128+
</div>
97129
}
98130
</div>
99131
</div>
@@ -102,55 +134,68 @@
102134
</div>
103135

104136
@code {
105-
private string SearchQuery { get; set; } = string.Empty;
106-
private bool HasSearched { get; set; } = false;
107-
private bool IsSearching { get; set; } = false;
108-
private StreamingAskResult? SearchResult { get; set; }
137+
private string Query { get; set; } = string.Empty;
138+
private bool IsLoading { get; set; } = false;
139+
private string Answer { get; set; } = string.Empty;
140+
private string CurrentQuestion { get; set; } = string.Empty;
109141

110-
public class PopularSearchItem
111-
{
112-
public string Text { get; set; } = string.Empty;
113-
}
142+
private bool HasResults => !string.IsNullOrEmpty(Answer) || IsLoading || !string.IsNullOrEmpty(CurrentQuestion);
114143

115-
private List<PopularSearchItem> PopularSearchItems { get; set; } = new List<PopularSearchItem>
144+
private List<string> PopularSearches = new List<string>
116145
{
117-
new PopularSearchItem { Text = "What is PARAG and how does it work?" },
118-
new PopularSearchItem { Text = "Deployment options and requirements" },
119-
new PopularSearchItem { Text = "Security features and compliance" },
120-
new PopularSearchItem { Text = "API integration and capabilities" },
121-
new PopularSearchItem { Text = "Pricing and licensing options" },
122-
new PopularSearchItem { Text = "Use cases and customer success stories" }
146+
"What is PARAG and how does it work?",
147+
"Deployment options and requirements",
148+
"Security features and compliance",
149+
"API integration and capabilities",
150+
"Pricing and licensing options",
151+
"Use cases and customer success stories"
123152
};
124153

154+
protected override void OnInitialized()
155+
{
156+
// Check for query parameter from navigation
157+
var uri = NavigationManager.ToAbsoluteUri(NavigationManager.Uri);
158+
if (Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(uri.Query).TryGetValue("query", out var queryParam))
159+
{
160+
Query = queryParam.ToString();
161+
_ = HandleSearch();
162+
}
163+
}
164+
125165
private async Task HandleSearch()
126166
{
127-
if (string.IsNullOrWhiteSpace(SearchQuery)) return;
167+
if (string.IsNullOrWhiteSpace(Query) || IsLoading)
168+
{
169+
return;
170+
}
128171

129-
HasSearched = true;
130-
IsSearching = true;
131-
SearchResult = new StreamingAskResult();
172+
IsLoading = true;
173+
Answer = string.Empty;
174+
CurrentQuestion = Query;
175+
StateHasChanged();
132176

133177
try
134178
{
135-
SearchResult = await NucliaService.AskVerseAsync(SearchQuery, (text) =>
179+
await NucliaService.AskVerseAsync(Query, (partialResponse) =>
136180
{
137-
if (SearchResult != null)
138-
{
139-
SearchResult.Response = text;
140-
InvokeAsync(StateHasChanged);
141-
}
181+
Answer = partialResponse;
182+
InvokeAsync(StateHasChanged);
142183
});
143184
}
185+
catch (Exception ex)
186+
{
187+
Answer = $"Sorry, I encountered an error: {ex.Message}";
188+
}
144189
finally
145190
{
146-
IsSearching = false;
191+
IsLoading = false;
147192
await InvokeAsync(StateHasChanged);
148193
}
149194
}
150195

151-
private async Task OnPillClick(string text)
196+
private async Task HandleExampleSearch(string searchText)
152197
{
153-
SearchQuery = text;
198+
Query = searchText;
154199
await HandleSearch();
155200
}
156201
}

0 commit comments

Comments
 (0)