completed categories feature

This commit is contained in:
James Shiffer 2020-06-22 11:59:54 -07:00
parent 03f01f65d3
commit 9f2b80a924
No known key found for this signature in database
GPG Key ID: C0DB8774A1B3BA45
7 changed files with 123 additions and 51 deletions

View File

@ -3,7 +3,7 @@ import mongoose from 'mongoose';
const { Schema } = mongoose; const { Schema } = mongoose;
const CategorySchema = new Schema({ const CategorySchema = new Schema({
name: { type: String, required: true, index: { unique: true } }, name: { type: String, required: true, index: { unique: true } },
slug: { type: String, required: true, index: { unique: true } } slug: { type: String, index: { unique: true } }
}); });

View File

@ -4,11 +4,11 @@ import Category from '../../models/category.js';
export async function get(req, res) export async function get(req, res)
{ {
let { slug } = req.params; let { slug } = req.params;
let articles; let articles, cat;
if (slug === 'all') { if (slug === 'all') {
articles = await Article.find().sort({ created_at: 'desc' }); articles = await Article.find().sort({ created_at: 'desc' }).populate({ path: 'category' });
} else { } else {
let cat = await Category.findOne({ slug }); cat = await Category.findOne({ slug });
if (!cat) { if (!cat) {
res.writeHead(404, { res.writeHead(404, {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
@ -18,11 +18,13 @@ export async function get(req, res)
})); }));
return; return;
} else { } else {
articles = await Article.find({ category: cat.id }).sort({ created_at: 'desc' }); articles = await Article.find({ category: cat.id })
.sort({ created_at: 'desc' })
.populate({ path: 'category' });
} }
} }
res.writeHead(200, { res.writeHead(200, {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
}); });
res.end(JSON.stringify(articles)); res.end(JSON.stringify({ category: cat, articles }));
} }

View File

@ -0,0 +1,70 @@
<script context="module">
export async function preload({ params, query }) {
if (params.slug === 'all') {
this.redirect(302, '/');
}
const res = await this.fetch(`c/${params.slug}.json`);
const data = await res.json();
if (res.status === 200) {
return {
articles: data.articles,
category: data.category
};
} else {
this.error(res.status, data.message);
}
}
</script>
<svelte:head>
<title>{category.name} Articles | HOWFEED.BIZ</title>
</svelte:head>
<style>
h1 {
margin: 0 auto;
color: whitesmoke;
margin-top: 1rem;
font-size: 2rem;
font-size: 3rem;
text-transform: uppercase;
text-align: center;
}
@media (min-width: 800px) {
h1 {
font-size: 4rem !important;
}
}
@media (min-width: 1280px) {
h1 {
font-size: 8rem !important;
}
}
</style>
<script>
export let articles;
export let category;
</script>
<div class="background"></div>
<div class="floaty">
<h1>{category.name}</h1>
<div class="article-list">
{#each articles 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 articles are in this category :(</p>
<p>Check back soon!</p>
{/each}
</div>
</div>

View File

@ -70,7 +70,7 @@
'Accept': 'application/json', 'Accept': 'application/json',
'Content-Type': 'application/json' 'Content-Type': 'application/json'
}, },
body: JSON.stringify({ html, image, title }) body: JSON.stringify({ html, image, title, category })
}); });
const json = await res.json(); const json = await res.json();
goto(`/a/${json.slug}`); goto(`/a/${json.slug}`);
@ -89,6 +89,7 @@
body: JSON.stringify({ name }) body: JSON.stringify({ name })
}); });
categories = await res.json(); categories = await res.json();
category = categories.filter(c => c.name === name)[0].slug;
} }
} }
</script> </script>

View File

@ -2,7 +2,7 @@
export async function preload() export async function preload()
{ {
const res = await this.fetch(`/c/all.json`); const res = await this.fetch(`/c/all.json`);
const articles = await res.json(); const { articles } = await res.json();
return { articles }; return { articles };
} }
</script> </script>
@ -19,22 +19,7 @@
h1, h2, p { h1, h2, p {
margin: 0 auto; margin: 0 auto;
} }
h1 {
font-size: 3rem;
text-transform: uppercase;
}
figure {
margin: 0;
}
img {
object-fit: contain;
max-width: 100%;
margin: 1rem;
}
@media (min-width: 800px) { @media (min-width: 800px) {
div.homepage {
padding-top: 5rem !important;
}
h1.welcome { h1.welcome {
font-size: 8rem !important; font-size: 8rem !important;
} }
@ -50,42 +35,19 @@
font-size: 3.5rem !important; font-size: 3.5rem !important;
} }
} }
div.background {
background: url('/cityscape.jpg') no-repeat center;
background-size: cover;
position: fixed;
height: 24rem;
width: 100%;
z-index: 0;
filter: blur(5px);
}
div.homepage {
padding-top: 8rem;
padding-bottom: 4rem;
position: absolute;
z-index: 1;
margin: 0 auto;
width: 100%;
}
h1.welcome, h2.desc { h1.welcome, h2.desc {
color: whitesmoke; color: whitesmoke;
} }
h1.welcome { h1.welcome {
margin-top: 1rem; margin-top: 1rem;
font-size: 3.75rem; font-size: 3.75rem;
} font-size: 3rem;
h2 {
text-transform: uppercase; text-transform: uppercase;
} }
h2.desc { h2.desc {
margin-bottom: 1rem; margin-bottom: 1rem;
font-size: 1.5rem; font-size: 1.5rem;
} text-transform: uppercase;
div.article-list {
box-shadow: 0 0 5px #000;
}
div.article-meta {
font-weight: bold;
} }
</style> </style>
@ -94,7 +56,7 @@
</svelte:head> </svelte:head>
<div class="background"></div> <div class="background"></div>
<div class="homepage"> <div class="floaty">
<h1 class="welcome">Welcome</h1> <h1 class="welcome">Welcome</h1>
<h2 class="desc">Find an Article</h2> <h2 class="desc">Find an Article</h2>
<div class="article-list"> <div class="article-list">
@ -110,7 +72,7 @@
</a> </a>
{:else} {:else}
<p>No articles have been published yet :(</p> <p>No articles have been published yet :(</p>
<p>Come back soon!</p> <p>Chcek back soon!</p>
{/each} {/each}
</div> </div>
</div> </div>

View File

@ -257,10 +257,10 @@ express()
} }
const cat = await new Category({ name }); const cat = await new Category({ name });
await cat.save(); await cat.save();
const categories = await Category.find();
res.writeHead(200, { res.writeHead(200, {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
}); });
const categories = await Category.find();
res.end(JSON.stringify(categories)); res.end(JSON.stringify(categories));
} catch (err) { } catch (err) {
res.writeHead(500, { res.writeHead(500, {

View File

@ -80,10 +80,14 @@ figure.article-image {
align-self: center; align-self: center;
justify-content: center; justify-content: center;
width: 33.33%; width: 33.33%;
margin: 0;
} }
figure.article-image img { figure.article-image img {
height: 6rem; height: 6rem;
width: auto; width: auto;
object-fit: contain;
max-width: 100%;
margin: 1rem;
} }
div.article-meta { div.article-meta {
margin: 1rem; margin: 1rem;
@ -95,9 +99,11 @@ div.article-meta {
} }
.article-title { .article-title {
font-size: 2rem; font-size: 2rem;
margin: 0 auto;
} }
.article-date { .article-date {
font-size: 1rem; font-size: 1rem;
margin: 0 auto;
} }
.content { .content {
@ -105,3 +111,34 @@ div.article-meta {
margin: 8rem 0; margin: 8rem 0;
padding: 2rem; padding: 2rem;
} }
div.background {
background: url('/cityscape.jpg') no-repeat center;
background-size: cover;
position: fixed;
height: 24rem;
width: 100%;
z-index: 0;
filter: blur(5px);
}
div.article-list {
box-shadow: 0 0 5px #000;
}
div.article-meta {
font-weight: bold;
}
div.floaty {
padding-top: 8rem;
padding-bottom: 4rem;
position: absolute;
z-index: 1;
margin: 0 auto;
width: 100%;
}
@media (min-width: 800px) {
div.floaty {
padding-top: 5rem !important;
}
}