forked from tanner/qotnews
parent
60e34935ee
commit
8115d86335
17 changed files with 352 additions and 304 deletions
@ -0,0 +1,52 @@ |
||||
<script> |
||||
import StoryInfo from "../components/StoryInfo.svelte"; |
||||
export let story; |
||||
|
||||
let host = new URL(story.url || story.link).hostname.replace(/^www\./, ""); |
||||
</script> |
||||
|
||||
<style> |
||||
.article-title { |
||||
text-align: justify; |
||||
} |
||||
.article-header { |
||||
padding: 0 0 1rem; |
||||
} |
||||
.article-body { |
||||
max-width: 45rem; |
||||
margin: 0 auto; |
||||
} |
||||
.article-body :global(figure) { |
||||
margin: 0; |
||||
} |
||||
.article-body :global(figcaption p), |
||||
.article-body :global(figcaption) { |
||||
padding: 0; |
||||
margin: 0; |
||||
} |
||||
.article-body :global(figcaption) { |
||||
font-style: italic; |
||||
margin: 0 1rem; |
||||
font-size: 0.9em; |
||||
text-align: justify; |
||||
} |
||||
.article-body :global(figure), |
||||
.article-body :global(img) { |
||||
max-width: 100%; |
||||
height: auto; |
||||
} |
||||
</style> |
||||
|
||||
<article class="article"> |
||||
<header class="article-header"> |
||||
<h1 class="article-title">{story.title}</h1> |
||||
{#if story.url} |
||||
<div>source: <a href={story.url}>{host}</a></div> |
||||
{/if} |
||||
<StoryInfo class="article-byline" {story} /> |
||||
</header> |
||||
|
||||
<section class="article-body"> |
||||
{@html story.text} |
||||
</section> |
||||
</article> |
@ -0,0 +1,55 @@ |
||||
<script> |
||||
import { stores } from "@sapper/app"; |
||||
export let href; |
||||
export let search; |
||||
export let count; |
||||
|
||||
const { page } = stores(); |
||||
|
||||
let skip = 0; |
||||
let limit = 20; |
||||
let prevLink = ""; |
||||
let nextLink = ""; |
||||
|
||||
page.subscribe((p) => { |
||||
count = Number(count); |
||||
skip = Number(p.query.skip) || 0; |
||||
limit = Number(p.query.limit) || 20; |
||||
|
||||
let previous = new URLSearchParams(search || ""); |
||||
let next = new URLSearchParams(search || ""); |
||||
|
||||
previous.append("skip", skip - Math.min(skip, limit)); |
||||
previous.append("limit", limit); |
||||
|
||||
next.append("skip", skip + limit); |
||||
next.append("limit", limit); |
||||
|
||||
prevLink = href + "?" + previous.toString(); |
||||
nextLink = href + "?" + next.toString(); |
||||
}); |
||||
</script> |
||||
|
||||
<style> |
||||
.pagination { |
||||
margin: 3rem 0; |
||||
display: flex; |
||||
flex-direction: row; |
||||
justify-content: space-between; |
||||
} |
||||
.pagination-link.is-next { |
||||
margin-left: auto; |
||||
} |
||||
</style> |
||||
|
||||
<div class="pagination"> |
||||
{#if skip > 0} |
||||
<a |
||||
class="pagination-link is-prev" |
||||
href={prevLink} |
||||
rel="prefetch">Previous</a> |
||||
{/if} |
||||
{#if count >= limit} |
||||
<a class="pagination-link is-next" href={nextLink} rel="prefetch">Next</a> |
||||
{/if} |
||||
</div> |
@ -1,26 +1,18 @@ |
||||
<script> |
||||
import fromUnixTime from "date-fns/fromUnixTime"; |
||||
import formatDistanceToNow from "date-fns/formatDistanceToNow"; |
||||
import Time from "../components/Time.svelte"; |
||||
export let story; |
||||
export let dateString = formatDistanceToNow(fromUnixTime(story.date), { |
||||
addSuffix: true, |
||||
}); |
||||
</script> |
||||
|
||||
<div class="info"> |
||||
<time |
||||
datetime={fromUnixTime(story.date).toISOString()} |
||||
title={fromUnixTime(story.date)}>{dateString}</time> |
||||
{#if story.author && story.author_link} |
||||
by |
||||
<a href={story.author_link}>{story.author}</a> |
||||
{:else if story.author}by {story.author}{/if} |
||||
on |
||||
<a href={story.url}>{story.source}</a> |
||||
{#if story.score}• {story.score} points{/if} |
||||
{#if story.num_comments} |
||||
• |
||||
<a rel="prefetch" href="/{story.id}#comments">{story.num_comments} |
||||
comments</a> |
||||
{/if} |
||||
</div> |
||||
<Time date={story.date} /> |
||||
{#if story.author && story.author_link} |
||||
by |
||||
<a href={story.author_link}>{story.author}</a> |
||||
{:else if story.author}by {story.author}{/if} |
||||
on |
||||
<a href={story.link || story.url}>{story.source}</a> |
||||
{#if story.score}• {story.score} points{/if} |
||||
{#if story.num_comments} |
||||
• |
||||
<a rel="prefetch" href="/{story.id}#comments">{story.num_comments} |
||||
comments</a> |
||||
{/if} |
||||
|
@ -0,0 +1,55 @@ |
||||
<script> |
||||
import { getLogoUrl } from "../utils/logos.js"; |
||||
import StoryInfo from "../components/StoryInfo.svelte"; |
||||
export let stories; |
||||
|
||||
const host = (url) => new URL(url).hostname.replace(/^www\./, ""); |
||||
</script> |
||||
|
||||
<style> |
||||
.story-item { |
||||
margin: 0.5rem 0 0; |
||||
padding-left: 1.2em; |
||||
} |
||||
.story-icon, |
||||
.story-title { |
||||
font-size: 1.2rem; |
||||
} |
||||
.story-icon { |
||||
margin-left: -1.2rem; |
||||
} |
||||
.story-source::before { |
||||
content: "("; |
||||
} |
||||
.story-source::after { |
||||
content: ")"; |
||||
} |
||||
|
||||
.story-item :global(a) { |
||||
text-decoration: none; |
||||
} |
||||
.story-item :global(a:hover) { |
||||
text-decoration: underline; |
||||
} |
||||
</style> |
||||
|
||||
{#each stories as story} |
||||
<article class="story-item"> |
||||
<header class="story-header"> |
||||
<img |
||||
src={getLogoUrl(story)} |
||||
alt="logo" |
||||
class="story-icon" |
||||
style="height: 1rem; width: 1rem;" /> |
||||
<a class="story-title" rel="prefetch" href="/{story.id}">{story.title}</a> |
||||
<a |
||||
class="story-source" |
||||
href={story.url || story.link}>{host(story.url || story.link)}</a> |
||||
</header> |
||||
<section class="story-info"> |
||||
<StoryInfo {story} /> |
||||
</section> |
||||
</article> |
||||
{/each} |
||||
|
||||
<slot /> |
@ -0,0 +1,11 @@ |
||||
<script> |
||||
import fromUnixTime from "date-fns/fromUnixTime"; |
||||
import formatDistanceToNow from "date-fns/formatDistanceToNow"; |
||||
export let date; |
||||
let d = fromUnixTime(date); |
||||
let datetime = d.toISOString(); |
||||
let title = d.toLocaleString(); |
||||
let dateString = formatDistanceToNow(d, { addSuffix: true }); |
||||
</script> |
||||
|
||||
<time {datetime} {title}>{dateString}</time> |
@ -1,36 +1,38 @@ |
||||
body { |
||||
margin: 0; |
||||
font-family: Roboto, -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; |
||||
font-size: 14px; |
||||
line-height: 1.5; |
||||
color: #333; |
||||
margin: 0; |
||||
font-family: Roboto, -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, |
||||
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; |
||||
font-size: 16px; |
||||
line-height: 1.5; |
||||
color: #333; |
||||
|
||||
margin-bottom: 50vh; |
||||
} |
||||
|
||||
h1, h2, h3, h4, h5, h6 { |
||||
margin: 0 0 0.5em 0; |
||||
font-weight: 400; |
||||
line-height: 1.2; |
||||
h1, |
||||
h2, |
||||
h3, |
||||
h4, |
||||
h5, |
||||
h6 { |
||||
margin: 0 0 0.5em 0; |
||||
font-weight: 400; |
||||
line-height: 1.2; |
||||
} |
||||
|
||||
h1 { |
||||
font-size: 2em; |
||||
font-size: 2em; |
||||
} |
||||
|
||||
a { |
||||
color: inherit; |
||||
color: inherit; |
||||
} |
||||
|
||||
code { |
||||
font-family: menlo, inconsolata, monospace; |
||||
font-size: calc(1em - 2px); |
||||
color: #555; |
||||
background-color: #f0f0f0; |
||||
padding: 0.2em 0.4em; |
||||
border-radius: 2px; |
||||
font-family: menlo, inconsolata, monospace; |
||||
font-size: calc(1em - 2px); |
||||
color: #555; |
||||
background-color: #f0f0f0; |
||||
padding: 0.2em 0.4em; |
||||
border-radius: 2px; |
||||
} |
||||
|
||||
@media (min-width: 400px) { |
||||
body { |
||||
font-size: 16px; |
||||
} |
||||
} |
Loading…
Reference in new issue