fuzzy-searching, parallax
This commit is contained in:
parent
5a1467c971
commit
817057a861
5
package-lock.json
generated
5
package-lock.json
generated
@ -2736,6 +2736,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"mongoose-fuzzy-searching": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/mongoose-fuzzy-searching/-/mongoose-fuzzy-searching-1.3.1.tgz",
|
||||
"integrity": "sha512-Vi+EwmYPoxZzgwBOuTg5FBjXqbX1gjbXxvX/4Ypo7yC2aGKwKfgEeenAVwU6DPirL/TDj6jLGEoblzMJ3+HWCg=="
|
||||
},
|
||||
"mongoose-legacy-pluralize": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz",
|
||||
|
@ -21,6 +21,7 @@
|
||||
"express": "^4.17.1",
|
||||
"express-session": "^1.17.1",
|
||||
"mongoose": "^5.9.18",
|
||||
"mongoose-fuzzy-searching": "^1.3.1",
|
||||
"multer": "^1.4.2",
|
||||
"passport": "^0.4.1",
|
||||
"passport-local": "^1.0.0",
|
||||
|
@ -1,6 +1,15 @@
|
||||
<script>
|
||||
import { stores } from '@sapper/app';
|
||||
import { stores, goto } from '@sapper/app';
|
||||
const { session } = stores();
|
||||
|
||||
let query = '';
|
||||
|
||||
function search(e)
|
||||
{
|
||||
if (e.keyCode === 13) {
|
||||
goto(`/search/${encodeURIComponent(query)}`);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@ -23,11 +32,10 @@
|
||||
padding: 0 1.5rem 0.25rem;
|
||||
align-items: start;
|
||||
}
|
||||
div.filler {
|
||||
div.search {
|
||||
flex: 1 0 0;
|
||||
}
|
||||
div.items div {
|
||||
display: block;
|
||||
margin: auto 0;
|
||||
display: flex;
|
||||
}
|
||||
div.link a {
|
||||
text-decoration: none;
|
||||
@ -48,12 +56,21 @@
|
||||
margin-left: 4rem;
|
||||
}
|
||||
}
|
||||
input.search {
|
||||
height: 1.5rem;
|
||||
width: 50%;
|
||||
font-size: 1rem;
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
<nav>
|
||||
<div class="items">
|
||||
<div><a href="/"><img class="wordmark" src="/logo.png" alt="HowFeed.biz"></a></div>
|
||||
<div class="filler"></div>
|
||||
<div class="search">
|
||||
<input class="search" on:keyup={search} bind:value={query} type="text" placeholder="Search">
|
||||
</div>
|
||||
{#if !$session.user}
|
||||
<div class="link"><a href="/contact">Contact Us</a></div>
|
||||
{:else}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import mongoose from 'mongoose';
|
||||
import mongoose_fuzzy_searching from 'mongoose-fuzzy-searching';
|
||||
|
||||
const { Schema } = mongoose;
|
||||
const ArticleSchema = new Schema({
|
||||
@ -28,13 +29,18 @@ const ArticleSchema = new Schema({
|
||||
|
||||
ArticleSchema.methods.genSlug = title => title.toLowerCase().replace(/\W+/g, '-');
|
||||
|
||||
ArticleSchema.pre('save', function (next) {
|
||||
var article = this;
|
||||
// only gen the slug if title has been modified (or is new)
|
||||
if (!article.isModified('title')) return next();
|
||||
ArticleSchema.plugin(mongoose_fuzzy_searching, {
|
||||
fields: ['html', 'title'],
|
||||
middlewares: {
|
||||
preSave: function () {
|
||||
var article = this;
|
||||
// only gen the slug if title has been modified (or is new)
|
||||
if (!article.isModified('title'))
|
||||
return;
|
||||
|
||||
article.slug = article.genSlug(article.title);
|
||||
next();
|
||||
article.slug = article.genSlug(article.title);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export default mongoose.model('Article', ArticleSchema);
|
||||
|
@ -83,7 +83,7 @@
|
||||
async function addCategory()
|
||||
{
|
||||
let name = prompt('Enter a category name');
|
||||
if (name) {
|
||||
if (name !== null) {
|
||||
const res = await fetch('/cms/category', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
@ -92,8 +92,13 @@
|
||||
},
|
||||
body: JSON.stringify({ name })
|
||||
});
|
||||
categories = await res.json();
|
||||
category = categories.filter(c => c.name === name)[0].slug;
|
||||
const json = await res.json();
|
||||
if (res.status === 200) {
|
||||
categories = json;
|
||||
category = categories.filter(c => c.name === name)[0].slug;
|
||||
} else {
|
||||
alert(`Error ${res.status}: ${json.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -36,7 +36,7 @@
|
||||
<h3>James N. Shiffer</h3>
|
||||
<p>Webmaster</p>
|
||||
<p>FemboyFinancial Holdings Co., Ltd. (USA LLC)</p>
|
||||
<p><a href="mailto:webmaster@femboyfashion.com.hk">webmaster@femboyfashion.com.hk</a></p>
|
||||
<p><a href="mailto:webmaster@howfeed.biz">webmaster@howfeed.biz</a></p>
|
||||
</div>
|
||||
</div>
|
||||
<div style="max-width:100%;margin:0 auto;width:700px;height:440px;">
|
||||
|
55
src/routes/search/[query].svelte
Normal file
55
src/routes/search/[query].svelte
Normal file
@ -0,0 +1,55 @@
|
||||
<script context="module">
|
||||
export async function preload({ params })
|
||||
{
|
||||
let query = params.query;
|
||||
const res = await this.fetch(`/search.json?query=${encodeURIComponent(query)}`);
|
||||
const json = await res.json();
|
||||
if (res.status === 200) {
|
||||
return { query, results: json };
|
||||
} else {
|
||||
this.error(res.status, res.message);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
export let query;
|
||||
export let results;
|
||||
</script>
|
||||
|
||||
<style>
|
||||
h1 {
|
||||
margin: 0 auto;
|
||||
color: whitesmoke;
|
||||
margin-top: 1rem;
|
||||
font-size: 2rem;
|
||||
font-size: 3rem;
|
||||
text-transform: uppercase;
|
||||
text-align: center;
|
||||
max-width: 80%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<svelte:head>
|
||||
<title>Search Results for: {query} | HOWFEED.BIZ</title>
|
||||
</svelte:head>
|
||||
|
||||
<div class="background"></div>
|
||||
<div class="floaty">
|
||||
<h1>Search Results for: {query}</h1>
|
||||
<div class="article-list">
|
||||
{#each results as {title, slug, image, created_at}}
|
||||
<a rel="prefetch" href={`/a/${slug}`}>
|
||||
<figure class="article-image">
|
||||
<img src={image || '/logo.png'} alt={title}>
|
||||
</figure>
|
||||
<div class="article-meta">
|
||||
<p class="article-title">{title}</p>
|
||||
<p class="article-date">{new Date(created_at).toLocaleDateString()}</p>
|
||||
</div>
|
||||
</a>
|
||||
{:else}
|
||||
<p>No results found :(</p>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
20
src/routes/search/index.json.js
Normal file
20
src/routes/search/index.json.js
Normal file
@ -0,0 +1,20 @@
|
||||
import Article from '../../models/article.js';
|
||||
|
||||
export async function get(req, res)
|
||||
{
|
||||
const { query } = req.query;
|
||||
if (!query) {
|
||||
res.writeHead(422, {
|
||||
'Content-Type': 'application/json'
|
||||
});
|
||||
res.end(JSON.stringify({
|
||||
message: `No search query provided`
|
||||
}));
|
||||
return;
|
||||
}
|
||||
const results = await Article.fuzzySearch(query);
|
||||
res.writeHead(200, {
|
||||
'Content-Type': 'application/json'
|
||||
});
|
||||
res.end(JSON.stringify(results));
|
||||
}
|
18
src/routes/search/index.svelte
Normal file
18
src/routes/search/index.svelte
Normal file
@ -0,0 +1,18 @@
|
||||
<script>
|
||||
import { goto } from '@sapper/app';
|
||||
|
||||
let query = '';
|
||||
</script>
|
||||
|
||||
<style>
|
||||
input {
|
||||
width: 440px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="content">
|
||||
<h1>Search Results</h1>
|
||||
<p>You haven't entered any search terms.</p>
|
||||
<input type="text" placeholder="Search Articles" bind:value={query}>
|
||||
<button type="submit" on:click={() => { goto(`/search/${encodeURIComponent(query)}`); }}>Search</button>
|
||||
</div>
|
@ -115,6 +115,7 @@ div.article-meta {
|
||||
div.background {
|
||||
background: url('/cityscape.jpg') no-repeat center;
|
||||
background-size: cover;
|
||||
background-attachment: fixed;
|
||||
position: fixed;
|
||||
height: 24rem;
|
||||
width: 100%;
|
||||
|
Loading…
x
Reference in New Issue
Block a user