mirror of
https://github.com/ivabus/www
synced 2024-11-24 15:55:05 +03:00
Merge pull request #186 from teaxyz/fuzzy-filter-packages
Fuzzy filter packages
This commit is contained in:
commit
e7ae5f5ed5
8 changed files with 233 additions and 80 deletions
|
@ -5,6 +5,8 @@ base = "./public"
|
|||
exclude-mail = true
|
||||
include = ["./public/**/*.md", "./public/**/*.html"]
|
||||
exclude = [
|
||||
"https://github.com/",
|
||||
"https://twitter.com/",
|
||||
"https://fonts.gstatic.com/",
|
||||
"https://fonts.googleapis.com/",
|
||||
"https://www.clarity.ms/tag/",
|
||||
|
|
|
@ -94,7 +94,12 @@
|
|||
<!-- Style for Swiper -->
|
||||
|
||||
<style>
|
||||
|
||||
.swiper-package-display{
|
||||
display:block;
|
||||
}
|
||||
.grid-package-display{
|
||||
display:none;
|
||||
}
|
||||
@media only screen and (min-width: 576px) {
|
||||
|
||||
.grid-package-display{
|
||||
|
@ -105,51 +110,6 @@
|
|||
display:none;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 576px) {
|
||||
|
||||
.grid-package-display{
|
||||
display:none;
|
||||
}
|
||||
|
||||
.swiper-package-display{
|
||||
display:block;
|
||||
}
|
||||
}
|
||||
|
||||
.swiper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin-bottom: 1vw !important;
|
||||
margin-top: 1vw;
|
||||
}
|
||||
|
||||
.swiper-slide {
|
||||
text-align: center;
|
||||
font-size: 18px;
|
||||
|
||||
/* Center slide text vertically */
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
justify-content: center;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.swiper-slide figure > img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<!-- Package CTA Section -->
|
||||
|
|
|
@ -39,7 +39,6 @@
|
|||
</div>
|
||||
</section>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/swiper/swiper-bundle.min.js"></script>
|
||||
|
||||
<!-- JavaScript Bundle with Popper -->
|
||||
|
||||
|
@ -146,19 +145,6 @@ integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+
|
|||
rdt('track', 'ViewContent');
|
||||
</script>
|
||||
|
||||
<script>
|
||||
var swiper = new Swiper(".mySwiper", {
|
||||
slidesPerView: 1.5,
|
||||
spaceBetween: 10,
|
||||
freeMode: true,
|
||||
loop: true,
|
||||
pagination: {
|
||||
el: ".swiper-pagination",
|
||||
clickable: true,
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
|
||||
const url = 'https://tea.breezy.hr/json?verbose=true';
|
||||
|
|
|
@ -1,17 +1,19 @@
|
|||
<!-- Package Grid -->
|
||||
|
||||
<section>
|
||||
|
||||
<!-- Package Grid Header -->
|
||||
<hr>
|
||||
<div class="container package-grid-header">
|
||||
<section class="flex">
|
||||
<div class="container package-grid-header two-boxes">
|
||||
<section class="flex flex-column flex-md-row">
|
||||
<h3>packages</h3>
|
||||
{{- partial "sort-dropdown.html" -}}
|
||||
</section>
|
||||
<p style="width:60%;">There are already plenty of packages available through tea. As the communi’tea builds the library, contributions will live here. We use <a href="https://stability.ai/blog/stable-diffusion-public-release">Stable Diffusion</a> to generate the artwork for each package using their title and code for input. That’s the power of Open Source.</p>
|
||||
</div>
|
||||
<hr>
|
||||
|
||||
{{- partial "search-menu.html" "searchTermDesktop" -}}
|
||||
<hr>
|
||||
|
||||
<div class="package-grid">
|
||||
|
||||
<!-- Start Package Grid -->
|
||||
|
@ -90,7 +92,7 @@
|
|||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script async src="https://unpkg.com/string-similarity@4.0.1/umd/string-similarity.min.js"></script>
|
||||
<script language="javascript" type="text/javascript">
|
||||
const sortOptions = {
|
||||
popularity: 'popularity',
|
||||
|
@ -100,16 +102,60 @@
|
|||
let sortDirection = 'desc'; // asc
|
||||
let limit = 16;
|
||||
|
||||
const grid = document.getElementById('packageGrid');
|
||||
const packagesCache = Array.from(grid.children).filter((e) => e.dataset && e.dataset.name);
|
||||
|
||||
function debounce(fn, delay) {
|
||||
var timer = null;
|
||||
return function () {
|
||||
var context = this, args = arguments;
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(function () {
|
||||
fn.apply(context, args);
|
||||
}, delay);
|
||||
};
|
||||
}
|
||||
|
||||
const onSearch = debounce(() => {
|
||||
const searchInput = document.getElementById('searchTermDesktop');
|
||||
if (searchInput.value) {
|
||||
const term = searchInput.value;
|
||||
const packages = getPackageThumbs();
|
||||
const sortedPackages = packages.sort((a, b) => {
|
||||
const aScore = getMatchScore(term, a.dataset);
|
||||
const bScore = getMatchScore(term, b.dataset);
|
||||
return bScore - aScore;
|
||||
});
|
||||
const grid = document.getElementById('packageGrid');
|
||||
grid.textContent = '';
|
||||
for(const sp of sortedPackages) {
|
||||
const score = getMatchScore(term, sp.dataset);
|
||||
if (score > 20) {
|
||||
sp.classList.remove('hidden');
|
||||
} else {
|
||||
sp.classList.add('hidden');
|
||||
}
|
||||
grid.appendChild(sp);
|
||||
}
|
||||
} else {
|
||||
sortPackages();
|
||||
}
|
||||
}, 300);
|
||||
|
||||
const searchInputDesktop = document.getElementById('searchTermDesktop');
|
||||
searchInputDesktop.addEventListener("search", onSearch);
|
||||
searchInputDesktop.addEventListener("change", onSearch);
|
||||
searchInputDesktop.addEventListener("keyup", onSearch);
|
||||
|
||||
function getPackageThumbs() {
|
||||
const grid = document.getElementById('packageGrid');
|
||||
return Array.from(grid.children).filter((e) => e.dataset && e.dataset.name);
|
||||
// const grid = document.getElementById('packageGrid');
|
||||
return packagesCache;
|
||||
}
|
||||
|
||||
const packagesCount = getPackageThumbs().length;
|
||||
|
||||
function sortPackages() {
|
||||
const packages = getPackageThumbs();
|
||||
|
||||
const sortedPackages = packages.sort((a, b) => {
|
||||
if (sortBy === sortOptions.popularity) {
|
||||
const aPop = +a.dataset.popularity;
|
||||
|
@ -149,6 +195,14 @@
|
|||
}
|
||||
}
|
||||
|
||||
function getMatchScore(term, dataset) {
|
||||
// provide higher value with name
|
||||
const { name, description } = dataset;
|
||||
const nameScore = stringSimilarity.compareTwoStrings(name, term);
|
||||
const descriptionScore = stringSimilarity.compareTwoStrings(description, term);
|
||||
return (nameScore*80) + (descriptionScore*20)
|
||||
}
|
||||
|
||||
const loadMoreButton = document.getElementById('loadMorePackagesBtn');
|
||||
loadMoreButton.addEventListener('click',() => {
|
||||
limit += 16;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<div class="card card-thumbnail" style="width: 100%" data-name="{{- .name -}}" data-popularity="{{- .dl_count -}}" data-last_modified="{{- .last_modified -}}">
|
||||
<div class="card card-thumbnail" style="width: 100%" data-name="{{- .name -}}" data-popularity="{{- .dl_count -}}" data-last_modified="{{- .last_modified -}}" data-description="{{- .desc -}}">
|
||||
<figure class="card-img-top" >
|
||||
<img class="package-image" src="{{- .thumb_image_url -}}" alt="{{- .name -}}" style="width:100%; height:100%;">
|
||||
<article class="card-thumb-label">
|
||||
|
|
53
src/layouts/partials/search-menu.html
Normal file
53
src/layouts/partials/search-menu.html
Normal file
|
@ -0,0 +1,53 @@
|
|||
<section>
|
||||
<div class="button-container">
|
||||
<div class="searchBar">
|
||||
<div style="display:flex; align-items:center;">
|
||||
<div class="icon">
|
||||
<i class="icon-search-icon"></i>
|
||||
</div>
|
||||
<input id="{{- . -}}" type="search" placeholder="search_" />
|
||||
</div>
|
||||
{{- partial "sort-dropdown.html" -}}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
|
||||
.icon-search-icon{
|
||||
font-size: 30px;
|
||||
color: #949494;
|
||||
margin-right: 20px;
|
||||
position: relative;
|
||||
top: 2px;
|
||||
}
|
||||
|
||||
.searchBar {
|
||||
padding: 0px;
|
||||
height: 150px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.searchBar .sorting-container {
|
||||
min-width: 260px;
|
||||
}
|
||||
.searchBar input {
|
||||
font-size: 32px;
|
||||
font-family: "pp-neue-machina", sans-serif;
|
||||
color:#00ffd0;
|
||||
text-transform:uppercase;
|
||||
margin-bottom: -5px;
|
||||
min-width: 60%;
|
||||
padding: 0px;
|
||||
background-color: #1a1a1a !important;
|
||||
border: none;
|
||||
color: #00ffd0;
|
||||
outline: none;
|
||||
border-radius: 0px;
|
||||
}
|
||||
.searchBar input::placeholder { /* Chrome, Firefox, Opera, Safari 10.1+ */
|
||||
color: #949494;
|
||||
opacity: 1; /* Firefox */
|
||||
}
|
||||
</style>
|
|
@ -1,6 +1,13 @@
|
|||
<style>
|
||||
.sorting-container{
|
||||
display:inline-block;
|
||||
display:none;
|
||||
}
|
||||
@media only screen and (min-width: 576px) {
|
||||
.sorting-container{
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
.sorting-container{
|
||||
font-family: "pp-neue-machina", sans-serif;
|
||||
background-color: #1a1a1a;
|
||||
border: 1px solid #ffffff;
|
||||
|
|
|
@ -5,19 +5,110 @@
|
|||
</div>
|
||||
<hr>
|
||||
|
||||
{{- partial "search-menu.html" "searchTermMobile" -}}
|
||||
<hr>
|
||||
<!-- Slider main container -->
|
||||
|
||||
<div class="row" style="margin-bottom: 2vw !important;">
|
||||
<div class="col">
|
||||
<div class="swiper mySwiper">
|
||||
<div class="swiper-wrapper">
|
||||
{{ range $.Site.Data.packages }}
|
||||
<div class="swiper-slide">
|
||||
<div class="row" style="margin-bottom: 2vw !important;">
|
||||
<div class="col">
|
||||
<div class="swiper mySwiper">
|
||||
<div id="parentSwiper" class="swiper-wrapper">
|
||||
{{ range $.Site.Data.packages }}
|
||||
<div class="swiper-slide">
|
||||
{{- partial "package-thumbnail.html" .}}
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
<!--<div class="swiper-pagination"></div>-->
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
<!--<div class="swiper-pagination"></div>-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<style>
|
||||
.swiper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin-bottom: 1vw !important;
|
||||
margin-top: 1vw;
|
||||
}
|
||||
|
||||
.swiper-slide {
|
||||
text-align: center;
|
||||
font-size: 18px;
|
||||
|
||||
/* Center slide text vertically */
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
justify-content: center;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.swiper-slide figure > img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
</style>
|
||||
<script src="https://cdn.jsdelivr.net/npm/swiper/swiper-bundle.min.js"></script>
|
||||
<script>
|
||||
let swipeyPackagesCache;
|
||||
const swiper = new Swiper(".mySwiper", {
|
||||
slidesPerView: 1.5,
|
||||
spaceBetween: 10,
|
||||
freeMode: true,
|
||||
loop: false,
|
||||
pagination: {
|
||||
el: ".swiper-pagination",
|
||||
clickable: true,
|
||||
},
|
||||
on: {
|
||||
afterInit: () => {
|
||||
const swiperParent = document.getElementById('parentSwiper');
|
||||
swipeyPackagesCache = Array.from(swiperParent.children)
|
||||
.filter((e) => e.childNodes[0].dataset.popularity)
|
||||
.map((e) => {
|
||||
e.classList = ['swiper-slide'];
|
||||
return e;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
const onSearchMobile = debounce(async () => {
|
||||
const searchInput = document.getElementById('searchTermMobile');
|
||||
if (searchInput.value) {
|
||||
const term = searchInput.value;
|
||||
const packages = [...swipeyPackagesCache];
|
||||
const sortedPackages = packages.sort((a, b) => {
|
||||
const aScore = getMatchScore(term, a.childNodes[0].dataset);
|
||||
const bScore = getMatchScore(term, b.childNodes[0].dataset);
|
||||
return bScore - aScore;
|
||||
});
|
||||
swiper.removeAllSlides();
|
||||
for(const sp of sortedPackages) {
|
||||
const score = getMatchScore(term, sp.childNodes[0].dataset);
|
||||
if (score > 20) {
|
||||
swiper.addSlide(1, sp);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const recache = [...swipeyPackagesCache];
|
||||
await swiper.removeAllSlides();
|
||||
swiper.appendSlide(recache);
|
||||
}
|
||||
}, 300);
|
||||
|
||||
const searchInputMobile = document.getElementById('searchTermMobile');
|
||||
searchInputMobile.addEventListener("search", onSearchMobile);
|
||||
searchInputMobile.addEventListener("change", onSearchMobile);
|
||||
searchInputMobile.addEventListener("keyup", onSearchMobile);
|
||||
</script>
|
Loading…
Reference in a new issue