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> |
<script> |
||||||
import fromUnixTime from "date-fns/fromUnixTime"; |
import Time from "../components/Time.svelte"; |
||||||
import formatDistanceToNow from "date-fns/formatDistanceToNow"; |
|
||||||
export let story; |
export let story; |
||||||
export let dateString = formatDistanceToNow(fromUnixTime(story.date), { |
|
||||||
addSuffix: true, |
|
||||||
}); |
|
||||||
</script> |
</script> |
||||||
|
|
||||||
<div class="info"> |
<Time date={story.date} /> |
||||||
<time |
{#if story.author && story.author_link} |
||||||
datetime={fromUnixTime(story.date).toISOString()} |
by |
||||||
title={fromUnixTime(story.date)}>{dateString}</time> |
<a href={story.author_link}>{story.author}</a> |
||||||
{#if story.author && story.author_link} |
{:else if story.author}by {story.author}{/if} |
||||||
by |
on |
||||||
<a href={story.author_link}>{story.author}</a> |
<a href={story.link || story.url}>{story.source}</a> |
||||||
{:else if story.author}by {story.author}{/if} |
{#if story.score}• {story.score} points{/if} |
||||||
on |
{#if story.num_comments} |
||||||
<a href={story.url}>{story.source}</a> |
• |
||||||
{#if story.score}• {story.score} points{/if} |
<a rel="prefetch" href="/{story.id}#comments">{story.num_comments} |
||||||
{#if story.num_comments} |
comments</a> |
||||||
• |
{/if} |
||||||
<a rel="prefetch" href="/{story.id}#comments">{story.num_comments} |
|
||||||
comments</a> |
|
||||||
{/if} |
|
||||||
</div> |
|
||||||
|
@ -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 { |
body { |
||||||
margin: 0; |
margin: 0; |
||||||
font-family: Roboto, -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; |
font-family: Roboto, -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, |
||||||
font-size: 14px; |
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; |
||||||
line-height: 1.5; |
font-size: 16px; |
||||||
color: #333; |
line-height: 1.5; |
||||||
|
color: #333; |
||||||
|
|
||||||
|
margin-bottom: 50vh; |
||||||
} |
} |
||||||
|
|
||||||
h1, h2, h3, h4, h5, h6 { |
h1, |
||||||
margin: 0 0 0.5em 0; |
h2, |
||||||
font-weight: 400; |
h3, |
||||||
line-height: 1.2; |
h4, |
||||||
|
h5, |
||||||
|
h6 { |
||||||
|
margin: 0 0 0.5em 0; |
||||||
|
font-weight: 400; |
||||||
|
line-height: 1.2; |
||||||
} |
} |
||||||
|
|
||||||
h1 { |
h1 { |
||||||
font-size: 2em; |
font-size: 2em; |
||||||
} |
} |
||||||
|
|
||||||
a { |
a { |
||||||
color: inherit; |
color: inherit; |
||||||
} |
} |
||||||
|
|
||||||
code { |
code { |
||||||
font-family: menlo, inconsolata, monospace; |
font-family: menlo, inconsolata, monospace; |
||||||
font-size: calc(1em - 2px); |
font-size: calc(1em - 2px); |
||||||
color: #555; |
color: #555; |
||||||
background-color: #f0f0f0; |
background-color: #f0f0f0; |
||||||
padding: 0.2em 0.4em; |
padding: 0.2em 0.4em; |
||||||
border-radius: 2px; |
border-radius: 2px; |
||||||
} |
} |
||||||
|
|
||||||
@media (min-width: 400px) { |
|
||||||
body { |
|
||||||
font-size: 16px; |
|
||||||
} |
|
||||||
} |
|
Loading…
Reference in new issue