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