main
Ogoun 5 months ago
parent 708729b3f0
commit 62dd21a4b7

@ -6,29 +6,6 @@
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<Page Include="web\css\fonts\Raleway-Italic-VariableFont_wght.ttf" />
<Page Include="web\css\fonts\Raleway-VariableFont_wght.ttf" />
<Page Include="web\css\fonts\Roboto-300.ttf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Page>
<Page Include="web\css\fonts\Roboto-300.woff">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Page>
<Page Include="web\css\fonts\Roboto-300.woff2">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Page>
<Page Include="web\css\fonts\Roboto-400.ttf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Page>
<Page Include="web\css\fonts\Roboto-400.woff">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Page>
<Page Include="web\css\fonts\Roboto-400.woff2">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Page>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\BukiVedi.Shared\BukiVedi.Shared.csproj" />
</ItemGroup>
@ -40,6 +17,9 @@
<None Update="web\assets\cover.jpg">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="web\assets\fortune.svg">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="web\assets\heart.svg">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
@ -52,10 +32,31 @@
<None Update="web\assets\search.svg">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="web\css\buki-common.css">
<None Update="web\css\common.css">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="web\css\common.css">
<None Update="web\css\fonts\Raleway-Italic-VariableFont_wght.ttf">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="web\css\fonts\Raleway-VariableFont_wght.ttf">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="web\css\fonts\Roboto-300.ttf">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="web\css\fonts\Roboto-300.woff">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="web\css\fonts\Roboto-300.woff2">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="web\css\fonts\Roboto-400.ttf">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="web\css\fonts\Roboto-400.woff">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="web\css\fonts\Roboto-400.woff2">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="web\css\login.css">
@ -74,60 +75,54 @@
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="web\fonts\Roboto-Black.ttf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="web\fonts\Roboto-BlackItalic.ttf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="web\fonts\Roboto-Bold.ttf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="web\fonts\Roboto-BoldItalic.ttf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="web\fonts\Roboto-Italic.ttf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="web\fonts\Roboto-Light.ttf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="web\fonts\Roboto-LightItalic.ttf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="web\fonts\Roboto-Medium.ttf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="web\fonts\Roboto-MediumItalic.ttf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="web\fonts\Roboto-Regular.ttf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="web\fonts\Roboto-Thin.ttf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="web\fonts\Roboto-ThinItalic.ttf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="web\images\favicon.ico">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="web\images\flower.jpeg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="web\index.html">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="web\js\bukivedi-auth.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="web\js\bukivedi.js">
<None Update="web\index.html">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="web\js\common\jquery.js">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="web\js\common\jquery.min.js">
<None Update="web\js\components\menu\index.js">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="web\js\components\tags\index.js">
@ -136,9 +131,6 @@
<None Update="web\js\constants\index.js">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="web\js\jquery.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="web\js\login\index.js">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
@ -160,6 +152,9 @@
<None Update="web\loginScript.js">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="web\README.md">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="web\script.js">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>

@ -36,6 +36,17 @@ namespace BukiVedi.App.Controllers
return Ok(await _handler.Search(request.Query, tag, OperationContext));
}
/// <summary>
/// Поиск книг по запросу
/// </summary>
/// <param name="request">Поисковый запрос</param>
/// <returns>Список найденных книг</returns>
[HttpPost("qsearch")]
public async Task<ActionResult<IEnumerable<BookInfo>>> SearchAI()
{
return Ok(await _handler.SearchAI(OperationContext));
}
#endregion
/// <summary>

@ -14,7 +14,7 @@ using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("BukiVedi.App")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+78ef654d3cca93dcdff7557d9a44da30b9d10a6a")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+708729b3f0a4a46b4ed8277753e30266f9b02ae4")]
[assembly: System.Reflection.AssemblyProductAttribute("BukiVedi.App")]
[assembly: System.Reflection.AssemblyTitleAttribute("BukiVedi.App")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]

@ -1 +1 @@
9dd3a16a8dacdbe5f2cc466ad40a08504afd3b209bf5aa3244617367acdb74bb
5d627d5604365b2a4254a699545c17a9cb8aa8618ee125b742c4fb1f29d8de02

@ -88,10 +88,19 @@ G:\Documents\GitHub\BukiVedi\src\BukiVedi.App\bin\Debug\net8.0\web\js\requests\i
G:\Documents\GitHub\BukiVedi\src\BukiVedi.App\bin\Debug\net8.0\web\js\scroll\index.js
G:\Documents\GitHub\BukiVedi\src\BukiVedi.App\bin\Debug\net8.0\web\script.js
G:\Documents\GitHub\BukiVedi\src\BukiVedi.App\bin\Debug\net8.0\web\assets\pencil.svg
G:\Documents\GitHub\BukiVedi\src\BukiVedi.App\bin\Debug\net8.0\web\js\common\jquery.min.js
G:\Documents\GitHub\BukiVedi\src\BukiVedi.App\bin\Debug\net8.0\web\js\components\tags\index.js
G:\Documents\GitHub\BukiVedi\src\BukiVedi.App\bin\Debug\net8.0\web\js\utils\index.js
G:\Documents\GitHub\BukiVedi\src\BukiVedi.App\bin\Debug\net8.0\web\loginScript.js
G:\Documents\GitHub\BukiVedi\src\BukiVedi.App\bin\Debug\net8.0\web\server.js
G:\Documents\GitHub\BukiVedi\src\BukiVedi.App\bin\Debug\net8.0\LemmaSharpPrebuilt.pdb
G:\Documents\GitHub\BukiVedi\src\BukiVedi.App\bin\Debug\net8.0\LemmaSharpPrebuilt.dll.config
G:\Documents\GitHub\BukiVedi\src\BukiVedi.App\bin\Debug\net8.0\web\assets\fortune.svg
G:\Documents\GitHub\BukiVedi\src\BukiVedi.App\bin\Debug\net8.0\web\css\fonts\Raleway-Italic-VariableFont_wght.ttf
G:\Documents\GitHub\BukiVedi\src\BukiVedi.App\bin\Debug\net8.0\web\css\fonts\Raleway-VariableFont_wght.ttf
G:\Documents\GitHub\BukiVedi\src\BukiVedi.App\bin\Debug\net8.0\web\css\fonts\Roboto-300.ttf
G:\Documents\GitHub\BukiVedi\src\BukiVedi.App\bin\Debug\net8.0\web\css\fonts\Roboto-300.woff
G:\Documents\GitHub\BukiVedi\src\BukiVedi.App\bin\Debug\net8.0\web\css\fonts\Roboto-300.woff2
G:\Documents\GitHub\BukiVedi\src\BukiVedi.App\bin\Debug\net8.0\web\css\fonts\Roboto-400.ttf
G:\Documents\GitHub\BukiVedi\src\BukiVedi.App\bin\Debug\net8.0\web\css\fonts\Roboto-400.woff
G:\Documents\GitHub\BukiVedi\src\BukiVedi.App\bin\Debug\net8.0\web\css\fonts\Roboto-400.woff2
G:\Documents\GitHub\BukiVedi\src\BukiVedi.App\bin\Debug\net8.0\web\js\components\menu\index.js
G:\Documents\GitHub\BukiVedi\src\BukiVedi.App\bin\Debug\net8.0\web\README.md

@ -0,0 +1,12 @@
# Vanilla JS Project
Vesion 1.0
## To run chrome for localhost:
`
"C:\Program Files\Google\Chrome\Application\chrome.exe" --disable-web-security --disable-gpu --user-data-dir=C:\Users\User\chromeTemp
`
## To run project for [localhost](http://localhost:3001/login.html):
`
npm start
`

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve"><path d="M256,16c-64.106,0-124.375,24.964-169.706,70.294S16,191.894,16,256s24.964,124.375,70.294,169.706S191.894,496,256,496 s124.375-24.964,169.706-70.294S496,320.106,496,256s-24.964-124.375-70.294-169.706S320.106,16,256,16z M456.194,155.59 l-40.313,26.875c-16.205-35.093-43.629-63.977-77.648-82.032l18.959-44.238C399.847,77.886,434.664,112.839,456.194,155.59z M256,416c-88.224,0-160-71.776-160-160S167.776,96,256,96s160,71.776,160,160S344.224,416,256,416z M342.674,49.453l-18.91,44.122 C302.896,84.836,280.003,80,256,80s-46.896,4.836-67.764,13.575l-18.91-44.122C196.001,38.218,225.287,32,256,32 S315.999,38.218,342.674,49.453z M154.809,56.195l18.959,44.238c-32.088,17.03-58.312,43.692-74.785,76.114l-42.925-21.463 C77.606,112.563,112.321,77.801,154.809,56.195z M49.336,169.612l43.052,21.526C84.398,211.22,80,233.105,80,256 c0,24.003,4.836,46.896,13.575,67.764l-44.122,18.91C38.218,315.999,32,286.713,32,256C32,225.396,38.176,196.21,49.336,169.612z M56.195,357.191l44.238-18.959c16.541,31.165,42.169,56.794,73.335,73.335l-18.959,44.238 C112.412,434.246,77.754,399.588,56.195,357.191z M169.326,462.547l18.91-44.122C209.104,427.164,231.997,432,256,432 s46.896-4.836,67.764-13.575l18.91,44.122C315.999,473.782,286.713,480,256,480S196.001,473.782,169.326,462.547z M357.191,455.805 l-18.959-44.238c34.019-18.055,61.443-46.939,77.648-82.032l40.313,26.875C434.664,399.161,399.847,434.114,357.191,455.805z M462.951,341.686l-40.925-27.283C428.477,296.118,432,276.464,432,256c0-20.464-3.523-40.118-9.974-58.403l40.925-27.283 C473.927,196.724,480,225.664,480,256C480,286.336,473.927,315.276,462.951,341.686z M349.654,338.341l-48.821-48.821 c5.494-7.329,9.225-16.047,10.587-25.519H336v16c0,2.882,1.55,5.542,4.059,6.961c1.224,0.693,2.583,1.039,3.941,1.039 c1.426,0,2.851-0.381,4.116-1.14l40-24c2.409-1.446,3.884-4.05,3.884-6.86s-1.475-5.414-3.884-6.86l-40-24 c-2.472-1.483-5.549-1.521-8.058-0.102S336,229.118,336,232v16h-24.581c-1.361-9.473-5.093-18.19-10.587-25.519l48.821-48.821 C351.103,172.211,352,170.21,352,168c0-4.418-3.582-8-8-8c-2.21,0-4.211,0.897-5.659,2.346l-48.821,48.821 c-7.329-5.494-16.046-9.225-25.519-10.587V184h16c4.418,0,8-3.582,8-8s-3.582-8-8-8h-6.131c3.809-4.249,6.131-9.858,6.131-16 c0-4.516-1.255-8.743-3.433-12.354c5.482-2.567,8.518-5.418,9.085-5.985c1.45-1.448,2.347-3.45,2.347-5.661c0-4.418-3.582-8-8-8 c-2.21,0-4.21,0.896-5.658,2.344C274.274,122.411,268.13,128,256,128c-12.149,0-18.184-5.512-18.435-5.747l0.088,0.087 c-1.447-1.446-3.446-2.34-5.653-2.34c-4.418,0-8,3.582-8,8c0,2.211,0.897,4.213,2.347,5.661c0.567,0.567,3.603,3.418,9.085,5.985 C233.255,143.257,232,147.484,232,152c0,6.142,2.322,11.751,6.131,16H232c-4.418,0-8,3.582-8,8s3.582,8,8,8h16v16.581 c-9.473,1.361-18.19,5.093-25.519,10.587l-48.821-48.821C172.211,160.897,170.21,160,168,160c-4.418,0-8,3.582-8,8 c0,2.21,0.897,4.211,2.346,5.659l48.821,48.821c-5.494,7.329-9.225,16.046-10.587,25.519h-33.957c-3.302-9.311-12.194-16-22.624-16 c-13.234,0-24,10.766-24,24s10.766,24,24,24c10.429,0,19.322-6.689,22.624-16h33.957c1.361,9.473,5.093,18.19,10.587,25.519 l-48.821,48.821C160.897,339.789,160,341.79,160,344c0,4.418,3.582,8,8,8c2.21,0,4.211-0.897,5.659-2.346l48.821-48.821 c7.329,5.494,16.046,9.225,25.519,10.587v21.267l-2.343-2.343c-3.124-3.124-8.189-3.124-11.313,0l-15.997,15.997 C216.897,347.789,216,349.79,216,352c0,4.418,3.582,8,8,8c2.21,0,4.211-0.897,5.659-2.346L240,347.314l10.343,10.343 c1.562,1.562,3.609,2.343,5.657,2.343s4.095-0.781,5.657-2.343L272,347.314l10.341,10.34C283.789,359.103,285.79,360,288,360 c4.418,0,8-3.582,8-8c0-2.21-0.897-4.211-2.346-5.659l-15.997-15.997c-3.124-3.124-8.189-3.124-11.313,0L264,332.686v-21.267 c9.473-1.361,18.19-5.093,25.519-10.587l48.821,48.821C339.789,351.103,341.79,352,344,352c4.418,0,8-3.582,8-8 C352,341.79,351.103,339.789,349.654,338.341z M352,246.129L368.451,256L352,265.871V246.129z M264,152c0,4.411-3.589,8-8,8 s-8-3.589-8-8s3.589-8,8-8S264,147.589,264,152z M256,296c-22.056,0-40-17.944-40-40s17.944-40,40-40s40,17.944,40,40 S278.056,296,256,296z M144,264c-4.411,0-8-3.589-8-8s3.589-8,8-8s8,3.589,8,8S148.411,264,144,264z M296,384c0,4.418-3.582,8-8,8 c-2.21,0-4.211-0.897-5.659-2.346L272,379.314l-10.343,10.343C260.095,391.219,258.047,392,256,392s-4.095-0.781-5.657-2.343 L240,379.314l-10.341,10.34C228.211,391.103,226.21,392,224,392c-4.418,0-8-3.582-8-8c0-2.21,0.897-4.211,2.346-5.659l15.997-15.997 c3.124-3.124,8.189-3.124,11.313,0L256,372.686l10.343-10.343c3.124-3.124,8.189-3.124,11.313,0l15.997,15.997 C295.103,379.789,296,381.79,296,384z"/></svg>

After

Width:  |  Height:  |  Size: 4.6 KiB

@ -76,6 +76,11 @@ input {
margin-bottom: 12px;
}
.mv-m {
margin-top: 20px;
margin-bottom: 20px;
}
.mt-m {
margin-top: 20px;
}
@ -130,6 +135,10 @@ input {
padding-right: 12px;
}
.pt-l {
padding-top: 40px;
}
/**
* display forms
**/
@ -138,6 +147,11 @@ input {
display: flex;
}
.justify-c {
display: flex;
justify-content: center;
}
.d-bl {
display: block;
}

@ -1,7 +1,7 @@
.background-logo {
position: absolute;
top: -15px;
top: 25px;
left: 20px;
z-index: -1;
overflow: hidden;

@ -34,10 +34,16 @@ header {
width: 20px;
height: 100%;
left: 10px;
top: 15px;
top: 55px;
opacity: 0.25;
}
.main-search-btn-wrapper {
position: absolute;
right: 5px;
top: 43px;
}
.main-search {
display: block;
width: 100%;
@ -47,6 +53,7 @@ header {
border-radius: 14px;
border-style: solid;
border-width: 1px;
padding-right: 200px;
}
.main-search:hover {
@ -67,20 +74,23 @@ header {
.main-search-btn {
display: block;
margin-left: auto;
margin-right: auto;
max-width: 200px;
width: 200px;
height: 50px;
visibility: hidden;
max-width: 120px;
width: 120px;
height: 44px;
min-width: 80px;
background: var(--main-font-color);
color: var(--main-bg-color);
font-size: 21px;
font-size: 17px;
line-height: 25px;
border-radius: 15px;
cursor: pointer;
}
.main-search-btn.visible {
visibility: visible;
}
.main-search-btn:hover {
opacity: 0.9;
}
@ -96,6 +106,61 @@ header {
margin-right: auto;
}
#fortuneButton {
background-color: transparent;
background-image: url(../assets/fortune.svg);
background-repeat: no-repeat;
width: 40px;
height: 40px;
border: 0;
margin-left: 12px;
margin-top: 3px;
position: relative;
transform-origin: center center;
}
#fortuneButton:hover {
cursor: pointer;
animation: antiClockwiseSpin 1s linear;
transform-origin: center center;
}
#fortuneButton:active {
transform: translateY(2px);
}
@keyframes antiClockwiseSpin {
0% {
transform: rotate(180deg);
}
100% {
transform: rotate(0deg);
}
}
@keyframes antiClockwiseSpin {
0% {
transform: rotate(180deg);
}
100% {
transform: rotate(0deg);
}
}
/*
#fortuneButton:hover:after {
content: "Мне повезет!";
color: var(--main-font-color);
width: 95px;
font-size: 13px;
padding: 5px;
border-radius: 5px;
background: #fff;
position: absolute;
opacity: 1;
z-index: 2;
} */
/*========================================================
Book Section
========================================================*/
@ -139,6 +204,7 @@ header {
.main-book__card.card_closed {
max-height: 450px;
min-height: 285px;
overflow-y: hidden;
}
@ -316,7 +382,7 @@ header {
padding-bottom: 4px;
background: #fff;
line-height: 28px;
width: 200px;
width: 230px;
vertical-align: middle;
}
@ -342,7 +408,7 @@ header {
.main-book__tags_title {
position: relative;
width: 55px;
width: 113px;
font-family: Vedi, Verdana, Tahoma;
font-size: 14px;
line-height: 24px;
@ -355,17 +421,23 @@ header {
color: var(--active-color);
}
.pencil {
position: absolute;
top: 4px;
left: 40px;
background-image: url(../assets/pencil.svg);
background-repeat: no-repeat;
width: 20px;
height: 100%;
height: 20px;
margin-left: 12px;
margin-top: 4px;
}
.main-book__tags_title:hover,
.main-book__tags_title:active .pencil {
.main-book__pencil {
position: absolute;
top: 0;
left: 90px;
}
.pencil:hover,
.pencil:active {
cursor: pointer;
filter: brightness(0) saturate(100%) invert(43%) sepia(34%) saturate(7336%)
hue-rotate(202deg) brightness(82%) contrast(97%);
}
@ -486,7 +558,7 @@ header {
box-sizing: border-box;
border: 1px solid #ccc;
border-radius: 4px;
background-color: #FFF;
background-color: #fff;
color: var(--main-font-color);
font-size: 14px;
font-family: Vedi, Verdana, Tahoma;

@ -22,17 +22,21 @@
<body>
<header>
<h1 class="background-logo">Vedi</h1>
<div class="main-search-wrapper mt-l d-fl">
<div class="main-search-wrapper pt-l d-fl">
<div class="main-search-pic"></div>
<input
id="search"
class="main-search pl-l pr-s"
class="main-search pl-l"
placeholder="Выбери книгу, и я найду для тебя похожие"
autocomplete="off"
autofocus
/>
<div class="main-search-btn-wrapper d-fl">
<button id="searchButton" class="main-search-btn">Найти</button>
<button id="fortuneButton" class="main-fortune-search-btn"></button>
</div>
</div>
<button id="searchButton" class="main-search-btn mt-m">Найти</button>
</div>
</header>
<main>

@ -0,0 +1,112 @@
import { waitForElement } from "../../requests/index.js";
import { getMenu } from "../../constants/index.js";
export default class MenuComponent {
element;
constructor({
isBlocked = false,
hasReadLater = false,
authors = [],
bookid = null,
article,
}) {
this.isBlocked = isBlocked;
this.hasReadLater = hasReadLater;
this.authors = authors;
this.bookid = bookid;
this.article = article;
this.isOpened = false;
this.render();
}
get template() {
return `
<nav class="main-book__menu main-book__menu_closed" data-menu></nav>`;
}
initialize() {
this.initEventListeners();
}
initEventListeners() {
const menuListener = this.article.querySelector(".main-book__menu");
menuListener.addEventListener("click", (event) => {
const isAction = event.target.closest("[data-action]");
if (!!isAction) {
const id = isAction.dataset.action;
this.makeAction({ id });
} else {
this.openMenu();
}
});
document.addEventListener("menu-outside-click", () => this.closeMenu());
}
get actions() {
return getMenu({
isBlocked: this.isBlocked,
hasReadLater: this.hasReadLater,
});
}
getMenuBody() {
return this.actions
.map(({ label, id }) => {
return `
<li class="main-book__action second-text" id="main-book__action" data-action=${id}>
${label}
</li>`;
})
.join("");
}
openMenu() {
this.element.classList.remove("main-book__menu_closed");
const ulElement = document.createElement("ul");
ulElement.innerHTML = this.getMenuBody();
this.element.append(ulElement);
this.element.classList.add("main-book__menu_opened");
this.isOpened = true;
}
closeMenu() {
if (this.isOpened) {
this.element.classList.remove("main-book__menu_opened");
this.element.firstElementChild.remove();
this.element.classList.add("main-book__menu_closed");
this.isOpened = false;
}
}
async makeAction({ id }) {
this.article.classList.add("blur", "spinner");
const { action, value } =
this.actions.find((act) => act.id === Number(id)) || {};
await action({ id, bookid: this.bookid });
if (value) {
const { id, label } = value;
this[`${id}`] = label;
}
this.article.classList.remove("spinner");
this.closeMenu();
}
async waitRendered() {
await waitForElement(".main-book__menu");
this.initialize();
}
async render() {
const divElement = document.createElement("div");
divElement.innerHTML = this.template;
this.element = divElement.firstElementChild;
this.waitRendered();
}
}

@ -11,27 +11,37 @@ export default class TagsComponent {
}
get template() {
return `
<h6 data-edit-tag class="main-book__tags_title mt-m">
Теги
<div class="pencil"></div>
</h6>
<div class="main-book__center main-book__tags d-fl mv-s">${this.getTags(
this.tags
)}</div>
`;
return `<div class="main-book_edit">
${
!(this.tags && this.tags.length)
? this.getTitle()
: this.getTags(this.tags)
}
</div>`;
}
getTitle() {
return `<h6 data-tags-editor class="main-book__tags_title mt-s mb-m">
Добавить теги
<div class="main-book__pencil pencil"></div>
</h6> `;
}
getTags(tags) {
return (tags || [])
return `<div class="main-book__center main-book__tags d-fl mt-s mb-m">
${(tags || [])
.map(({ id, name }) => {
return `<a class="main-book__tag main-book__link" data-tag=${id}>#${name}</a>`;
})
.join("");
.join("")}
<div data-tags-editor class="pencil"></div></div>`;
}
getTextarea(tags) {
return `
<textarea class="main-book__textarea" data-area>${(tags || [])
<textarea data-tags-editor placeholder="Редактировать поле" class="main-book__textarea" data-area>${(
tags || []
)
.map(({ name }) => name)
.join(" ")}</textarea>
`;
@ -42,15 +52,13 @@ export default class TagsComponent {
}
initEventListeners() {
const tagsEditorListener = this.article.querySelector(
".main-book__tags_title"
);
const tagsEditorListener = this.article.querySelector(".main-book_edit");
tagsEditorListener.addEventListener("click", () => {
const tagsWrapper = this.article.querySelector(".main-book__tags");
if (!this.isTextareaMode) {
const tagsWrapper = this.article.querySelector(".main-book_edit");
tagsWrapper.innerHTML = this.getTextarea(this.tags);
this.article.querySelector(".main-book__textarea").focus();
this.isTextareaMode = true;
}
@ -64,7 +72,7 @@ export default class TagsComponent {
}
});
document.addEventListener("outside-click", async () => {
document.addEventListener("tag-outside-click", async () => {
if (this.isTextareaMode) {
this.closeTextarea();
}
@ -72,22 +80,31 @@ export default class TagsComponent {
}
async closeTextarea() {
const tagsWrapper = this.article.querySelector(".main-book__tags");
const tagsWrapper = this.article.querySelector(".main-book_edit");
const area = this.article.querySelector(".main-book__textarea");
const tags = area.value
.split(" ")
.map((item) => item.trim())
.filter((i) => i);
if (!!(tags || []).length > 0) {
if (
this.tags?.length !== tags?.length ||
(this.tags || []).some(({ name }, index) => name !== tags[index])
) {
await this.setTags({ bookid: this.bookid, tags });
}
tagsWrapper.innerHTML = this.getTags(this.tags);
if (!!(tags || []).length > 0) {
tagsWrapper.innerHTML = this.getTags(this.tags);
} else {
tagsWrapper.innerHTML = this.getTitle();
}
this.isTextareaMode = false;
}
async waitRendered() {
await waitForElement(".main-book__tags");
await waitForElement(".main-book_edit");
this.initialize();
}

@ -1,40 +1,73 @@
import * as requests from '../requests/index.js';
import * as requests from "../requests/index.js";
export const SUCCESS = "success";
export const menuEnum = [
export const menuDict = [
{
id: 1,
label: "Авторов в избранное",
action: requests.addAuthorToFavourites,
label: "В очередь на чтение",
action: requests.readLater,
value: {
id: 'hasReadLater',
label: true,
}
},
{
id: 2,
label: "В очередь на чтение",
action: requests.readLater,
label: "Убрать из очереди",
action: requests.removeFromReadLater,
value: {
id: 'hasReadLater',
label: false,
}
},
{
id: 3,
label: "Игнорировать книгу",
action: requests.ignoreBook,
value: {
id: 'isBlocked',
label: true,
}
},
{
id: 4,
label: "Игнорировать автора",
action: requests.ignoreAuthors,
label: "Перестать игнорировать книгу",
action: requests.stopIgnoreBook,
value: {
id: 'isBlocked',
label: false,
}
},
{
id: 5,
label: "Авторов в избранное",
action: requests.addAuthorToFavourites,
},
{
id: 6,
label: "Заметка",
label: "Игнорировать авторов",
action: requests.ignoreAuthors,
},
{
id: 7,
label: "Заметка",
action: () => {},
},
{
id: 8,
label: "Поделиться",
action: () => {},
},
];
export const getMenu = ({ isBlocked, hasReadLater }) =>
menuDict
.filter((item) => (isBlocked ? item.id !== 3 : item.id !== 4))
.filter((item) => (hasReadLater ? item.id !== 1 : item.id !== 2));
export const DEFAULT_AUTHOR = {
id: 0,
name: 'Неизвестно'
name: "Неизвестно",
};
export const likeEnum = [
@ -47,5 +80,5 @@ export const likeEnum = [
id: 1,
label: "Не нравится",
action: requests.removeBookToFavourites,
}
]
},
];

@ -1,6 +1,7 @@
import { menuEnum, likeEnum, DEFAULT_AUTHOR } from "../constants/index.js";
import { likeEnum, DEFAULT_AUTHOR } from "../constants/index.js";
import {
fetchData,
fetchRandomData,
downloadBook,
searchByAuthor,
searchByTag,
@ -9,6 +10,7 @@ import {
import { stopPropagation } from "../utils/index.js";
import TagsComponent from "../components/tags/index.js";
import MenuComponent from "../components/menu/index.js";
export default class BookSection {
subElements = [];
@ -37,31 +39,22 @@ export default class BookSection {
const booksListener = document.querySelector(".main-book__wrapper");
booksListener.addEventListener("click", (event) => {
let id, title;
stopPropagation(event);
const menuEvent = new CustomEvent("menu-outside-click");
const tagEvent = new CustomEvent("tag-outside-click");
const isLike = event.target.closest("[data-like]");
const isMenu = event.target.closest("[data-menu]");
const isAction = event.target.closest("[data-action]");
const isLink = event.target.closest("[data-link]");
const isAuthor = event.target.closest("[data-author]");
const isMoreDetails = event.target.closest("[data-details]");
const isTagWrapper = event.target.closest("[data-tags-wrapper]");
const isTagWrapper = event.target.closest("[data-tags-editor]");
const isTag = event.target.closest("[data-tag]");
stopPropagation(event);
const isMenuWrapper = event.target.closest("[data-menu]");
switch (true) {
case !!isAction:
id = isAction.dataset.action;
const { authorid, bookid } =
isAction.parentNode.parentNode.dataset || {};
this.makeAction({ id, authorid, bookid });
break;
case !!isLike:
this.makeLike(isLike);
break;
case !!isMenu:
this.openMenu(isMenu);
break;
case !!isLink:
@ -80,20 +73,21 @@ export default class BookSection {
this.toggleDetails(isMoreDetails);
break;
case !isTagWrapper:
const myEvent = new CustomEvent("outside-click");
document.dispatchEvent(myEvent);
this.closeMenu();
case !!isMenuWrapper:
break;
case !!isTag:
id = isTag.dataset.tag;
this.update({ isByTag: true, id });
default:
this.closeMenu();
break;
case !isTagWrapper && !isTag && !isMenuWrapper:
document.dispatchEvent(tagEvent);
document.dispatchEvent(menuEvent);
break;
default:
break;
}
});
}
@ -128,10 +122,6 @@ export default class BookSection {
<div class="main-book__menu_like ${
isFavorite ? "liked" : "not-liked"
}" data-like=${isFavorite} data-bookid=${id}></div>
<nav class="main-book__menu main-book__menu_closed"
data-bookid=${id}
data-menu></nav>
</div>
<div class="main-book__image mr-m">
<div class='d-fl'>
@ -170,7 +160,7 @@ export default class BookSection {
</p>
</div>
<div class="main-book__body body_closed mb-m mt-s">
<div data-tags-wrapper class="main-book__tags_wrapper"></div>
<div class="main-book__tags_wrapper"></div>
<div>
<span class="second-text">
${description || "Нет описания"}</span>
@ -197,17 +187,6 @@ export default class BookSection {
</article>`;
}
getMenuBody() {
return menuEnum
.map(({ label, id }) => {
return `
<li class="main-book__action second-text" id="main-book__action" data-action=${id}>
${label}
</li>`;
})
.join("");
}
getAuthors(authors) {
return (authors || [DEFAULT_AUTHOR])
.map(({ id, name }) => {
@ -217,29 +196,6 @@ export default class BookSection {
.join("");
}
openMenu(element) {
this.closeMenu();
element.classList.remove("main-book__menu_closed");
const divElement = document.createElement("ul");
divElement.innerHTML = this.getMenuBody();
element.append(divElement);
element.classList.add("main-book__menu_opened");
}
closeMenu() {
const elements = document.querySelectorAll(".main-book__menu_opened");
if (elements && elements.length) {
for (const subElement of elements) {
subElement.firstElementChild.remove();
subElement.classList.remove("main-book__menu_opened");
subElement.classList.add("main-book__menu_closed");
}
}
}
toggleDetails(element) {
const isOpened = element.classList.contains("opened");
const article = element.parentNode.parentNode;
@ -264,13 +220,23 @@ export default class BookSection {
const articles = document.querySelectorAll("[data-card]");
articles.forEach((article, i) => {
const tagWrapper = article.querySelector(".main-book__tags_wrapper");
const menuWrapper = article.querySelector(".main-book__menu_wrapper");
const bookid = article.dataset.bookid;
const { tags } = this.data[i] || [];
const { tags, isBlocked, hasReadLater, authors } = this.data[i] || [];
const tagsComponent = new TagsComponent({ tags, article, bookid });
const menuComponent = new MenuComponent({
isBlocked,
hasReadLater,
authors,
bookid,
article,
});
tagWrapper.append(tagsComponent.element);
menuWrapper.append(menuComponent.element);
// console.log('article.scrollHeight', article.scrollHeight);
if (article.scrollHeight > 502) {
if (article.scrollHeight > 424) {
const arrow = article.querySelector(".main-book__arrow_wrapper");
arrow.classList.remove("hidden");
}
@ -295,27 +261,26 @@ export default class BookSection {
const { bookid: likedBookId, like } = element.dataset || {};
const isLiked = like === "true";
if (!isLiked) {
await likeEnum[0].action({ bookid: likedBookId });
element.classList.remove("not-liked");
element.classList.add("liked");
} else {
if (isLiked) {
await likeEnum[1].action({ bookid: likedBookId });
element.classList.remove("liked");
element.classList.add("not-liked");
} else {
await likeEnum[0].action({ bookid: likedBookId });
element.classList.remove("not-liked");
element.classList.add("liked");
}
element.dataset.like = !isLiked;
this.data = this.data.map(({ isFavorite, id, ...rest }) =>
likedBookId === id
? { id, isFavorite: !isFavorite, ...rest }
? { id, ...rest, isFavorite: !isFavorite }
: {
id,
isFavorite,
...rest,
}
);
console.log("new data", this.data);
this.element.classList.remove("spinner");
}
@ -326,6 +291,8 @@ export default class BookSection {
this.data = await searchByAuthor({ id: params.id });
} else if (params?.isByTag) {
this.data = await searchByTag({ id: params.id });
} else if (params?.isByRandom) {
this.data = await fetchRandomData();
} else {
const query = params;
this.data = await fetchData({ query, url: this.url });
@ -335,10 +302,11 @@ export default class BookSection {
if (this.data && Object.values(this.data).length) {
this.subElements.body.innerHTML = this.getBookBody(this.data);
this.initialize();
await this.countHeight();
} else {
this.subElements.body.innerHTML = this.getEmptyBody();
}
await this.countHeight();
this.element.classList.remove("spinner");
}
@ -375,48 +343,50 @@ export default class BookSection {
}
}
// this.data = [
// {
// id: "2",
// authors: [{ id: "1", name: "123" }],
// description:
// "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.",
// format: "123",
// genres: [],
// imageUrl: "",
// title: "What is Lorem Ipsum?",
// series: [],
// subseries: [],
// year: 1992,
// tags: [
// { id: 1, name: "Интересно" },
// { id: 22, name: "Почитать" },
// { id: 155, name: "Рекомендовали" },
// { id: 166, name: "завтра" },
// { id: 11, name: "наверное" },
// { id: 221, name: "Почитданетать" },
// { id: 1515, name: "раздватри" },
// { id: 1661, name: "возможно" },
// ],
// isFavorite: true,
// },
// {
// id: "22",
// authors: [{ id: "1", name: "123" }],
// description:
// "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.",
// format: "123",
// genres: [],
// imageUrl: "",
// title: "dsfwqedwqefrwef",
// series: [],
// subseries: [],
// year: 1992,
// tags: [
// { id: 1, name: "Интересно" },
// { id: 22, name: "Почитать" },
// { id: 155, name: "Рекомендовали" },
// ],
// isFavorite: true,
// },
// ];
const testData = [
{
id: "2",
authors: [{ id: "1", name: "123" }],
description:
"Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.",
format: "123",
genres: [],
imageUrl: "",
title: "What is Lorem Ipsum?",
series: [],
subseries: [],
year: 1992,
tags: [
{ id: 1, name: "Интересно" },
{ id: 22, name: "Почитать" },
{ id: 155, name: "Рекомендовали" },
{ id: 166, name: "завтра" },
{ id: 11, name: "наверное" },
{ id: 221, name: "Почитданетать" },
{ id: 1515, name: "раздватри" },
{ id: 1661, name: "возможно" },
],
isFavorite: true,
hasReadLater: true,
isBlocked: true,
},
{
id: "22",
authors: [{ id: "1", name: "123" }],
description:
"Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.",
format: "123",
genres: [],
imageUrl: "",
title: "dsfwqedwqefrwef",
series: [],
subseries: [],
year: 1992,
tags: [
{ id: 1, name: "Интересно" },
{ id: 22, name: "Почитать" },
{ id: 155, name: "Рекомендовали" },
],
isFavorite: true,
},
];

@ -20,6 +20,24 @@ export const fetchData = ({ query, url }) => {
});
};
export const fetchRandomData = () => {
return $.ajax({
contentType: "application/json; charset=utf-8",
dataType: "json",
type: "POST",
url: "../api/books/qsearch",
success: function (data, textStatus, jqXHR) {
if (textStatus === SUCCESS) {
return data;
}
return [];
},
error: function (jqXHR, textStatus, errorThrown) {
console.log(jqXHR.statusText);
},
});
};
export const addBookToFavourites = ({ bookid }) => {
return $.ajax({
type: "POST",
@ -221,10 +239,6 @@ export const changeTags = ({ bookid, tags }) => {
console.log(jqXHR.statusText);
},
});
// return [
// {id: "6611598e1468849d1b00570d", name: "шиза"}
// ];
};
export const searchByTag = ({ id }) => {

@ -1,4 +1,4 @@
export const stopPropagation = event => {
event.stopImmediatePropagation();
event.stopPropagation();
}
export const stopPropagation = (event) => {
event.stopImmediatePropagation();
event.stopPropagation();
};

@ -1,14 +1,17 @@
import BookSection from "./js/main/index.js";
import ButtonScroll from './js/scroll/index.js';
import ButtonScroll from "./js/scroll/index.js";
const input = document.getElementById("search");
const books = document.getElementById("books");
const content = document.getElementById("content");
const searchButton = document.getElementById("searchButton");
const fortuneButton = document.getElementById("fortuneButton");
const booksSection = new BookSection({
url: "../api/books/search",
label: "books",
});
const click = () => {
const query = document.getElementById("search").value;
if (query) {
@ -16,8 +19,19 @@ const click = () => {
}
};
searchButton.addEventListener("click", click);
const fortuneClick = () => {
booksSection.update({ isByRandom: true });
};
searchButton.addEventListener("click", click);
fortuneButton.addEventListener("click", fortuneClick);
input.addEventListener("input", function (e) {
if (e.target.value && e.target.value.length !== 0) {
searchButton.classList.add("visible");
} else {
searchButton.classList.remove("visible");
}
});
input.addEventListener("keypress", function (event) {
if (event.key === "Enter") {
click();
@ -25,5 +39,5 @@ input.addEventListener("keypress", function (event) {
});
books.append(booksSection.element);
const scroll = new ButtonScroll()
content.append(scroll.element)
const scroll = new ButtonScroll();
content.append(scroll.element);

@ -1,52 +0,0 @@
const path = require('path');
const { createProxyMiddleware } = require('http-proxy-middleware');
const cors = require('cors');
const express = require('express');
const app = express();
const server = require('http').Server(app);
const router = require('express').Router()
const options = {
target: 'https://book.ogoun.name/', // target host
changeOrigin: true, // needed for virtual hosted sites
ws: true, // proxy websockets
logLevel: 'debug',
secure: false,
cookieDomainRewrite: {
'*': 'localhost',
},
onProxyRes(proxyRes, req, _res) {
if (proxyRes.headers['set-cookie'] !== undefined) {
req.cookie = proxyRes.headers['set-cookie'];
}
},
onProxyReq(proxyReq, req, _res) {
if (req && req.cookie !== undefined) {
proxyReq.setHeader('Cookie', req.cookie[0]);
}
},
};
const myLogger = function (req, res, next) {
next()
}
app.use(myLogger)
app.use(express.static(__dirname));
app.use(express.static(__dirname + '/js'));
app.use(express.static(__dirname + '/css'));
app.use(express.static(__dirname + '/constants'));
// app.get('/login', function (req, res) {
// res.sendFile(path.join(__dirname, '/login.html'));
// });
app.use('/', cors({
credentials: true,
origin: 'http://localhost:3000',
}), createProxyMiddleware(options));
server.listen(3001);

@ -2,6 +2,7 @@
using BukiVedi.Shared.Models;
using BukiVedi.Shared.Services;
using BukiVedi.Shared.Services.Mappers;
using ZeroLevel.Patterns.Queries;
using ZeroLevel.Services.FileSystem;
namespace BukiVedi.Shared.Apps
@ -176,6 +177,12 @@ namespace BukiVedi.Shared.Apps
return Enumerable.Empty<BookInfo>();
}
public async Task<IEnumerable<BookInfo>> SearchAI(OperationContext context)
{
var books = (await _library.SearchBooksAI(context.OperationInitiator.Id)).ToArray();
return await BookEntityMapper.Map(books, context);
}
public async Task UnblockBook(string id, OperationContext context)
{
var account_id = context.OperationInitiator.Id;

@ -5,6 +5,7 @@ namespace BukiVedi.Shared.Apps
public interface IBooksHandler
{
Task<IEnumerable<BookInfo>> Search(string query, string? tag, OperationContext context);
Task<IEnumerable<BookInfo>> SearchAI(OperationContext context);
Task AddToFavorite(string id, OperationContext context);
Task AddAuthorsToFavorite(string id, OperationContext context);
Task BlockBook(string id, OperationContext context);

@ -16,7 +16,7 @@ namespace BukiVedi.Shared
Task<long> Count(FilterDefinition<T> predicate);
Task<bool> Exists(FilterDefinition<T> filter);
Task<bool> ExistById(string id);
T[] GetRandomDocuments(int count);
Task<T> Write(T obj);

@ -13,6 +13,7 @@ namespace BukiVedi.Shared.Services
{
Task<IEnumerable<BookEntity>> SearchBooksByAuthor(string author_id);
Task<IEnumerable<BookEntity>> SearchBooks(string title);
Task<BookEntity[]> SearchBooksAI(string accountId);
Task<IEnumerable<BookEntity>> SearchByTagBooks(string accountId, string tagId);
Task<IEnumerable<BookEntity>> SearchTaggedBooks(string accountId, string tag = null!);
Task<IEnumerable<BookEntity>> SearchFavoritesBooks(string accountId);
@ -96,7 +97,7 @@ namespace BukiVedi.Shared.Services
public async Task<IEnumerable<BookEntity>> SearchFavoritesBooks(string accountId)
{
IEnumerable<string> bookIds = (await Tables.FavoriteBooks.Get(Filters.FavoriteBooks.ByUser(accountId)))?.Select(t => t.BookId)?.ToHashSet()!;
if (bookIds != null && bookIds.Any())
{
@ -149,7 +150,7 @@ namespace BukiVedi.Shared.Services
{
IEnumerable<string> bookIds;
if (string.IsNullOrWhiteSpace(tag))
{
{
bookIds = (await Tables.UserTag.Get(Filters.Tags.ByUser(accountId)))?.Select(t => t.BookId)?.ToHashSet()!;
}
else
@ -439,5 +440,27 @@ namespace BukiVedi.Shared.Services
await Tables.Books.Write(book);
}
}
public Task<BookEntity[]> SearchBooksAI(string accountId)
{
var books = Tables.Books.GetRandomDocuments(50);
var result = new BookEntity[books.Length];
int index = 0;
foreach (var b in books)
{
result[index] = new BookEntity
{
Authors = GetAuthors(b),
Title = b.Title,
Year = b.Year,
Description = b.Description,
Format = b.Format,
Genre = new Genre(),
Id = b.Id,
};
index++;
}
return Task.FromResult(result);
}
}
}

@ -1,6 +1,7 @@
using BukiVedi.Shared.Entities;
using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
using System.Linq.Expressions;
using ZeroLevel.Services.FileSystem;
@ -104,6 +105,12 @@ namespace BukiVedi.Shared.Services.MongoDB
return result.ToEnumerable().ToArray();
}
public T[] GetRandomDocuments(int count)
{
var result = _collection.AsQueryable().Sample(count);
return result.ToArray();
}
public async Task<long> Count(FilterDefinition<T> filter)
{
return await _collection.CountDocumentsAsync(filter);

@ -14,7 +14,7 @@ using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("BukiVedi.Shared")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+78ef654d3cca93dcdff7557d9a44da30b9d10a6a")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+708729b3f0a4a46b4ed8277753e30266f9b02ae4")]
[assembly: System.Reflection.AssemblyProductAttribute("BukiVedi.Shared")]
[assembly: System.Reflection.AssemblyTitleAttribute("BukiVedi.Shared")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]

@ -1 +1 @@
43fea615f27b115ca71adae9d28aa42c583a4dce3ecf8ac2e68c45249fa1eb8e
47f2ecfa029d676b8f2f23a9542e5f91afdb2a5aba3b39b9691101443bb7f9e8

Loading…
Cancel
Save

Powered by TurnKey Linux.