Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implemented search on blog page #421

Merged
merged 4 commits into from
Feb 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions apps/valor-software-site/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@
"budgets": [
{
"type": "initial",
"maximumWarning": "500kb",
"maximumError": "1mb"
"maximumWarning": "2mb",
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
Expand Down Expand Up @@ -98,8 +98,8 @@
"budgets": [
{
"type": "initial",
"maximumWarning": "500kb",
"maximumError": "1mb"
"maximumWarning": "2mb",
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,12 +261,14 @@ <h3 id="_make_the_solution_test_friendly">Make the solution test-friendly</h3>
<p>Run the CLI as a separate process and intercommunicate with them.</p>
</li>
<li>
<p>Run the CLI functionality inside the tests.
I chose the second one because it&#8217;s more suitable for integration testing. The first is mostly regarding e2e or Big (Google definitions) tests. Also, the second approach is much more straightforward in implementation. But there is one critical answer here. We must pass the input data (key presses) to the CLI.</p>
<p>Run the CLI functionality inside the tests.</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>I chose the second one because it&#8217;s more suitable for integration testing. The first is mostly regarding e2e or Big (Google definitions) tests. Also, the second approach is much more straightforward in implementation. But there is one critical answer here. We must pass the input data (key presses) to the CLI.</p>
</div>
<div class="paragraph">
<p>If we talk about the first approach, the following approaches will be useful: <a href="https://stackoverflow.com/questions/13230370/nodejs-child-process-write-to-stdin-from-an-already-initialised-process" target="_blank" rel="noopener">Nodejs Child Process: write to stdin from an already initialised process</a>. It makes sense to note here that the approaches above are rather for e2e testing than integration.</p>
</div>
<div class="paragraph">
Expand Down
2 changes: 2 additions & 0 deletions apps/valor-software-site/src/assets/styles/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
// swiper core styles
@import 'swiper/css';

@import 'material-icons/iconfont/material-icons.scss';

body, html {
@apply bg-grey_bg h-full;
scroll-behavior: smooth;
Expand Down
17 changes: 14 additions & 3 deletions libs/route-pages/blog/src/blog.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,33 @@ import { CommonDocsModule } from '@valor-software/common-docs';
import { BlogComponent, ArticleComponent, BlogItemComponent } from './components';
import { FeedbackModule } from '@valor-software/feedback';
import { SwiperModule } from 'swiper/angular';
import { DomainNamePipe } from './pipes/domain-name.pipe';
import { DomainNamePipe, HighlightMatchingLettersPipe } from './pipes';
import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { MatInputModule } from '@angular/material/input';
import { MatIconModule } from '@angular/material/icon';
import { ReactiveFormsModule } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';

@NgModule({
declarations: [
BlogPageComponent,
BlogComponent,
ArticleComponent,
BlogItemComponent,
DomainNamePipe
DomainNamePipe,
HighlightMatchingLettersPipe
],
imports: [
CommonModule,
RouterModule.forChild(routes),
CommonDocsModule,
FeedbackModule,
SwiperModule
SwiperModule,
MatAutocompleteModule,
MatInputModule,
MatIconModule,
ReactiveFormsModule,
MatButtonModule
]
})
export class BlogModule {
Expand Down
111 changes: 72 additions & 39 deletions libs/route-pages/blog/src/pages/blog-page/blog-page.component.html
Original file line number Diff line number Diff line change
@@ -1,52 +1,85 @@
<section class="landing-section !pt-24 lg:!pt-40 !pb-0">
<div *ngIf="firstArticles.length > 0 && activeArticle"
class="container flex flex-col lg:flex-row">
<section class="landing-section !pt-24 !pb-0">
<div class="container flex flex-col items-end">
<mat-form-field *ngIf="articles.length > 0"
class="search">
<input type="text"
matInput
[placeholder]="'Search'"
[formControl]="searchTermControl"
[matAutocomplete]="autoGroup">
<mat-autocomplete [disableRipple]="true"
#autoGroup="matAutocomplete">
<mat-optgroup *ngFor="let group of groupedAndFilteredArticles" [label]="group.tag">
<mat-option *ngFor="let article of group.articles" [value]="article.title"
(click)="navigateToArticle(article.title)"
(onSelectionChange)="navigateToArticle(article.title)">
<span class="cursor-pointer"
[innerHtml]="article.title | highlightMatchingLetters: searchTermControl.value"></span>
</mat-option>
</mat-optgroup>
</mat-autocomplete>

<a *ngIf="activeArticle?.title"
href="javascript:void(0)"
[routerLink]="[getRouteLink(activeArticle.title)]"
class="cursor-pointer main-image">
<blog-item
class="w-full lg:pt-0"
[showActiveArticle]="true"
[article]="activeArticle">
</blog-item>
</a>
<mat-icon matPrefix>search</mat-icon>
<button *ngIf="searchTermControl?.value?.length ?? 0 > 0"
[disableRipple]="true"
mat-icon-button
(click)="searchTermControl.reset()"
matSuffix>
<mat-icon>close</mat-icon>
</button>
</mat-form-field>

<div class="first-articles">
<ng-container *ngFor="let article of firstArticles">
<a
href="javascript:void(0)"
[routerLink]="[getRouteLink(article.title)]"
class="w-full cursor-pointer smaller-article-item mb-8">
<blog-item
*ngIf="article?.title !== activeArticle?.title"
[showLatestArticles]="true"
[article]="article"
></blog-item>
</a>
</ng-container>
</div>

<div class="block lg:hidden mt-4 lg:mt-0">
<h1 class="main-title mb-4">Latest Articles</h1>
<div class="flex flex-col lg:flex-row mt-7"
*ngIf="firstArticles.length > 0 && activeArticle">

<a *ngIf="activeArticle?.title"
href="javascript:void(0)"
[routerLink]="[getRouteLink(activeArticle.title)]"
class="cursor-pointer main-image">
<blog-item
class="w-full lg:pt-0"
[showActiveArticle]="true"
[article]="activeArticle">
</blog-item>
</a>

<swiper
[config]="swiperConfig"
class="pink_swiper transparent_slides">
<ng-template swiperSlide *ngFor="let article of firstArticles">
<a href="javascript:void(0)" [routerLink]="[getRouteLink(article.title)]"
class="w-full lg:max-w-380 lg:w-31% cursor-pointer smaller-article-item">
<div class="first-articles">
<ng-container *ngFor="let article of articles | slice : 0: 4">
<a
href="javascript:void(0)"
[routerLink]="[getRouteLink(article.title)]"
class="w-full cursor-pointer smaller-article-item">
<blog-item
*ngIf="article?.title !== activeArticle?.title"
[showLatestArticles]="true"
[article]="article">
</blog-item>
[article]="article"
></blog-item>
</a>
</ng-template>
</ng-container>
</div>

<div class="block lg:hidden mt-4 lg:mt-0">
<h1 class="main-title mb-4">Latest Articles</h1>

</swiper>
<swiper
[config]="swiperConfig"
class="pink_swiper transparent_slides">
<ng-template swiperSlide *ngFor="let article of firstArticles">
<a href="javascript:void(0)" [routerLink]="[getRouteLink(article.title)]"
class="w-full lg:max-w-380 lg:w-31% cursor-pointer smaller-article-item">
<blog-item
*ngIf="article?.title !== activeArticle?.title"
[showLatestArticles]="true"
[article]="article">
</blog-item>
</a>
</ng-template>

</swiper>
</div>
</div>

</div>
</section>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ $bp-large: 1024px;
}

.first-articles {
width: 30%;
width: 32%;
display: none;
flex-direction: column;
max-height: 100%;
Expand All @@ -35,4 +35,86 @@ $bp-large: 1024px;

::ng-deep .pink_swiper .swiper-slide {
padding-top: 0;
}

.search {
width: 32%;
}

::ng-deep .cdk-overlay-pane {
.mat-mdc-autocomplete-panel {
background-color: #515151;
padding-top: 0;
padding-bottom: 16px;
max-height: 306px
}

.mat-mdc-optgroup {
color: #E3E3E3;
}

.mat-mdc-optgroup-label {
min-height: auto;
margin-bottom: 8px;
margin-top: 16px;
}

.mat-mdc-option {
background-color: #343434;
margin: 0 16px 4px;
color: #E3E3E3;
border-radius: 4px;
}

.mat-mdc-optgroup .mat-mdc-option:not(.mat-mdc-option-multiple) {
padding: 10px 12px;
}

.mat-mdc-option:hover:not(.mdc-list-item--disabled) {
background-color: rgba(226, 78, 99, 1) !important;
color: rgba(255, 255, 255, 1) !important;
}

.mat-mdc-option:focus:not(.mdc-list-item--disabled) {
background-color: rgba(226, 78, 99, 1) !important;
color: rgba(255, 255, 255, 1) !important;
}

.mat-mdc-option:active:not(.mdc-list-item--disabled) {
background-color: rgba(226, 78, 99, 1) !important;
color: rgba(255, 255, 255, 1) !important;
}

.mat-mdc-option:focus.mdc-list-item, .mat-mdc-option.mat-mdc-option-active.mdc-list-item {
background-color: rgba(226, 78, 99, 1) !important;
color: rgba(255, 255, 255, 1) !important;
}
}

::ng-deep .mat-icon {
color: #8C8C8C;
}

::ng-deep .mdc-text-field--filled:not(.mdc-text-field--disabled) {
background-color: #515151 !important;
}

::ng-deep .mdc-text-field__input:focus {
box-shadow: none;
}

::ng-deep .mdc-text-field--filled:not(.mdc-text-field--disabled) .mdc-line-ripple::after {
border-bottom-color: transparent !important;
}

::ng-deep .mat-mdc-autocomplete-trigger {
color: rgba(255, 255, 255, 1) !important;
}

::ng-deep .mdc-text-field--filled:not(.mdc-text-field--disabled) .mdc-text-field__input {
caret-color: white !important;
}

::ng-deep .mat-mdc-input-element::placeholder{
color: #8C8C8C !important;
}
Loading
Loading